Mercurial > projects > dcrypt
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 } |