Line | Count | Source (jump to first uncovered line) |
1 | | // |
2 | | // Md2.c |
3 | | // |
4 | | // Copyright (c) Microsoft Corporation. Licensed under the MIT license. |
5 | | // |
6 | | // |
7 | | // This module contains the routines to implement MD2 from RFC 1319 |
8 | | // |
9 | | // This is a new implementation, NOT based on the existing one in RSA32.lib, |
10 | | // which is the one from RSA data security. |
11 | | // |
12 | | // The implementation had to be refreshed anyway to conform to our coding |
13 | | // guidelines for cryptographic functions. |
14 | | // Re-implementing the function along the lines of our SHA-family implementations |
15 | | // was easy, and it removes a file with RSA copyright from our system. |
16 | | // |
17 | | // The only data copied for this implementation is the S table from the |
18 | | // RFC. |
19 | | // |
20 | | |
21 | | #include "precomp.h" |
22 | | |
23 | | // |
24 | | // See the symcrypt.h file for documentation on what the various functions do. |
25 | | // |
26 | | |
27 | | const SYMCRYPT_HASH SymCryptMd2Algorithm_default = { |
28 | | &SymCryptMd2Init, |
29 | | &SymCryptMd2Append, |
30 | | &SymCryptMd2Result, |
31 | | &SymCryptMd2AppendBlocks, |
32 | | &SymCryptMd2StateCopy, |
33 | | sizeof( SYMCRYPT_MD2_STATE ), |
34 | | SYMCRYPT_MD2_RESULT_SIZE, |
35 | | SYMCRYPT_MD2_INPUT_BLOCK_SIZE, |
36 | | SYMCRYPT_FIELD_OFFSET( SYMCRYPT_MD2_STATE, chain ), |
37 | | SYMCRYPT_FIELD_SIZE( SYMCRYPT_MD2_STATE, chain ), |
38 | | }; |
39 | | |
40 | | const PCSYMCRYPT_HASH SymCryptMd2Algorithm = &SymCryptMd2Algorithm_default; |
41 | | |
42 | | // |
43 | | // These entries are called S[i] in RFC1319 |
44 | | // |
45 | | const BYTE SymCryptMd2STable[256] = { |
46 | | 41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6, |
47 | | 19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188, |
48 | | 76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24, |
49 | | 138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251, |
50 | | 245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63, |
51 | | 148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50, |
52 | | 39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165, |
53 | | 181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210, |
54 | | 150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157, |
55 | | 112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27, |
56 | | 96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15, |
57 | | 85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197, |
58 | | 234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65, |
59 | | 129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123, |
60 | | 8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233, |
61 | | 203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228, |
62 | | 166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237, |
63 | | 31, 26, 219, 153, 141, 51, 159, 17, 131, 20 |
64 | | }; |
65 | | |
66 | | |
67 | | // |
68 | | // SymCryptMd2 |
69 | | // |
70 | | #define ALG MD2 |
71 | | #define Alg Md2 |
72 | | #include "hash_pattern.c" |
73 | | #undef ALG |
74 | | #undef Alg |
75 | | |
76 | | |
77 | | // |
78 | | // SymCryptMd2Init |
79 | | // |
80 | | VOID |
81 | | SYMCRYPT_CALL |
82 | | SymCryptMd2Init( _Out_ PSYMCRYPT_MD2_STATE pState ) |
83 | 216 | { |
84 | | // |
85 | | // We use the secure wipe as the init routine is also used to re-initialize |
86 | | // (and wipe) the state after a hash computation. |
87 | | // In that case the compiler might conclude that this wipe can be optimized |
88 | | // away, and that would leak data. |
89 | | // |
90 | 216 | SymCryptWipeKnownSize( pState, sizeof( *pState ) ); |
91 | 216 | SYMCRYPT_SET_MAGIC( pState ); |
92 | 216 | } |
93 | | |
94 | | |
95 | | // |
96 | | // SymCryptMd2Append |
97 | | // |
98 | | VOID |
99 | | SYMCRYPT_CALL |
100 | | SymCryptMd2Append( _Inout_ PSYMCRYPT_MD2_STATE pState, |
101 | | _In_reads_( cbData ) PCBYTE pbData, |
102 | | SIZE_T cbData ) |
103 | 12.5k | { |
104 | 12.5k | SymCryptHashAppendInternal( SymCryptMd2Algorithm, (PSYMCRYPT_COMMON_HASH_STATE)pState, pbData, cbData ); |
105 | 12.5k | } |
106 | | |
107 | | |
108 | | // |
109 | | // SymCryptMd2Result |
110 | | // |
111 | | VOID |
112 | | SYMCRYPT_CALL |
113 | | SymCryptMd2Result( _Inout_ PSYMCRYPT_MD2_STATE state, |
114 | | _Out_writes_( SYMCRYPT_MD2_RESULT_SIZE ) PBYTE pbResult ) |
115 | 108 | { |
116 | | // |
117 | | // The buffer is never completely full, so it is easy to compute the actual padding. |
118 | | // |
119 | 108 | SIZE_T tmp; |
120 | 108 | SIZE_T paddingBytes = 16 - state->bytesInBuffer; |
121 | | |
122 | | |
123 | 108 | SYMCRYPT_CHECK_MAGIC( state ); |
124 | | |
125 | 108 | memset( &state->buffer[state->bytesInBuffer], (BYTE)paddingBytes, paddingBytes ); |
126 | | |
127 | 108 | SymCryptMd2AppendBlocks( &state->chain, state->buffer, SYMCRYPT_MD2_INPUT_BLOCK_SIZE, &tmp ); |
128 | | |
129 | | // |
130 | | // Append the checksum |
131 | | // |
132 | 108 | SymCryptMd2AppendBlocks( &state->chain, state->chain.C, SYMCRYPT_MD2_INPUT_BLOCK_SIZE, &tmp ); |
133 | | |
134 | 108 | memcpy( pbResult, &state->chain.X[0], SYMCRYPT_MD2_RESULT_SIZE ); |
135 | | |
136 | | // |
137 | | // Wipe & re-initialize |
138 | | // |
139 | | // (Our init code wipes the buffer too, so we don't have to.) |
140 | | // |
141 | 108 | SymCryptMd2Init( state ); |
142 | 108 | } |
143 | | |
144 | | |
145 | | VOID |
146 | | SYMCRYPT_CALL |
147 | | SymCryptMd2AppendBlocks( |
148 | | _Inout_ PSYMCRYPT_MD2_CHAINING_STATE pChain, |
149 | | _In_reads_( cbData ) PCBYTE pbData, |
150 | | SIZE_T cbData, |
151 | | _Out_ SIZE_T * pcbRemaining ) |
152 | 854 | { |
153 | | // |
154 | | // For variable names see RFC 1319. |
155 | | // |
156 | 854 | unsigned int t; |
157 | 854 | int j,k; |
158 | | |
159 | 142k | while( cbData >= SYMCRYPT_MD2_INPUT_BLOCK_SIZE ) |
160 | 141k | { |
161 | 141k | BYTE L; |
162 | | // |
163 | | // read the data once into our structure |
164 | | // |
165 | 141k | memcpy( &pChain->X[16], pbData, SYMCRYPT_MD2_INPUT_BLOCK_SIZE ); |
166 | | |
167 | | // |
168 | | // Update the checksum block. |
169 | | // The L value at the end of the previous block is in the last byte of the checksum |
170 | | // |
171 | 141k | L = pChain->C[15]; |
172 | | |
173 | 2.40M | for( j=0; j<16; j++ ) |
174 | 2.26M | { |
175 | 2.26M | pChain->C[j] = L = pChain->C[j] ^ SymCryptMd2STable[ L ^ pChain->X[16+j] ]; |
176 | 2.26M | } |
177 | | |
178 | | // |
179 | | // Now we compute the actual hash |
180 | | // |
181 | 141k | SymCryptXorBytes( &pChain->X[0], &pChain->X[16], &pChain->X[32], 16 ); |
182 | | |
183 | 141k | t = 0; |
184 | 2.68M | for( j=0; j<18; j++ ) |
185 | 2.54M | { |
186 | 124M | for( k=0; k<48; k++ ) |
187 | 122M | { |
188 | 122M | t = pChain->X[k] ^ SymCryptMd2STable[t]; |
189 | 122M | pChain->X[k] = (BYTE) t; |
190 | 122M | } |
191 | 2.54M | t = (t + j)& 0xff; |
192 | 2.54M | } |
193 | | |
194 | 141k | pbData += SYMCRYPT_MD2_INPUT_BLOCK_SIZE; |
195 | 141k | cbData -= SYMCRYPT_MD2_INPUT_BLOCK_SIZE; |
196 | 141k | } |
197 | | |
198 | 854 | *pcbRemaining = cbData; |
199 | 854 | } |
200 | | |
201 | | |
202 | | VOID |
203 | | SYMCRYPT_CALL |
204 | | SymCryptMd2StateExport( |
205 | | _In_ PCSYMCRYPT_MD2_STATE pState, |
206 | | _Out_writes_bytes_( SYMCRYPT_MD2_STATE_EXPORT_SIZE ) PBYTE pbBlob ) |
207 | 0 | { |
208 | 0 | SYMCRYPT_ALIGN SYMCRYPT_MD2_STATE_EXPORT_BLOB blob; // local copy to have proper alignment. |
209 | 0 | C_ASSERT( sizeof( blob ) == SYMCRYPT_MD2_STATE_EXPORT_SIZE ); |
210 | |
|
211 | 0 | SYMCRYPT_CHECK_MAGIC( pState ); |
212 | |
|
213 | 0 | SymCryptWipeKnownSize( &blob, sizeof( blob ) ); // wipe to avoid any data leakage |
214 | |
|
215 | 0 | blob.header.magic = SYMCRYPT_BLOB_MAGIC; |
216 | 0 | blob.header.size = SYMCRYPT_MD2_STATE_EXPORT_SIZE; |
217 | 0 | blob.header.type = SymCryptBlobTypeMd2State; |
218 | | |
219 | | // |
220 | | // Copy the relevant data. Buffer will be 0-padded. |
221 | | // |
222 | 0 | memcpy( &blob.C[0], &pState->chain.C[0], 16 ); |
223 | 0 | memcpy( &blob.X[0], &pState->chain.X[0], 16 ); |
224 | 0 | blob.bytesInBuffer = (UINT32) pState->bytesInBuffer; |
225 | 0 | memcpy( &blob.buffer[0], &pState->buffer[0], blob.bytesInBuffer ); |
226 | |
|
227 | 0 | SYMCRYPT_ASSERT( (PCBYTE) &blob + sizeof( blob ) - sizeof( SYMCRYPT_BLOB_TRAILER ) == (PCBYTE) &blob.trailer ); |
228 | 0 | SymCryptMarvin32( SymCryptMarvin32DefaultSeed, (PCBYTE) &blob, sizeof( blob ) - sizeof( SYMCRYPT_BLOB_TRAILER ), &blob.trailer.checksum[0] ); |
229 | |
|
230 | 0 | memcpy( pbBlob, &blob, sizeof( blob ) ); |
231 | | |
232 | | //cleanup: |
233 | 0 | SymCryptWipeKnownSize( &blob, sizeof( blob ) ); |
234 | 0 | return; |
235 | 0 | } |
236 | | |
237 | | SYMCRYPT_ERROR |
238 | | SYMCRYPT_CALL |
239 | | SymCryptMd2StateImport( |
240 | | _Out_ PSYMCRYPT_MD2_STATE pState, |
241 | | _In_reads_bytes_( SYMCRYPT_MD2_STATE_EXPORT_SIZE) PCBYTE pbBlob ) |
242 | 0 | { |
243 | 0 | SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; |
244 | 0 | SYMCRYPT_ALIGN SYMCRYPT_MD2_STATE_EXPORT_BLOB blob; // local copy to have proper alignment. |
245 | 0 | BYTE checksum[8]; |
246 | |
|
247 | 0 | C_ASSERT( sizeof( blob ) == SYMCRYPT_MD2_STATE_EXPORT_SIZE ); |
248 | 0 | memcpy( &blob, pbBlob, sizeof( blob ) ); |
249 | |
|
250 | 0 | if( blob.header.magic != SYMCRYPT_BLOB_MAGIC || |
251 | 0 | blob.header.size != SYMCRYPT_MD2_STATE_EXPORT_SIZE || |
252 | 0 | blob.header.type != SymCryptBlobTypeMd2State ) |
253 | 0 | { |
254 | 0 | scError = SYMCRYPT_INVALID_BLOB; |
255 | 0 | goto cleanup; |
256 | 0 | } |
257 | | |
258 | 0 | SymCryptMarvin32( SymCryptMarvin32DefaultSeed, (PCBYTE) &blob, sizeof( blob ) - sizeof( SYMCRYPT_BLOB_TRAILER ), checksum ); |
259 | 0 | if( memcmp( checksum, &blob.trailer.checksum[0], 8 ) != 0 ) |
260 | 0 | { |
261 | 0 | scError = SYMCRYPT_INVALID_BLOB; |
262 | 0 | goto cleanup; |
263 | 0 | } |
264 | | |
265 | 0 | memcpy( &pState->chain.C[0], &blob.C[0], 16 ); |
266 | 0 | memcpy( &pState->chain.X[0], &blob.X[0], 16 ); |
267 | 0 | memcpy( &pState->buffer[0], &blob.buffer[0], 16 ); |
268 | 0 | pState->bytesInBuffer = blob.bytesInBuffer; |
269 | |
|
270 | 0 | pState->dataLengthL = blob.bytesInBuffer; |
271 | 0 | pState->dataLengthH = 1; |
272 | |
|
273 | 0 | SYMCRYPT_SET_MAGIC( pState ); |
274 | |
|
275 | 0 | cleanup: |
276 | 0 | SymCryptWipeKnownSize( &blob, sizeof(blob) ); |
277 | 0 | return scError; |
278 | 0 | } |
279 | | |
280 | | |
281 | | |
282 | | |
283 | | |
284 | | |
285 | | // |
286 | | // Simple test vector for FIPS module testing |
287 | | // |
288 | | |
289 | | static const BYTE md2KATAnswer[ 16 ] = { |
290 | | 0xda, 0x85, 0x3b, 0x0d, 0x3f, 0x88, 0xd9, 0x9b, |
291 | | 0x30, 0x28, 0x3a, 0x69, 0xe6, 0xde, 0xd6, 0xbb, |
292 | | } ; |
293 | | |
294 | | VOID |
295 | | SYMCRYPT_CALL |
296 | | SymCryptMd2Selftest(void) |
297 | 0 | { |
298 | 0 | BYTE result[SYMCRYPT_MD2_RESULT_SIZE]; |
299 | |
|
300 | 0 | SymCryptMd2( SymCryptTestMsg3, sizeof( SymCryptTestMsg3 ), result ); |
301 | |
|
302 | 0 | SymCryptInjectError( result, sizeof( result ) ); |
303 | |
|
304 | 0 | if( memcmp( result, md2KATAnswer, sizeof( result ) ) != 0 ) { |
305 | 0 | SymCryptFatal( 'MD2t' ); |
306 | 0 | } |
307 | 0 | } |
308 | | |
309 | | |