1 module dcrypt.crypto.engines.rc4; 2 3 public import dcrypt.crypto.streamcipher; 4 5 deprecated("RC4 is considered insecure. Avoid using it"): 6 7 // test RC4 8 unittest 9 { 10 11 static string[] test_keys = [ 12 x"0123456789abcdef", 13 x"0123456789abcdef", 14 x"0000000000000000", 15 x"ef012345", 16 x"0123456789abcdef" 17 ]; 18 19 static string[] test_plaintexts = [ 20 x"0123456789abcdef", 21 x"0000000000000000", 22 x"0000000000000000", 23 x"00000000000000000000", 24 x"01010101010101010101010101010101 25 01010101010101010101010101010101 26 01010101010101010101010101010101 27 01010101010101010101010101010101 28 01010101010101010101010101010101 29 01010101010101010101010101010101 30 01010101010101010101010101010101 31 01010101010101010101010101010101 32 01010101010101010101010101010101 33 01010101010101010101010101010101 34 01010101010101010101010101010101 35 01010101010101010101010101010101 36 01010101010101010101010101010101 37 01010101010101010101010101010101 38 01010101010101010101010101010101 39 01010101010101010101010101010101 40 01010101010101010101010101010101 41 01010101010101010101010101010101 42 01010101010101010101010101010101 43 01010101010101010101010101010101 44 01010101010101010101010101010101 45 01010101010101010101010101010101 46 01010101010101010101010101010101 47 01010101010101010101010101010101 48 01010101010101010101010101010101 49 01010101010101010101010101010101 50 01010101010101010101010101010101 51 01010101010101010101010101010101 52 01010101010101010101010101010101 53 01010101010101010101010101010101 54 01010101010101010101010101010101 55 01010101010101010101010101010101" 56 ]; 57 58 static string[] test_ciphertexts = [ 59 x"75b7878099e0c596", 60 x"7494c2e7104b0879", 61 x"de188941a3375d3a", 62 x"d6a141a7ec3c38dfbd61", 63 x"7595c3e6114a09780c4ad452338e1ffd 64 9a1be9498f813d76533449b6778dcad8 65 c78a8d2ba9ac66085d0e53d59c26c2d1 66 c490c1ebbe0ce66d1b6b1b13b6b919b8 67 47c25a91447a95e75e4ef16779cde8bf 68 0a95850e32af9689444fd377108f98fd 69 cbd4e726567500990bcc7e0ca3c4aaa3 70 04a387d20f3b8fbbcd42a1bd311d7a43 71 03dda5ab078896ae80c18b0af66dff31 72 9616eb784e495ad2ce90d7f772a81747 73 b65f62093b1e0db9e5ba532fafec4750 74 8323e671327df9444432cb7367cec82f 75 5d44c0d00b67d650a075cd4b70dedd77 76 eb9b10231b6b5b741347396d62897421 77 d43df9b42e446e358e9c11a9b2184ecb 78 ef0cd8e7a877ef968f1390ec9b3d35a5 79 585cb009290e2fcde7b5ec66d9084be4 80 4055a619d9dd7fc3166f9487f7cb2729 81 12426445998514c15d53a18c864ce3a2 82 b7555793988126520eacf2e3066e230c 83 91bee4dd5304f5fd0405b35bd99c7313 84 5d3d9bc335ee049ef69b3867bf2d7bd1 85 eaa595d8bfc0066ff8d31509eb0c6caa 86 006c807a623ef84c3d33c195d23ee320 87 c40de0558157c822d4b8c569d849aed5 88 9d4e0fd7f379586b4b7ff684ed6a189f 89 7486d49b9c4bad9ba24b96abf924372c 90 8a8fffb10d55354900a77a3db5f205e1 91 b99fcd8660863a159ad4abe40fa48934 92 163ddde542a6585540fd683cbfd8c00f 93 12129a284deacc4cdefe58be7137541c 94 047126c8d49e2755ab181ab7e940b0c0" 95 ]; 96 97 streamCipherTest(new RC4Engine, test_keys, test_plaintexts, test_ciphertexts); 98 } 99 100 alias StreamCipherWrapper!RC4 RC4Engine; 101 102 static assert(isStreamCipher!RC4, "RC4 is not a stream cipher!"); 103 104 @safe 105 public struct RC4 { 106 107 public enum name = "RC4"; 108 109 private enum STATE_LENGTH = 256; 110 111 private { 112 ubyte[STATE_LENGTH] state; 113 ubyte[] workingKey; 114 ubyte x, y; 115 bool initialized = false, forEncryption; 116 } 117 118 @safe @nogc nothrow 119 ~this() { 120 import dcrypt.util.util: wipe; 121 122 wipe(state); 123 wipe(workingKey); 124 wipe(x, y); 125 } 126 127 /** 128 * Initialize the cipher. 129 * 130 * Params: 131 * forEncryption = if true the cipher is initialized for encryption, if false for decryption. 132 * keyParams = the key and other data required by the cipher. 133 * iv = not used 134 */ 135 public void start(bool forEncryption, in ubyte[] userKey, in ubyte[] iv = null) { 136 this.forEncryption = forEncryption; 137 138 workingKey = userKey.dup; 139 reset(); 140 } 141 142 /** 143 * Encrypt one single byte 144 */ 145 public ubyte returnByte(ubyte b) nothrow @nogc { 146 return b ^ nextByte(); 147 } 148 149 public void processBytes(in ubyte[] input, ubyte[] output) nothrow @nogc { 150 foreach(i; 0 .. input.length){ 151 output[i] = nextByte() ^ input[i]; 152 } 153 } 154 155 public void reset() nothrow @nogc { 156 KSA(workingKey); 157 } 158 159 private ubyte nextByte() nothrow @nogc { 160 x = cast(ubyte)(x+1); 161 y = cast(ubyte)(y + state[x]); 162 163 // swap i, j 164 ubyte temp = state[x]; 165 state[x] = state[y]; 166 state[y] = temp; 167 168 return state[(state[x]+state[y])%STATE_LENGTH]; 169 } 170 171 private void KSA(in ubyte[] workingKey) nothrow @nogc { 172 173 // state = [0,2,3,...,state.length-1] 174 foreach(i, ref s; state) { 175 s = cast(ubyte) i; 176 } 177 uint j = 0; 178 179 foreach(uint i; 0 .. STATE_LENGTH){ 180 j = (j + state[i] + workingKey[i%workingKey.length]) % STATE_LENGTH; 181 182 // swap i, j 183 ubyte temp = state[i]; 184 state[i] = state[j]; 185 state[j] = temp; 186 } 187 x = y = 0; 188 } 189 190 191 }