/src/SymCrypt/lib/sp800_108.c
Line | Count | Source (jump to first uncovered line) |
1 | | // |
2 | | // sp800_108.c |
3 | | // |
4 | | // Copyright (c) Microsoft Corporation. Licensed under the MIT license. |
5 | | // |
6 | | |
7 | | // |
8 | | // This module contains the routines to implement the SP800-108 CTR KDF function |
9 | | // |
10 | | // |
11 | | |
12 | | #include "precomp.h" |
13 | | |
14 | | SYMCRYPT_ERROR |
15 | | SYMCRYPT_CALL |
16 | | SymCryptSp800_108Derive( |
17 | | _In_ PCSYMCRYPT_SP800_108_EXPANDED_KEY pExpandedKey, |
18 | | _In_reads_opt_(cbLabel) PCBYTE pbLabel, |
19 | | SIZE_T cbLabel, |
20 | | _In_reads_opt_(cbContext) PCBYTE pbContext, |
21 | | SIZE_T cbContext, |
22 | | _Out_writes_(cbResult) PBYTE pbResult, |
23 | | SIZE_T cbResult) |
24 | 34 | { |
25 | 34 | SYMCRYPT_MAC_STATE macState; |
26 | 34 | UINT32 iBlock; |
27 | 34 | SIZE_T bytes; |
28 | 34 | SIZE_T blockSize = pExpandedKey->macAlg->resultSize; |
29 | 34 | SIZE_T bytesRemaining = cbResult; |
30 | 34 | BYTE buf[4]; |
31 | 34 | SYMCRYPT_ALIGN BYTE rbBlockResult[SYMCRYPT_MAC_MAX_RESULT_SIZE]; |
32 | | |
33 | 34 | SYMCRYPT_ASSERT( |
34 | 34 | blockSize <= SYMCRYPT_MAC_MAX_RESULT_SIZE && |
35 | 34 | bytesRemaining > 0 ); |
36 | | |
37 | 34 | if( cbResult > UINT32_MAX/8 ) |
38 | 0 | { |
39 | | // SP800-108 requires the output size in bits to be encoded in a 32-bit value. |
40 | | // cbResults that are too large are impossible. |
41 | 0 | return SYMCRYPT_INVALID_ARGUMENT; |
42 | 0 | } |
43 | | |
44 | 34 | iBlock = 0; |
45 | 10.3k | while( bytesRemaining > 0 ) |
46 | 10.3k | { |
47 | 10.3k | iBlock += 1; |
48 | 10.3k | pExpandedKey->macAlg->initFunc ( &macState, &pExpandedKey->macKey); |
49 | | |
50 | | // |
51 | | // We append the pieces into the MAC function. This is inefficient but works always. |
52 | | // If we need more speed for large outputs, we could use a fixed-size stack buffer to build the |
53 | | // concatenation & do a single append. This reduces the # calls in the loop, but adds one memcpy to |
54 | | // the parameters. For small output sizes this is probably a wash. |
55 | | // |
56 | | |
57 | 10.3k | SYMCRYPT_STORE_MSBFIRST32( &buf[0], iBlock ); |
58 | 10.3k | pExpandedKey->macAlg->appendFunc( &macState, &buf[0], 4 ); // block count encoded in 4 bytes |
59 | | |
60 | 10.3k | if( cbLabel != (SIZE_T) -1 ) |
61 | 10.3k | { |
62 | | // |
63 | | // cbLabel == -1 signals a generic input in the Context field. |
64 | | // |
65 | 10.3k | pExpandedKey->macAlg->appendFunc( &macState, pbLabel, cbLabel ); // label |
66 | | |
67 | 10.3k | buf[0] = 0; |
68 | 10.3k | pExpandedKey->macAlg->appendFunc( &macState, &buf[0], 1 ); // zero byte |
69 | 10.3k | } |
70 | | |
71 | 10.3k | pExpandedKey->macAlg->appendFunc( &macState, pbContext, cbContext); // Context |
72 | | |
73 | 10.3k | SYMCRYPT_STORE_MSBFIRST32( &buf[0], 8 * (UINT32)cbResult ); |
74 | 10.3k | pExpandedKey->macAlg->appendFunc( &macState, &buf[0], 4 ); // output length, in bits |
75 | | |
76 | 10.3k | pExpandedKey->macAlg->resultFunc( &macState, rbBlockResult ); |
77 | | |
78 | 10.3k | bytes = SYMCRYPT_MIN( bytesRemaining, blockSize ); |
79 | 10.3k | memcpy( pbResult, rbBlockResult, bytes ); |
80 | 10.3k | pbResult += bytes; |
81 | 10.3k | bytesRemaining -= bytes; |
82 | 10.3k | } |
83 | | |
84 | 34 | SymCryptWipeKnownSize( rbBlockResult, sizeof( rbBlockResult ) ); |
85 | 34 | return SYMCRYPT_NO_ERROR; |
86 | 34 | } |
87 | | |
88 | | SYMCRYPT_ERROR |
89 | | SYMCRYPT_CALL |
90 | | SymCryptSp800_108ExpandKey( |
91 | | _Out_ PSYMCRYPT_SP800_108_EXPANDED_KEY pExpandedKey, |
92 | | _In_ PCSYMCRYPT_MAC macAlgorithm, |
93 | | _In_reads_(cbKey) PCBYTE pbKey, |
94 | | SIZE_T cbKey ) |
95 | 34 | { |
96 | 34 | SYMCRYPT_ASSERT( macAlgorithm->expandedKeySize <= sizeof( pExpandedKey->macKey ) ); |
97 | | |
98 | 34 | pExpandedKey->macAlg = macAlgorithm; |
99 | 34 | return macAlgorithm->expandKeyFunc(&pExpandedKey->macKey, pbKey, cbKey ); |
100 | 34 | } |
101 | | |
102 | | SYMCRYPT_ERROR |
103 | | SYMCRYPT_CALL |
104 | | SymCryptSp800_108( |
105 | | PCSYMCRYPT_MAC macAlgorithm, |
106 | | _In_reads_(cbKey) PCBYTE pbKey, |
107 | | SIZE_T cbKey, |
108 | | _In_reads_opt_(cbLabel) PCBYTE pbLabel, |
109 | | SIZE_T cbLabel, |
110 | | _In_reads_opt_(cbContext) PCBYTE pbContext, |
111 | | SIZE_T cbContext, |
112 | | _Out_writes_(cbResult) PBYTE pbResult, |
113 | | SIZE_T cbResult) |
114 | 34 | { |
115 | 34 | SYMCRYPT_SP800_108_EXPANDED_KEY key; |
116 | 34 | SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; |
117 | | |
118 | 34 | scError = SymCryptSp800_108ExpandKey( &key, macAlgorithm, pbKey, cbKey ); |
119 | 34 | if( scError != SYMCRYPT_NO_ERROR ) |
120 | 0 | { |
121 | 0 | goto cleanup; |
122 | 0 | } |
123 | | |
124 | 34 | scError = SymCryptSp800_108Derive( &key, pbLabel, cbLabel, pbContext, cbContext, pbResult, cbResult ); |
125 | 34 | if( scError != SYMCRYPT_NO_ERROR ) |
126 | 0 | { |
127 | 0 | goto cleanup; |
128 | 0 | } |
129 | | |
130 | 34 | cleanup: |
131 | | |
132 | 34 | SymCryptWipeKnownSize( &key, sizeof( key ) ); |
133 | | |
134 | 34 | return scError; |
135 | | |
136 | 34 | } |
137 | | |
138 | | |
139 | | // |
140 | | // Self tests are in sp800_108_*.c files |
141 | | // to avoid pulling in SHA-1 when only SP800-108-SHA256 is used and |
142 | | // similar scenarios. |
143 | | // |
144 | | |