1 /** 2 * Copyright: Copyright (C) Thomas Dixon 2009. All rights reserved. 3 * License: BSD style: $(LICENSE) 4 * Authors: Thomas Dixon 5 */ 6 7 module tango.util.cipher.RC4; 8 9 private import tango.util.cipher.Cipher; 10 11 /** Implementation of RC4 designed by Ron Rivest of RSA Security. */ 12 class RC4 : StreamCipher 13 { 14 private 15 { 16 ubyte[] state; 17 const(ubyte)[] workingKey; 18 ubyte x, y; 19 } 20 21 this() 22 { 23 state = new ubyte[256]; 24 } 25 26 this(bool encrypt, ubyte[] key) { 27 this(); 28 init(encrypt, key); 29 } 30 31 final void init(bool encrypt, ubyte[] key) 32 { 33 if (key.length < 0 || key.length > 256) 34 invalid(name()~": Invalid key length (requires 1-256 bytes)"); 35 36 workingKey = key; 37 setup(workingKey); 38 39 _encrypt = _initialized = true; 40 } 41 42 @property final override const(char)[] name() 43 { 44 return "RC4"; 45 } 46 47 override ubyte returnByte(ubyte input) 48 { 49 if (!_initialized) 50 invalid(name()~": Cipher not initialized"); 51 52 y += state[++x]; 53 ubyte t = state[x]; 54 state[x] = state[y]; 55 state[y] = t; 56 57 return (input^state[cast(ubyte)(state[x]+state[y])]); 58 } 59 60 final override uint update(const(void[]) input_, void[] output_) 61 { 62 if (!_initialized) 63 invalid(name()~": Cipher not initialized"); 64 65 const(ubyte[]) input = cast(const(ubyte[])) input_; 66 ubyte[] output = cast(ubyte[]) output_; 67 68 if (input.length > output.length) 69 invalid(name()~": Output buffer too short"); 70 71 for (int i = 0; i < input.length; i++) 72 { 73 y += state[++x]; 74 ubyte t = state[x]; 75 state[x] = state[y]; 76 state[y] = t; 77 output[i] = input[i] ^ state[cast(ubyte)(state[x]+state[y])]; 78 } 79 80 return cast(uint)input.length; 81 } 82 83 final override void reset() 84 { 85 setup(workingKey); 86 } 87 88 // Do RC4's key setup in a separate method to ease resetting 89 private void setup(const(ubyte)[] key) 90 { 91 for (int i = 0; i < 256; i++) 92 state[i] = cast(ubyte)i; 93 94 x = 0; 95 for (int i = 0; i < 256; i++) 96 { 97 x += key[i % key.length] + state[i]; 98 ubyte t = state[i]; 99 state[i] = state[x]; 100 state[x] = t; 101 } 102 103 x = y = 0; 104 } 105 106 /** Some RC4 test vectors. */ 107 debug (UnitTest) 108 { 109 unittest 110 { 111 __gshared immutable immutable(char)[][] test_keys = [ 112 "0123456789abcdef", 113 "0123456789abcdef", 114 "0000000000000000", 115 "ef012345", 116 "0123456789abcdef" 117 ]; 118 119 __gshared immutable immutable(char)[][] test_plaintexts = [ 120 "0123456789abcdef", 121 "0000000000000000", 122 "0000000000000000", 123 "00000000000000000000", 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 "01010101010101010101010101010101"~ 140 "01010101010101010101010101010101"~ 141 "01010101010101010101010101010101"~ 142 "01010101010101010101010101010101"~ 143 "01010101010101010101010101010101"~ 144 "01010101010101010101010101010101"~ 145 "01010101010101010101010101010101"~ 146 "01010101010101010101010101010101"~ 147 "01010101010101010101010101010101"~ 148 "01010101010101010101010101010101"~ 149 "01010101010101010101010101010101"~ 150 "01010101010101010101010101010101"~ 151 "01010101010101010101010101010101"~ 152 "01010101010101010101010101010101"~ 153 "01010101010101010101010101010101"~ 154 "01010101010101010101010101010101"~ 155 "01010101010101010101010101010101" 156 ]; 157 158 __gshared immutable immutable(char)[][] test_ciphertexts = [ 159 "75b7878099e0c596", 160 "7494c2e7104b0879", 161 "de188941a3375d3a", 162 "d6a141a7ec3c38dfbd61", 163 "7595c3e6114a09780c4ad452338e1ffd"~ 164 "9a1be9498f813d76533449b6778dcad8"~ 165 "c78a8d2ba9ac66085d0e53d59c26c2d1"~ 166 "c490c1ebbe0ce66d1b6b1b13b6b919b8"~ 167 "47c25a91447a95e75e4ef16779cde8bf"~ 168 "0a95850e32af9689444fd377108f98fd"~ 169 "cbd4e726567500990bcc7e0ca3c4aaa3"~ 170 "04a387d20f3b8fbbcd42a1bd311d7a43"~ 171 "03dda5ab078896ae80c18b0af66dff31"~ 172 "9616eb784e495ad2ce90d7f772a81747"~ 173 "b65f62093b1e0db9e5ba532fafec4750"~ 174 "8323e671327df9444432cb7367cec82f"~ 175 "5d44c0d00b67d650a075cd4b70dedd77"~ 176 "eb9b10231b6b5b741347396d62897421"~ 177 "d43df9b42e446e358e9c11a9b2184ecb"~ 178 "ef0cd8e7a877ef968f1390ec9b3d35a5"~ 179 "585cb009290e2fcde7b5ec66d9084be4"~ 180 "4055a619d9dd7fc3166f9487f7cb2729"~ 181 "12426445998514c15d53a18c864ce3a2"~ 182 "b7555793988126520eacf2e3066e230c"~ 183 "91bee4dd5304f5fd0405b35bd99c7313"~ 184 "5d3d9bc335ee049ef69b3867bf2d7bd1"~ 185 "eaa595d8bfc0066ff8d31509eb0c6caa"~ 186 "006c807a623ef84c3d33c195d23ee320"~ 187 "c40de0558157c822d4b8c569d849aed5"~ 188 "9d4e0fd7f379586b4b7ff684ed6a189f"~ 189 "7486d49b9c4bad9ba24b96abf924372c"~ 190 "8a8fffb10d55354900a77a3db5f205e1"~ 191 "b99fcd8660863a159ad4abe40fa48934"~ 192 "163ddde542a6585540fd683cbfd8c00f"~ 193 "12129a284deacc4cdefe58be7137541c"~ 194 "047126c8d49e2755ab181ab7e940b0c0" 195 ]; 196 197 RC4 r = new RC4(); 198 foreach (uint i, immutable(char)[] test_key; test_keys) 199 { 200 ubyte[] buffer = new ubyte[test_plaintexts[i].length>>1]; 201 char[] result; 202 203 r.init(true, ByteConverter.hexDecode(test_key)); 204 205 // Encryption 206 r.update(ByteConverter.hexDecode(test_plaintexts[i]), buffer); 207 result = ByteConverter.hexEncode(buffer); 208 assert(result == test_ciphertexts[i], 209 r.name~": ("~result~") != ("~test_ciphertexts[i]~")"); 210 211 r.reset(); 212 213 // Decryption 214 r.update(ByteConverter.hexDecode(test_ciphertexts[i]), buffer); 215 result = ByteConverter.hexEncode(buffer); 216 assert(result == test_plaintexts[i], 217 r.name~": ("~result~") != ("~test_plaintexts[i]~")"); 218 } 219 } 220 } 221 }