comparison dcrypt/crypto/ciphers/RC4.d @ 0:0e08791a1418

Initial import.
author Thomas Dixon <reikon@reikon.us>
date Sun, 10 Aug 2008 14:20:17 -0400
parents
children 483e4467b5f6
comparison
equal deleted inserted replaced
-1:000000000000 0:0e08791a1418
1 /**
2 * This file is part of the dcrypt project.
3 *
4 * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved.
5 * License: MIT
6 * Authors: Thomas Dixon
7 */
8
9 module dcrypt.crypto.ciphers.RC4;
10
11 import dcrypt.crypto.StreamCipher;
12
13 version (UnitTest) {
14 import dcrypt.misc.Util;
15 }
16
17 /** Implementation of RC4 designed by Ron Rivest of RSA Security. */
18 class RC4 : StreamCipher {
19 private ubyte[] state,
20 workingKey;
21 private ubyte x, y;
22 private bool initialized;
23
24 void init(bool encrypt, CipherParameters params) {
25 SymmetricKey keyParams = cast(SymmetricKey)params;
26 if (!keyParams)
27 throw new InvalidParameterError(
28 name()~": Invalid parameter passed to init");
29 if (keyParams.key.length < 0 || keyParams.key.length > 256)
30 throw new InvalidKeyError(
31 name()~": Invalid key length (requires 1-256 bytes)");
32 workingKey = keyParams.key;
33 state = new ubyte[256];
34 setup(workingKey);
35 initialized = true;
36 }
37
38 char[] name() {
39 return "RC4";
40 }
41
42 ubyte returnByte(ubyte input) {
43 y += state[++x];
44 ubyte t = state[x];
45 state[x] = state[y];
46 state[y] = t;
47 return (input^state[cast(ubyte)(state[x]+state[y])]);
48 }
49
50 void processBytes(void[] input_, uint inOff, uint len, void[] output_, uint outOff) {
51 if (!initialized)
52 throw new NotInitializedError(name()~": Cipher not initialized");
53
54 ubyte[] input = cast(ubyte[]) input_;
55 ubyte[] output = cast(ubyte[]) output_;
56
57 if ((inOff + len) > input.length)
58 throw new ShortBufferError(name()~": Input buffer too short");
59
60 if ((outOff + len) > output.length)
61 throw new ShortBufferError(name()~": Output buffer too short");
62
63 for (int i = 0; i < len; i++) {
64 y += state[++x];
65 ubyte t = state[x];
66 state[x] = state[y];
67 state[y] = t;
68 output[outOff++] = input[inOff++] ^ state[cast(ubyte)(state[x]+state[y])];
69 }
70 }
71
72 void reset() {
73 setup(workingKey);
74 }
75
76 // Do RC4's key setup in a separate method to ease resetting
77 private void setup(ubyte[] key) {
78 for (int i = 0; i < 256; i++)
79 state[i] = cast(ubyte)i;
80
81 x = 0;
82 for (int i = 0; i < 256; i++) {
83 x += key[i % key.length] + state[i];
84 ubyte t = state[i];
85 state[i] = state[x];
86 state[x] = t;
87 }
88 x = y = 0;
89 }
90
91 /** Some RC4 test vectors. */
92 version (UnitTest) {
93 unittest {
94 static const char[][] test_keys = [
95 "0123456789abcdef",
96 "0123456789abcdef",
97 "0000000000000000",
98 "ef012345",
99 "0123456789abcdef"
100 ];
101
102 static const char[][] test_plaintexts = [
103 "0123456789abcdef",
104 "0000000000000000",
105 "0000000000000000",
106 "00000000000000000000",
107 "01010101010101010101010101010101"~
108 "01010101010101010101010101010101"~
109 "01010101010101010101010101010101"~
110 "01010101010101010101010101010101"~
111 "01010101010101010101010101010101"~
112 "01010101010101010101010101010101"~
113 "01010101010101010101010101010101"~
114 "01010101010101010101010101010101"~
115 "01010101010101010101010101010101"~
116 "01010101010101010101010101010101"~
117 "01010101010101010101010101010101"~
118 "01010101010101010101010101010101"~
119 "01010101010101010101010101010101"~
120 "01010101010101010101010101010101"~
121 "01010101010101010101010101010101"~
122 "01010101010101010101010101010101"~
123 "01010101010101010101010101010101"~
124 "01010101010101010101010101010101"~
125 "01010101010101010101010101010101"~
126 "01010101010101010101010101010101"~
127 "01010101010101010101010101010101"~
128 "01010101010101010101010101010101"~
129 "01010101010101010101010101010101"~
130 "01010101010101010101010101010101"~
131 "01010101010101010101010101010101"~
132 "01010101010101010101010101010101"~
133 "01010101010101010101010101010101"~
134 "01010101010101010101010101010101"~
135 "01010101010101010101010101010101"~
136 "01010101010101010101010101010101"~
137 "01010101010101010101010101010101"~
138 "01010101010101010101010101010101"
139 ];
140
141 static const char[][] test_ciphertexts = [
142 "75b7878099e0c596",
143 "7494c2e7104b0879",
144 "de188941a3375d3a",
145 "d6a141a7ec3c38dfbd61",
146 "7595c3e6114a09780c4ad452338e1ffd"~
147 "9a1be9498f813d76533449b6778dcad8"~
148 "c78a8d2ba9ac66085d0e53d59c26c2d1"~
149 "c490c1ebbe0ce66d1b6b1b13b6b919b8"~
150 "47c25a91447a95e75e4ef16779cde8bf"~
151 "0a95850e32af9689444fd377108f98fd"~
152 "cbd4e726567500990bcc7e0ca3c4aaa3"~
153 "04a387d20f3b8fbbcd42a1bd311d7a43"~
154 "03dda5ab078896ae80c18b0af66dff31"~
155 "9616eb784e495ad2ce90d7f772a81747"~
156 "b65f62093b1e0db9e5ba532fafec4750"~
157 "8323e671327df9444432cb7367cec82f"~
158 "5d44c0d00b67d650a075cd4b70dedd77"~
159 "eb9b10231b6b5b741347396d62897421"~
160 "d43df9b42e446e358e9c11a9b2184ecb"~
161 "ef0cd8e7a877ef968f1390ec9b3d35a5"~
162 "585cb009290e2fcde7b5ec66d9084be4"~
163 "4055a619d9dd7fc3166f9487f7cb2729"~
164 "12426445998514c15d53a18c864ce3a2"~
165 "b7555793988126520eacf2e3066e230c"~
166 "91bee4dd5304f5fd0405b35bd99c7313"~
167 "5d3d9bc335ee049ef69b3867bf2d7bd1"~
168 "eaa595d8bfc0066ff8d31509eb0c6caa"~
169 "006c807a623ef84c3d33c195d23ee320"~
170 "c40de0558157c822d4b8c569d849aed5"~
171 "9d4e0fd7f379586b4b7ff684ed6a189f"~
172 "7486d49b9c4bad9ba24b96abf924372c"~
173 "8a8fffb10d55354900a77a3db5f205e1"~
174 "b99fcd8660863a159ad4abe40fa48934"~
175 "163ddde542a6585540fd683cbfd8c00f"~
176 "12129a284deacc4cdefe58be7137541c"~
177 "047126c8d49e2755ab181ab7e940b0c0"
178 ];
179
180 RC4 r = new RC4();
181 foreach (uint i, char[] test_key; test_keys) {
182 ubyte[] buffer = new ubyte[test_plaintexts[i].length>>1];
183 char[] result;
184
185 r.init(true, new SymmetricKey(Util.hexToUbytes(test_key)));
186
187 // Encryption
188 r.processBytes(Util.hexToUbytes(test_plaintexts[i]), 0, buffer.length, buffer, 0);
189 result = Util.ubytesToHex(buffer);
190 assert(result == test_ciphertexts[i],
191 r.name()~": ("~result~") != ("~test_ciphertexts[i]~")");
192
193 r.reset();
194
195 // Decryption
196 r.processBytes(Util.hexToUbytes(test_ciphertexts[i]), 0, buffer.length, buffer, 0);
197 result = Util.ubytesToHex(buffer);
198 assert(result == test_plaintexts[i],
199 r.name()~": ("~result~") != ("~test_ciphertexts[i]~")");
200 }
201 }
202 }
203 }