/src/SymCrypt/lib/marvin32.c
Line | Count | Source (jump to first uncovered line) |
1 | | // |
2 | | // Marvin32.c |
3 | | // |
4 | | // Copyright (c) Microsoft Corporation. Licensed under the MIT license. |
5 | | // |
6 | | |
7 | | // |
8 | | // This module contains the routines to implement the Marvin32 checksum function |
9 | | // |
10 | | // |
11 | | |
12 | | #include "precomp.h" |
13 | | |
14 | | // |
15 | | // See the symcrypt.h file for documentation on what the various functions do. |
16 | | // |
17 | | |
18 | | |
19 | | // |
20 | | // Default initial seed, first 8 bytes of SHA256( "Marvin32" ); |
21 | | // |
22 | | static const SYMCRYPT_MARVIN32_EXPANDED_SEED SymCryptMarvin32DefaultSeedStruct = { |
23 | | {0xcd0893b7, 0xd53cd9ce}, |
24 | | #if defined( SYMCRYPT_MAGIC_ENABLED ) |
25 | | SYMCRYPT_MAGIC_VALUE( &SymCryptMarvin32DefaultSeedStruct ), |
26 | | #endif |
27 | | }; |
28 | | |
29 | | PCSYMCRYPT_MARVIN32_EXPANDED_SEED const SymCryptMarvin32DefaultSeed = &SymCryptMarvin32DefaultSeedStruct; |
30 | | |
31 | | // |
32 | | // Round rotation amounts. This array is optimized away by the compiler |
33 | | // as we inline all our rotations. |
34 | | // |
35 | | static const int rotate[4] = { |
36 | | 20, 9, 27, 19, |
37 | | }; |
38 | | |
39 | | |
40 | | SYMCRYPT_ERROR |
41 | | SYMCRYPT_CALL |
42 | | SymCryptMarvin32ExpandSeed( |
43 | | _Out_ PSYMCRYPT_MARVIN32_EXPANDED_SEED pExpandedSeed, |
44 | | _In_reads_(cbSeed) PCBYTE pbSeed, |
45 | | SIZE_T cbSeed ) |
46 | 0 | { |
47 | 0 | SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; |
48 | |
|
49 | 0 | if( cbSeed != SYMCRYPT_MARVIN32_SEED_SIZE ) |
50 | 0 | { |
51 | 0 | scError = SYMCRYPT_WRONG_KEY_SIZE; |
52 | 0 | goto cleanup; |
53 | 0 | } |
54 | 0 | pExpandedSeed->s[0] = SYMCRYPT_LOAD_LSBFIRST32( pbSeed ); |
55 | 0 | pExpandedSeed->s[1] = SYMCRYPT_LOAD_LSBFIRST32( pbSeed + 4 ); |
56 | |
|
57 | 0 | SYMCRYPT_SET_MAGIC( pExpandedSeed ); |
58 | |
|
59 | 0 | cleanup: |
60 | 0 | return scError; |
61 | 0 | } |
62 | | |
63 | | VOID |
64 | | SYMCRYPT_CALL |
65 | | SymCryptMarvin32SeedCopy( _In_ PCSYMCRYPT_MARVIN32_EXPANDED_SEED pSrc, |
66 | | _Out_ PSYMCRYPT_MARVIN32_EXPANDED_SEED pDst ) |
67 | 0 | { |
68 | 0 | SYMCRYPT_CHECK_MAGIC( pSrc ); |
69 | 0 | *pDst = *pSrc; |
70 | 0 | SYMCRYPT_SET_MAGIC( pDst ); |
71 | 0 | } |
72 | | |
73 | | |
74 | | VOID |
75 | | SYMCRYPT_CALL |
76 | | SymCryptMarvin32StateCopy( |
77 | | _In_ PCSYMCRYPT_MARVIN32_STATE pSrc, |
78 | | _In_opt_ PCSYMCRYPT_MARVIN32_EXPANDED_SEED pExpandedSeed, |
79 | | _Out_ PSYMCRYPT_MARVIN32_STATE pDst ) |
80 | 0 | { |
81 | 0 | SYMCRYPT_CHECK_MAGIC( pSrc ); |
82 | 0 | *pDst = *pSrc; |
83 | |
|
84 | 0 | if( pExpandedSeed == NULL ) |
85 | 0 | { |
86 | 0 | SYMCRYPT_CHECK_MAGIC( pSrc->pSeed ); |
87 | 0 | pDst->pSeed = pSrc->pSeed; |
88 | 0 | } |
89 | 0 | else |
90 | 0 | { |
91 | 0 | SYMCRYPT_CHECK_MAGIC( pExpandedSeed ); |
92 | 0 | pDst->pSeed = pExpandedSeed; |
93 | 0 | } |
94 | |
|
95 | 0 | SYMCRYPT_SET_MAGIC( pDst ); |
96 | 0 | } |
97 | | |
98 | | |
99 | | VOID |
100 | | SYMCRYPT_CALL |
101 | | SymCryptMarvin32Init( _Out_ PSYMCRYPT_MARVIN32_STATE pState, |
102 | | _In_ PCSYMCRYPT_MARVIN32_EXPANDED_SEED pExpandedSeed) |
103 | 0 | { |
104 | 0 | pState->chain = *pExpandedSeed; |
105 | 0 | pState->dataLength = 0; |
106 | 0 | pState->pSeed = pExpandedSeed; |
107 | |
|
108 | 0 | *(UINT32 *) &pState->buffer[4] = 0; // wipe the last 4 bytes of the buffer. |
109 | |
|
110 | 0 | SYMCRYPT_SET_MAGIC( pState ); |
111 | 0 | } |
112 | | |
113 | | |
114 | | // |
115 | | // SymCryptMarvin32Append |
116 | | // |
117 | | |
118 | | VOID |
119 | | SYMCRYPT_CALL |
120 | | SymCryptMarvin32Append( _Inout_ PSYMCRYPT_MARVIN32_STATE state, |
121 | | _In_reads_( cbData ) PCBYTE pbData, |
122 | | SIZE_T cbData ) |
123 | 0 | { |
124 | 0 | UINT32 bytesInBuffer = state->dataLength; |
125 | |
|
126 | 0 | SYMCRYPT_CHECK_MAGIC( state ); |
127 | |
|
128 | 0 | state->dataLength += (UINT32) cbData; // We only keep track of the last 2 bits... |
129 | |
|
130 | 0 | #define ALG MARVIN32 |
131 | 0 | #define Alg Marvin32 |
132 | 0 | #include "hash_buffer_pattern.c" |
133 | 0 | #undef ALG |
134 | 0 | #undef Alg |
135 | |
|
136 | 0 | } |
137 | | |
138 | | |
139 | | // |
140 | | // SymCryptMarvin32Result |
141 | | // |
142 | | VOID |
143 | | SYMCRYPT_CALL |
144 | | SymCryptMarvin32Result( |
145 | | _Inout_ PSYMCRYPT_MARVIN32_STATE pState, |
146 | | _Out_writes_( SYMCRYPT_MARVIN32_RESULT_SIZE ) PBYTE pbResult ) |
147 | 0 | { |
148 | 0 | SIZE_T bytesInBuffer = ( pState->dataLength) & 0x3; |
149 | |
|
150 | 0 | SYMCRYPT_CHECK_MAGIC( pState ); |
151 | | |
152 | | // |
153 | | // Wipe four bytes in the buffer. |
154 | | // Doing this first ensures that this write is aligned when the input was of |
155 | | // length 0 mod 4. |
156 | | // The buffer is 8 bytes long, so we never overwrite anything else. |
157 | | // |
158 | 0 | *(UINT32 *) &pState->buffer[bytesInBuffer] = 0; |
159 | | |
160 | | // |
161 | | // The buffer is never completely full, so we can always put the first |
162 | | // padding byte in. |
163 | | // |
164 | 0 | pState->buffer[bytesInBuffer++] = 0x80; |
165 | | |
166 | | // |
167 | | // Process the final block |
168 | | // |
169 | 0 | SymCryptMarvin32AppendBlocks( &pState->chain, pState->buffer, 8 ); |
170 | |
|
171 | 0 | SYMCRYPT_STORE_LSBFIRST32( pbResult , pState->chain.s[0] ); |
172 | 0 | SYMCRYPT_STORE_LSBFIRST32( pbResult + 4, pState->chain.s[1] ); |
173 | | |
174 | | // |
175 | | // Wipe only those things that we need to wipe. |
176 | | // |
177 | |
|
178 | 0 | *(UINT32 *) &pState->buffer[0] = 0; |
179 | 0 | pState->dataLength = 0; |
180 | |
|
181 | 0 | pState->chain = *pState->pSeed; |
182 | 0 | } |
183 | | |
184 | 0 | #define BLOCK( a, b ) \ |
185 | 0 | {\ |
186 | 0 | b ^= a; a = ROL32( a, rotate[0] );\ |
187 | 0 | a += b; b = ROL32( b, rotate[1] );\ |
188 | 0 | b ^= a; a = ROL32( a, rotate[2] );\ |
189 | 0 | a += b; b = ROL32( b, rotate[3] );\ |
190 | 0 | } |
191 | | |
192 | | VOID |
193 | | SYMCRYPT_CALL |
194 | | SymCryptMarvin32AppendBlocks( |
195 | | _Inout_ PSYMCRYPT_MARVIN32_CHAINING_STATE pChain, |
196 | | _In_reads_( cbData ) PCBYTE pbData, |
197 | | SIZE_T cbData ) |
198 | 0 | { |
199 | 0 | UINT32 s0 = pChain->s[0]; |
200 | 0 | UINT32 s1 = pChain->s[1]; |
201 | |
|
202 | 0 | SIZE_T bytesInFirstBlock = cbData & 0xc; // 0, 4, 8, or 12 |
203 | |
|
204 | 0 | SYMCRYPT_ASSERT( (cbData & 3) == 0 ); |
205 | | |
206 | |
|
207 | 0 | pbData += bytesInFirstBlock; |
208 | 0 | cbData -= bytesInFirstBlock; |
209 | |
|
210 | 0 | switch( bytesInFirstBlock ) |
211 | 0 | { |
212 | 0 | case 0: // This handles the cbData == 0 case too |
213 | 0 | while( cbData > 0 ) |
214 | 0 | { |
215 | 0 | pbData += 16; |
216 | 0 | cbData -= 16; |
217 | |
|
218 | 0 | s0 += SYMCRYPT_LOAD_LSBFIRST32( pbData - 16 ); |
219 | 0 | BLOCK( s0, s1 ); |
220 | 0 | case 12: |
221 | 0 | s0 += SYMCRYPT_LOAD_LSBFIRST32( pbData - 12 ); |
222 | 0 | BLOCK( s0, s1 ); |
223 | 0 | case 8: |
224 | 0 | s0 += SYMCRYPT_LOAD_LSBFIRST32( pbData - 8 ); |
225 | 0 | BLOCK( s0, s1 ); |
226 | 0 | case 4: |
227 | 0 | s0 += SYMCRYPT_LOAD_LSBFIRST32( pbData - 4 ); |
228 | 0 | BLOCK( s0, s1 ); |
229 | 0 | } |
230 | 0 | } |
231 | |
|
232 | 0 | pChain->s[0] = s0; |
233 | 0 | pChain->s[1] = s1; |
234 | 0 | } |
235 | | |
236 | | |
237 | | VOID |
238 | | SYMCRYPT_CALL |
239 | | SymCryptMarvin32( |
240 | | _In_ PCSYMCRYPT_MARVIN32_EXPANDED_SEED pExpandedSeed, |
241 | | _In_reads_( cbData ) PCBYTE pbData, |
242 | | SIZE_T cbData, |
243 | | _Out_writes_( SYMCRYPT_MARVIN32_RESULT_SIZE ) PBYTE pbResult ) |
244 | | // |
245 | | // To reduce the per-computation overhead, we have a dedicated code here instead of the whole Init/Append/Result stuff. |
246 | | // |
247 | 0 | { |
248 | 0 | UINT32 tmp; |
249 | |
|
250 | 0 | UINT32 s0 = pExpandedSeed->s[0]; |
251 | 0 | UINT32 s1 = pExpandedSeed->s[1]; |
252 | |
|
253 | 0 | while( cbData > 7 ) |
254 | 0 | { |
255 | 0 | s0 += SYMCRYPT_LOAD_LSBFIRST32( pbData ); |
256 | 0 | BLOCK( s0, s1 ); |
257 | 0 | s0 += SYMCRYPT_LOAD_LSBFIRST32( pbData + 4 ); |
258 | 0 | BLOCK( s0, s1 ); |
259 | 0 | pbData += 8; |
260 | 0 | cbData -= 8; |
261 | 0 | } |
262 | | |
263 | | /* |
264 | | switch( cbData ) |
265 | | { |
266 | | case 3: |
267 | | buf[2] = pbData[2]; |
268 | | case 2: |
269 | | *(UINT16 *) &buf[0] = *(UINT16 *) pbData; |
270 | | break; |
271 | | case 1: |
272 | | buf[0] = pbData[0]; |
273 | | case 0: |
274 | | ; |
275 | | } |
276 | | |
277 | | buf[ cbData ] = 0x80; |
278 | | |
279 | | s0 += LOAD_LSBFIRST32( buf ); |
280 | | */ |
281 | | |
282 | |
|
283 | 0 | switch( cbData ) |
284 | 0 | { |
285 | 0 | default: |
286 | 0 | case 4: s0 += SYMCRYPT_LOAD_LSBFIRST32( pbData ); BLOCK( s0, s1 ); pbData += 4; |
287 | 0 | case 0: tmp = 0x80; break; |
288 | | |
289 | 0 | case 5: s0 += SYMCRYPT_LOAD_LSBFIRST32( pbData ); BLOCK( s0, s1 ); pbData += 4; |
290 | 0 | case 1: tmp = 0x8000 | pbData[0]; break; |
291 | | |
292 | 0 | case 6: s0 += SYMCRYPT_LOAD_LSBFIRST32( pbData ); BLOCK( s0, s1 ); pbData += 4; |
293 | 0 | case 2: tmp = 0x800000 | SYMCRYPT_LOAD_LSBFIRST16( pbData ); break; |
294 | | |
295 | 0 | case 7: s0 += SYMCRYPT_LOAD_LSBFIRST32( pbData ); BLOCK( s0, s1 ); pbData += 4; |
296 | 0 | case 3: tmp = SYMCRYPT_LOAD_LSBFIRST16( pbData ) | (pbData[2] << 16) | 0x80000000; break; |
297 | 0 | } |
298 | 0 | s0 += tmp; |
299 | | |
300 | |
|
301 | 0 | BLOCK( s0, s1 ); |
302 | 0 | BLOCK( s0, s1 ); |
303 | |
|
304 | 0 | SYMCRYPT_STORE_LSBFIRST32( pbResult , s0 ); |
305 | 0 | SYMCRYPT_STORE_LSBFIRST32( pbResult + 4, s1 ); |
306 | 0 | } |
307 | | |
308 | | |
309 | | |
310 | | // |
311 | | // Simple test vector |
312 | | // |
313 | | |
314 | | static const BYTE marvin32KATAnswer[ 8 ] = { |
315 | | 0xbf, 0x69, 0x27, 0x49, 0x39, 0x43, 0xc7, 0x22, |
316 | | } ; |
317 | | |
318 | | VOID |
319 | | SYMCRYPT_CALL |
320 | | SymCryptMarvin32Selftest(void) |
321 | 0 | { |
322 | 0 | BYTE res[SYMCRYPT_MARVIN32_RESULT_SIZE]; |
323 | |
|
324 | 0 | SymCryptMarvin32( SymCryptMarvin32DefaultSeed, SymCryptTestMsg3, sizeof( SymCryptTestMsg3 ), res ); |
325 | |
|
326 | 0 | SymCryptInjectError( res, sizeof( res ) ); |
327 | 0 | if( memcmp( res, marvin32KATAnswer, sizeof( res ) ) != 0 ) |
328 | 0 | { |
329 | 0 | SymCryptFatal( 'marv' ); |
330 | 0 | } |
331 | 0 | } |
332 | | |