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 }