Coverage Report

Created: 2024-11-21 07:03

/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
}