/src/SymCrypt/lib/blockciphermodes.c
Line | Count | Source (jump to first uncovered line) |
1 | | // |
2 | | // BlockCipherModes.c generic implementation of all block cipher modes |
3 | | // |
4 | | // Copyright (c) Microsoft Corporation. Licensed under the MIT license. |
5 | | // |
6 | | |
7 | | #include "precomp.h" |
8 | | |
9 | | VOID |
10 | | SYMCRYPT_CALL |
11 | | SymCryptEcbEncrypt( |
12 | | _In_ PCSYMCRYPT_BLOCKCIPHER pBlockCipher, |
13 | | _In_ PCVOID pExpandedKey, |
14 | | _In_reads_( cbData ) PCBYTE pbSrc, |
15 | | _Out_writes_( cbData ) PBYTE pbDst, |
16 | | SIZE_T cbData ) |
17 | 0 | { |
18 | 0 | SIZE_T i; |
19 | 0 | SIZE_T cbToDo = cbData & ~(pBlockCipher->blockSize - 1); |
20 | |
|
21 | 0 | if( pBlockCipher->ecbEncryptFunc != NULL ) |
22 | 0 | { |
23 | | // |
24 | | // Use optimized implementation if available |
25 | | // |
26 | 0 | (*pBlockCipher->ecbEncryptFunc)( pExpandedKey, pbSrc, pbDst, cbData ); |
27 | 0 | return; |
28 | 0 | } |
29 | | |
30 | | // |
31 | | // To avoid buffer overruns we truncate the work to an integral number of blocks. |
32 | | // |
33 | | |
34 | 0 | for( i=0; i<cbToDo; i+= pBlockCipher->blockSize ) |
35 | 0 | { |
36 | 0 | (*pBlockCipher->encryptFunc)( pExpandedKey, pbSrc + i, pbDst + i ); |
37 | 0 | } |
38 | 0 | } |
39 | | |
40 | | VOID |
41 | | SYMCRYPT_CALL |
42 | | SymCryptEcbDecrypt( |
43 | | _In_ PCSYMCRYPT_BLOCKCIPHER pBlockCipher, |
44 | | _In_ PCVOID pExpandedKey, |
45 | | _In_reads_( cbData ) PCBYTE pbSrc, |
46 | | _Out_writes_( cbData ) PBYTE pbDst, |
47 | | SIZE_T cbData ) |
48 | 0 | { |
49 | 0 | SIZE_T i; |
50 | 0 | SIZE_T cbToDo = cbData & ~(pBlockCipher->blockSize - 1); |
51 | |
|
52 | 0 | if( pBlockCipher->ecbDecryptFunc != NULL ) |
53 | 0 | { |
54 | | // |
55 | | // Use optimized implementation if available |
56 | | // |
57 | 0 | (*pBlockCipher->ecbDecryptFunc)( pExpandedKey, pbSrc, pbDst, cbData ); |
58 | 0 | return; |
59 | 0 | } |
60 | | |
61 | 0 | for( i=0; i<cbToDo; i+= pBlockCipher->blockSize ) |
62 | 0 | { |
63 | 0 | (*pBlockCipher->decryptFunc)( pExpandedKey, pbSrc + i, pbDst + i ); |
64 | 0 | } |
65 | 0 | } |
66 | | |
67 | | |
68 | | // |
69 | | // SymCryptCbcEncrypt |
70 | | // |
71 | | // Generic CBC encryption routine for block ciphers. |
72 | | // The following restrictions must be obeyed: |
73 | | // - blockSize <= 32 and must be a power of 2 |
74 | | // - cbData must be a multiple of the block size |
75 | | // |
76 | | VOID |
77 | | SYMCRYPT_CALL |
78 | | SymCryptCbcEncrypt( |
79 | | _In_ PCSYMCRYPT_BLOCKCIPHER pBlockCipher, |
80 | | _In_ PCVOID pExpandedKey, |
81 | | _Inout_updates_( pBlockCipher->blockSize ) |
82 | | PBYTE pbChainingValue, |
83 | | _In_reads_( cbData ) PCBYTE pbSrc, |
84 | | _Out_writes_( cbData ) PBYTE pbDst, |
85 | | SIZE_T cbData ) |
86 | 0 | { |
87 | 0 | SYMCRYPT_ALIGN BYTE buf[SYMCRYPT_MAX_BLOCK_SIZE]; |
88 | 0 | SIZE_T blockSize; |
89 | 0 | PCBYTE pbSrcEnd; |
90 | 0 | PCBYTE pSrc = pbSrc; |
91 | 0 | PBYTE pDst = pbDst; |
92 | |
|
93 | 0 | if( pBlockCipher->cbcEncryptFunc != NULL ) |
94 | 0 | { |
95 | | // |
96 | | // Use optimized implementation if available |
97 | | // |
98 | 0 | (*pBlockCipher->cbcEncryptFunc)( pExpandedKey, pbChainingValue, pSrc, pDst, cbData ); |
99 | 0 | return; |
100 | 0 | } |
101 | | |
102 | 0 | blockSize = pBlockCipher->blockSize; |
103 | |
|
104 | 0 | SYMCRYPT_ASSERT( blockSize <= SYMCRYPT_MAX_BLOCK_SIZE ); |
105 | | |
106 | | |
107 | | // |
108 | | // Compute the end of the data, rounding the size down to a multiple of the block size. |
109 | | // |
110 | 0 | pbSrcEnd = &pbSrc[ cbData & ~(blockSize - 1) ]; |
111 | | |
112 | | // |
113 | | // We keep the chaining state in a local buffer to enforce the read-once write-once rule. |
114 | | // |
115 | 0 | memcpy( buf, pbChainingValue, blockSize ); |
116 | 0 | while( pSrc < pbSrcEnd ) |
117 | 0 | { |
118 | 0 | SYMCRYPT_ASSERT( pSrc <= pbSrc + cbData - blockSize ); // help PreFast |
119 | 0 | SYMCRYPT_ASSERT( pDst <= pbDst + cbData - blockSize ); // help PreFast |
120 | 0 | SYMCRYPT_ASSERT( blockSize <= cbData ); // help PreFast |
121 | 0 | SymCryptXorBytes( pSrc, buf, buf, blockSize ); |
122 | 0 | (*pBlockCipher->encryptFunc)( pExpandedKey, buf, buf ); |
123 | 0 | memcpy( pDst, buf, blockSize ); |
124 | 0 | pSrc += blockSize; |
125 | 0 | pDst += blockSize; |
126 | 0 | } |
127 | |
|
128 | 0 | memcpy( pbChainingValue, buf, blockSize ); |
129 | |
|
130 | 0 | SymCryptWipeKnownSize( buf, sizeof( buf )); |
131 | 0 | } |
132 | | |
133 | | // |
134 | | // SymCryptCbcDecrypt |
135 | | // |
136 | | // Generic CBC decryption routine for block ciphers. |
137 | | // The following restrictions must be obeyed: |
138 | | // - blockSize <= 32 and must be a power of 2 |
139 | | // - cbData must be a multiple of the block size |
140 | | // |
141 | | VOID |
142 | | SYMCRYPT_CALL |
143 | | SymCryptCbcDecrypt( |
144 | | _In_ PCSYMCRYPT_BLOCKCIPHER pBlockCipher, |
145 | | _In_ PCVOID pExpandedKey, |
146 | | _Inout_updates_( pBlockCipher->blockSize ) |
147 | | PBYTE pbChainingValue, |
148 | | _In_reads_( cbData ) PCBYTE pbSrc, |
149 | | _Out_writes_( cbData ) PBYTE pbDst, |
150 | | SIZE_T cbData ) |
151 | 0 | { |
152 | 0 | SYMCRYPT_ALIGN BYTE buf[3 * SYMCRYPT_MAX_BLOCK_SIZE]; |
153 | 0 | PBYTE chain = &buf[0]; |
154 | 0 | PBYTE ciphertext = &buf[SYMCRYPT_MAX_BLOCK_SIZE]; |
155 | 0 | PBYTE tmp = &buf[2*SYMCRYPT_MAX_BLOCK_SIZE]; |
156 | |
|
157 | 0 | SIZE_T blockSize; |
158 | 0 | PCBYTE pbSrcEnd; |
159 | |
|
160 | 0 | if( pBlockCipher->cbcDecryptFunc != NULL ) |
161 | 0 | { |
162 | 0 | (*pBlockCipher->cbcDecryptFunc)( pExpandedKey, pbChainingValue, pbSrc, pbDst, cbData ); |
163 | 0 | return; |
164 | 0 | } |
165 | | |
166 | 0 | blockSize = pBlockCipher->blockSize; |
167 | 0 | SYMCRYPT_ASSERT( blockSize <= SYMCRYPT_MAX_BLOCK_SIZE ); |
168 | | |
169 | | // |
170 | | // Compute the end of the data, rounding the size down to a multiple of the block size. |
171 | | // |
172 | 0 | pbSrcEnd = &pbSrc[ cbData & ~(blockSize-1) ]; |
173 | |
|
174 | 0 | #pragma warning(suppress: 22105) |
175 | 0 | memcpy( chain, pbChainingValue, blockSize ); |
176 | | |
177 | | // |
178 | | // Loop structured to obey the read-once/write-once rule |
179 | | // |
180 | 0 | while( pbSrc < pbSrcEnd ) |
181 | 0 | { |
182 | 0 | SYMCRYPT_ASSERT( pbSrc <= pbSrcEnd - blockSize ); // help PreFast |
183 | 0 | memcpy( ciphertext, pbSrc, blockSize ); |
184 | 0 | (*pBlockCipher->decryptFunc)( pExpandedKey, ciphertext, tmp ); |
185 | 0 | SymCryptXorBytes( tmp, chain, pbDst, blockSize ); |
186 | 0 | memcpy( chain, ciphertext, blockSize ); |
187 | 0 | pbDst += blockSize; |
188 | 0 | pbSrc += blockSize; |
189 | 0 | } |
190 | |
|
191 | 0 | memcpy( pbChainingValue, chain, blockSize ); |
192 | |
|
193 | 0 | SymCryptWipeKnownSize( buf, sizeof( buf )); |
194 | 0 | } |
195 | | |
196 | | VOID |
197 | | SYMCRYPT_CALL |
198 | | SymCryptCbcMac( |
199 | | _In_ PCSYMCRYPT_BLOCKCIPHER pBlockCipher, |
200 | | _In_ PCVOID pExpandedKey, |
201 | | _Inout_updates_( pBlockCipher->blockSize ) |
202 | | PBYTE pbChainingValue, |
203 | | _In_reads_( cbData ) PCBYTE pbSrc, |
204 | | SIZE_T cbData ) |
205 | 0 | { |
206 | 0 | SYMCRYPT_ALIGN BYTE buf[32]; |
207 | 0 | SIZE_T blockSize; |
208 | 0 | PCBYTE pbSrcEnd; |
209 | 0 | PCBYTE p; |
210 | |
|
211 | 0 | if( pBlockCipher->cbcMacFunc != NULL ) |
212 | 0 | { |
213 | | // |
214 | | // Use optimized implementation if available |
215 | | // |
216 | 0 | (*pBlockCipher->cbcMacFunc)( pExpandedKey, pbChainingValue, pbSrc, cbData ); |
217 | 0 | return; |
218 | 0 | } |
219 | | |
220 | 0 | blockSize = pBlockCipher->blockSize; |
221 | 0 | SYMCRYPT_ASSERT( blockSize <= SYMCRYPT_MAX_BLOCK_SIZE ); |
222 | | |
223 | | // |
224 | | // Compute the end of the data, rounding the size down to a multiple of the block size. |
225 | | // |
226 | 0 | pbSrcEnd = &pbSrc[ cbData & ~(blockSize - 1) ]; |
227 | | |
228 | | // |
229 | | // We keep the chaining state in a local buffer to enforce the read-once write-once rule. |
230 | | // It also improves memory locality. |
231 | | // |
232 | 0 | memcpy( buf, pbChainingValue, blockSize ); |
233 | 0 | p = pbSrc; |
234 | 0 | while( p < pbSrcEnd ) |
235 | 0 | { |
236 | 0 | SYMCRYPT_ASSERT( p <= pbSrc + cbData - blockSize ); |
237 | 0 | SymCryptXorBytes( p, buf, buf, blockSize ); |
238 | 0 | (*pBlockCipher->encryptFunc)( pExpandedKey, buf, buf ); |
239 | 0 | p += blockSize; |
240 | 0 | } |
241 | |
|
242 | 0 | memcpy( pbChainingValue, buf, blockSize ); |
243 | |
|
244 | 0 | SymCryptWipeKnownSize( buf, sizeof( buf )); |
245 | 0 | } |
246 | | |
247 | | VOID |
248 | | SYMCRYPT_CALL |
249 | | SymCryptCtrMsb32( |
250 | | _In_ PCSYMCRYPT_BLOCKCIPHER pBlockCipher, |
251 | | _In_ PCVOID pExpandedKey, |
252 | | _Inout_updates_( pBlockCipher->blockSize ) |
253 | | PBYTE pbChainingValue, |
254 | | _In_reads_( cbData ) PCBYTE pbSrc, |
255 | | _Out_writes_( cbData ) PBYTE pbDst, |
256 | | SIZE_T cbData ) |
257 | 0 | { |
258 | 0 | SYMCRYPT_ALIGN BYTE buf[2 * SYMCRYPT_MAX_BLOCK_SIZE]; |
259 | 0 | PBYTE count = &buf[0]; |
260 | 0 | PBYTE keystream= &buf[SYMCRYPT_MAX_BLOCK_SIZE]; |
261 | 0 | SIZE_T blockSize; |
262 | 0 | PCBYTE pbSrcEnd; |
263 | |
|
264 | 0 | blockSize = pBlockCipher->blockSize; |
265 | 0 | SYMCRYPT_ASSERT( blockSize <= SYMCRYPT_MAX_BLOCK_SIZE ); |
266 | | |
267 | | // |
268 | | // Compute the end of the data, rounding the size down to a multiple of the block size. |
269 | | // |
270 | 0 | pbSrcEnd = &pbSrc[ cbData & ~(blockSize - 1) ]; |
271 | | |
272 | | // |
273 | | // We keep the chaining state in a local buffer to enforce the read-once write-once rule. |
274 | | // It also improves memory locality. |
275 | | // |
276 | 0 | #pragma warning(suppress: 22105) |
277 | 0 | memcpy( count, pbChainingValue, blockSize ); |
278 | 0 | while( pbSrc < pbSrcEnd ) |
279 | 0 | { |
280 | 0 | SYMCRYPT_ASSERT( pbSrc <= pbSrcEnd - blockSize ); // help PreFast |
281 | 0 | (*pBlockCipher->encryptFunc)( pExpandedKey, count, keystream ); |
282 | 0 | SymCryptXorBytes( keystream, pbSrc, pbDst, blockSize ); |
283 | | |
284 | | // |
285 | | // We only need to increment the last 32 bits of the counter value. |
286 | | // |
287 | 0 | SYMCRYPT_STORE_MSBFIRST32( &count[ blockSize-4 ], 1 + SYMCRYPT_LOAD_MSBFIRST32( &count[ blockSize-4 ] ) ); |
288 | |
|
289 | 0 | pbSrc += blockSize; |
290 | 0 | pbDst += blockSize; |
291 | 0 | } |
292 | |
|
293 | 0 | memcpy( pbChainingValue, count, blockSize ); |
294 | |
|
295 | 0 | SymCryptWipeKnownSize( buf, sizeof( buf )); |
296 | 0 | } |
297 | | |
298 | | VOID |
299 | | SYMCRYPT_CALL |
300 | | SymCryptCtrMsb64( |
301 | | _In_ PCSYMCRYPT_BLOCKCIPHER pBlockCipher, |
302 | | _In_ PCVOID pExpandedKey, |
303 | | _Inout_updates_( pBlockCipher->blockSize ) |
304 | | PBYTE pbChainingValue, |
305 | | _In_reads_( cbData ) PCBYTE pbSrc, |
306 | | _Out_writes_( cbData ) PBYTE pbDst, |
307 | | SIZE_T cbData ) |
308 | 0 | { |
309 | 0 | SYMCRYPT_ALIGN BYTE buf[2 * SYMCRYPT_MAX_BLOCK_SIZE]; |
310 | 0 | PBYTE count = &buf[0]; |
311 | 0 | PBYTE keystream= &buf[SYMCRYPT_MAX_BLOCK_SIZE]; |
312 | 0 | SIZE_T blockSize; |
313 | 0 | PCBYTE pbSrcEnd; |
314 | |
|
315 | 0 | if( pBlockCipher->ctrMsb64Func != NULL ) |
316 | 0 | { |
317 | | // |
318 | | // Use optimized implementation if available |
319 | | // |
320 | 0 | (*pBlockCipher->ctrMsb64Func)( pExpandedKey, pbChainingValue, pbSrc, pbDst, cbData ); |
321 | 0 | return; |
322 | 0 | } |
323 | | |
324 | 0 | blockSize = pBlockCipher->blockSize; |
325 | 0 | SYMCRYPT_ASSERT( blockSize <= SYMCRYPT_MAX_BLOCK_SIZE ); |
326 | | |
327 | | // |
328 | | // Compute the end of the data, rounding the size down to a multiple of the block size. |
329 | | // |
330 | 0 | pbSrcEnd = &pbSrc[ cbData & ~(blockSize - 1) ]; |
331 | | |
332 | | // |
333 | | // We keep the chaining state in a local buffer to enforce the read-once write-once rule. |
334 | | // It also improves memory locality. |
335 | | // |
336 | 0 | #pragma warning(suppress: 22105) |
337 | 0 | memcpy( count, pbChainingValue, blockSize ); |
338 | 0 | while( pbSrc < pbSrcEnd ) |
339 | 0 | { |
340 | 0 | SYMCRYPT_ASSERT( pbSrc <= pbSrcEnd - blockSize ); // help PreFast |
341 | 0 | (*pBlockCipher->encryptFunc)( pExpandedKey, count, keystream ); |
342 | 0 | SymCryptXorBytes( keystream, pbSrc, pbDst, blockSize ); |
343 | | |
344 | | // |
345 | | // We only need to increment the last 64 bits of the counter value. |
346 | | // |
347 | 0 | SYMCRYPT_STORE_MSBFIRST64( &count[ blockSize-8 ], 1 + SYMCRYPT_LOAD_MSBFIRST64( &count[ blockSize-8 ] ) ); |
348 | |
|
349 | 0 | pbSrc += blockSize; |
350 | 0 | pbDst += blockSize; |
351 | 0 | } |
352 | |
|
353 | 0 | memcpy( pbChainingValue, count, blockSize ); |
354 | |
|
355 | 0 | SymCryptWipeKnownSize( buf, sizeof( buf )); |
356 | 0 | } |
357 | | |
358 | | VOID |
359 | | SYMCRYPT_CALL |
360 | | SymCryptCfbEncrypt( |
361 | | _In_ PCSYMCRYPT_BLOCKCIPHER pBlockCipher, |
362 | | SIZE_T cbShift, |
363 | | _In_ PCVOID pExpandedKey, |
364 | | _Inout_updates_( pBlockCipher->blockSize ) |
365 | | PBYTE pbChainingValue, |
366 | | _In_reads_( cbData ) PCBYTE pbSrc, |
367 | | _Out_writes_( cbData ) PBYTE pbDst, |
368 | | SIZE_T cbData ) |
369 | | // |
370 | | // Encrypt a buffer using the CFB cipher mode. |
371 | | // |
372 | | // This implements the CFB mode using a 1-byte feedback shift. |
373 | | // This requires a block cipher encryption call for each byte, which is very slow. |
374 | | // Use of this cipher mode is not recommended. |
375 | | // |
376 | | // - pBlockCipher is a pointer to the block cipher description table. |
377 | | // Suitable description tables for all ciphers in this library have been pre-defined. |
378 | | // - pExpandedKey points to the expanded key to use. This generic function uses PVOID so there |
379 | | // is no type safety to ensure that the expanded key and the encryption function match. |
380 | | // - pbChainingValue points to the chaining value. On entry and exit it |
381 | | // contains the last blockSize ciphertext bytes. |
382 | | // - pbSrc is the input data buffer that will be encrypted/decrypted. |
383 | | // - cbData. Number of bytes to encrypt/decrypt. This must be a multiple of the block size. |
384 | | // - pbDst is the output buffer that receives the encrypted/decrypted data. The input and output |
385 | | // buffers may be the same or non-overlapping, but may not partially overlap. |
386 | | // |
387 | 0 | { |
388 | 0 | SYMCRYPT_ALIGN BYTE buf[2*SYMCRYPT_MAX_BLOCK_SIZE]; |
389 | 0 | PBYTE chain = &buf[0]; |
390 | 0 | PBYTE tmp = &buf[SYMCRYPT_MAX_BLOCK_SIZE]; |
391 | 0 | SIZE_T blockSize; |
392 | |
|
393 | 0 | blockSize = pBlockCipher->blockSize; |
394 | 0 | SYMCRYPT_ASSERT( blockSize <= SYMCRYPT_MAX_BLOCK_SIZE ); |
395 | | |
396 | | // Force cbShift to either be 1 or blockSize |
397 | 0 | if(cbShift != 1) |
398 | 0 | { |
399 | 0 | cbShift = blockSize; |
400 | 0 | } |
401 | |
|
402 | 0 | memcpy( chain, pbChainingValue, blockSize ); |
403 | 0 | while( cbData >= cbShift ) |
404 | 0 | { |
405 | 0 | (*pBlockCipher->encryptFunc)( pExpandedKey, chain, tmp ); |
406 | 0 | SymCryptXorBytes( pbSrc, tmp, tmp, cbShift ); // tmp[0..cbShift-1] ^= pbSrc[0..cbShift-1] |
407 | 0 | memcpy( pbDst, tmp, cbShift ); |
408 | |
|
409 | 0 | memmove( chain, chain + cbShift, blockSize - cbShift ); |
410 | 0 | memcpy( chain + blockSize - cbShift, tmp, cbShift ); |
411 | |
|
412 | 0 | pbDst += cbShift; |
413 | 0 | pbSrc += cbShift; |
414 | 0 | cbData -= cbShift; |
415 | 0 | } |
416 | |
|
417 | 0 | memcpy( pbChainingValue, chain, blockSize ); |
418 | 0 | } |
419 | | |
420 | | |
421 | | VOID |
422 | | SYMCRYPT_CALL |
423 | | SymCryptCfbDecrypt( |
424 | | _In_ PCSYMCRYPT_BLOCKCIPHER pBlockCipher, |
425 | | SIZE_T cbShift, |
426 | | _In_ PCVOID pExpandedKey, |
427 | | _Inout_updates_( pBlockCipher->blockSize ) |
428 | | PBYTE pbChainingValue, |
429 | | _In_reads_( cbData ) PCBYTE pbSrc, |
430 | | _Out_writes_( cbData ) PBYTE pbDst, |
431 | | SIZE_T cbData ) |
432 | 0 | { |
433 | 0 | SYMCRYPT_ALIGN BYTE buf[2*SYMCRYPT_MAX_BLOCK_SIZE]; |
434 | 0 | PBYTE chain = &buf[0]; |
435 | 0 | PBYTE tmp = &buf[SYMCRYPT_MAX_BLOCK_SIZE]; |
436 | 0 | SIZE_T blockSize; |
437 | |
|
438 | 0 | blockSize = pBlockCipher->blockSize; |
439 | 0 | SYMCRYPT_ASSERT( blockSize <= SYMCRYPT_MAX_BLOCK_SIZE ); |
440 | | |
441 | | // Force cbShift to either be 1 or blockSize |
442 | 0 | if(cbShift != 1) |
443 | 0 | { |
444 | 0 | cbShift = blockSize; |
445 | 0 | } |
446 | |
|
447 | 0 | memcpy( chain, pbChainingValue, blockSize ); |
448 | 0 | while( cbData >= cbShift ) |
449 | 0 | { |
450 | 0 | (*pBlockCipher->encryptFunc)( pExpandedKey, chain, tmp ); |
451 | | |
452 | | // |
453 | | // First we update the chain block |
454 | | // |
455 | |
|
456 | 0 | memmove( chain, chain + cbShift, blockSize - cbShift ); |
457 | 0 | memcpy( chain + blockSize - cbShift, pbSrc, cbShift ); |
458 | | |
459 | | // |
460 | | // To obey the read-once rule, we take the ciphertext from the updated chain block. |
461 | | // |
462 | 0 | SymCryptXorBytes( chain + blockSize - cbShift, tmp, pbDst, cbShift ); |
463 | |
|
464 | 0 | pbDst += cbShift; |
465 | 0 | pbSrc += cbShift; |
466 | 0 | cbData -= cbShift; |
467 | 0 | } |
468 | |
|
469 | 0 | memcpy( pbChainingValue, chain, blockSize ); |
470 | 0 | } |