Line | Count | Source (jump to first uncovered line) |
1 | | // |
2 | | // Rc4.c |
3 | | // |
4 | | // Copyright (c) Microsoft Corporation. Licensed under the MIT license. |
5 | | // |
6 | | // This is a new implementation, NOT based on the existing ones in RSA32.lib. |
7 | | // The algorithm specification is taken from "ARCFOUR Algorithm" internet |
8 | | // draft dated July 1999, and from memory. |
9 | | // |
10 | | |
11 | | #include "precomp.h" |
12 | | |
13 | | SYMCRYPT_ERROR |
14 | | SYMCRYPT_CALL |
15 | | SymCryptRc4Init( |
16 | | _Out_ PSYMCRYPT_RC4_STATE pState, |
17 | | _In_reads_( cbKey ) PCBYTE pbKey, |
18 | | _In_ SIZE_T cbKey ) |
19 | 0 | { |
20 | 0 | SIZE_T i; |
21 | 0 | SIZE_T j; |
22 | 0 | BYTE keyBuf[256]; |
23 | 0 | SIZE_T keyIdx; |
24 | |
|
25 | 0 | SYMCRYPT_RC4_S_TYPE T; |
26 | |
|
27 | 0 | if( cbKey > 256 || cbKey == 0 ) |
28 | 0 | { |
29 | 0 | return SYMCRYPT_WRONG_KEY_SIZE; |
30 | 0 | } |
31 | | |
32 | | // |
33 | | // Make a copy of the key to obey the read-once rule. |
34 | | // This is a case where it looks safe to break the read-once |
35 | | // rule, but it isn't. RC4 with very long keys (e.g. 256 bytes) |
36 | | // is actually very vulnerable against related-key attacks. |
37 | | // One obvious precaution is to limit the length of the RC4 key, |
38 | | // which one of the layers above us might do. |
39 | | // Allowing the key bytes to change as we read them negates |
40 | | // this countermeasure. |
41 | | // |
42 | 0 | memcpy( keyBuf, pbKey, cbKey ); |
43 | |
|
44 | 0 | for( i=0; i<256; i++ ) |
45 | 0 | { |
46 | 0 | pState->S[i] = (SYMCRYPT_RC4_S_TYPE) i; |
47 | 0 | } |
48 | |
|
49 | 0 | j = 0; |
50 | 0 | keyIdx = 0; |
51 | 0 | for( i=0; i<256; i++ ) |
52 | 0 | { |
53 | |
|
54 | 0 | T = pState->S[i]; |
55 | 0 | j = (j + T + keyBuf[keyIdx]) & 0xff; |
56 | 0 | pState->S[i] = pState->S[j]; |
57 | 0 | pState->S[j] = T; |
58 | 0 | keyIdx++; |
59 | 0 | if( keyIdx == cbKey ) |
60 | 0 | { |
61 | 0 | keyIdx = 0; |
62 | 0 | } |
63 | 0 | } |
64 | | |
65 | | // |
66 | | // We store the i value already incremented for the next byte. |
67 | | // This seems to allow better instruction sequencing interleaving in the actual en/decrypt loop |
68 | | // |
69 | 0 | pState->i = 1; |
70 | 0 | pState->j = 0; |
71 | |
|
72 | 0 | SYMCRYPT_SET_MAGIC( pState ); |
73 | |
|
74 | 0 | SymCryptWipe( keyBuf, cbKey ); |
75 | |
|
76 | 0 | return SYMCRYPT_NO_ERROR; |
77 | 0 | } |
78 | | |
79 | | |
80 | | VOID |
81 | | SYMCRYPT_CALL |
82 | | SymCryptRc4Crypt( |
83 | | _Inout_ PSYMCRYPT_RC4_STATE pState, |
84 | | _In_reads_( cbData ) PCBYTE pbSrc, |
85 | | _Out_writes_( cbData ) PBYTE pbDst, |
86 | | _In_ SIZE_T cbData ) |
87 | 0 | { |
88 | 0 | SIZE_T i; |
89 | 0 | SIZE_T j; |
90 | 0 | SYMCRYPT_RC4_S_TYPE Ti; |
91 | 0 | SYMCRYPT_RC4_S_TYPE Tj; |
92 | 0 | PCBYTE pbSrcEnd = pbSrc + cbData; |
93 | |
|
94 | 0 | SYMCRYPT_CHECK_MAGIC( pState ); |
95 | |
|
96 | 0 | i = pState->i; |
97 | 0 | j = pState->j; |
98 | | |
99 | | // |
100 | | // I tried to unroll this loop 4x and use a single 32-bit operation to XOR the key |
101 | | // stream with the data. This actually makes the code slower by 1 c/B on a Core 2. |
102 | | // I suspect that that is because the instruction decoders are the bottleneck, and |
103 | | // a small loop can be run out of the uop queue which bypasses the instruction decoders. |
104 | | // A larger loop has to be decoded every time, and that slows things down. |
105 | | // The theoretical gain of unrolling the loop is less than 1 c/B, |
106 | | // and as Core 2 and derived CPUs are the most commonly used CPUs by our customers, |
107 | | // it is not worthwhile to persue this further. |
108 | | // |
109 | | // - Niels Ferguson (niels) 2010-10-11 |
110 | | // |
111 | |
|
112 | 0 | while( pbSrc < pbSrcEnd ) |
113 | 0 | { |
114 | | // |
115 | | // Our i value is already incremented |
116 | | // |
117 | 0 | Ti = pState->S[i]; |
118 | 0 | j = (j + Ti ) & 0xff; |
119 | 0 | Tj = pState->S[j]; |
120 | 0 | pState->S[i] = Tj; |
121 | 0 | pState->S[j] = Ti; |
122 | 0 | *pbDst = (BYTE) (*pbSrc ^ pState->S[(Ti + Tj) & 0xff]); |
123 | |
|
124 | 0 | i = (i + 1) & 0xff; |
125 | |
|
126 | 0 | pbSrc++; |
127 | 0 | pbDst++; |
128 | 0 | } |
129 | |
|
130 | 0 | pState->i = (BYTE) i; |
131 | 0 | pState->j = (BYTE) j; |
132 | 0 | } |
133 | | |
134 | | |
135 | | static const BYTE rc4KatAnswer[ 3 ] = { 0x71, 0x46, 0x92 }; |
136 | | |
137 | | |
138 | | VOID |
139 | | SYMCRYPT_CALL |
140 | | SymCryptRc4Selftest(void) |
141 | 0 | { |
142 | 0 | BYTE buf[3]; |
143 | 0 | SYMCRYPT_RC4_STATE state; |
144 | |
|
145 | 0 | SymCryptRc4Init( &state, SymCryptTestKey32, sizeof( SymCryptTestKey32 ) ); |
146 | |
|
147 | 0 | SymCryptRc4Crypt( &state, SymCryptTestMsg3, buf, sizeof( buf ) ); |
148 | |
|
149 | 0 | SymCryptInjectError( buf, sizeof( buf ) ); |
150 | |
|
151 | 0 | if( memcmp( buf, rc4KatAnswer, sizeof( buf )) != 0 ) |
152 | 0 | { |
153 | 0 | SymCryptFatal( 'rc4 ' ); |
154 | 0 | } |
155 | |
|
156 | 0 | } |
157 | | |
158 | | |
159 | | |