forked from microsoft/SymCrypt
-
Notifications
You must be signed in to change notification settings - Fork 0
/
aescmac.c
259 lines (210 loc) · 7.42 KB
/
aescmac.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
//
// aescmac.c Implementation of the AES-CMAC block cipher mode
//
// Copyright (c) Microsoft Corporation. Licensed under the MIT license.
//
#include "precomp.h"
const SYMCRYPT_MAC SymCryptAesCmacAlgorithm_fast = {
SymCryptAesCmacExpandKey,
SymCryptAesCmacInit,
SymCryptAesCmacAppend,
SymCryptAesCmacResult,
sizeof(SYMCRYPT_AES_CMAC_EXPANDED_KEY),
sizeof(SYMCRYPT_AES_CMAC_STATE),
SYMCRYPT_AES_CMAC_RESULT_SIZE,
NULL,
0,
};
const PCSYMCRYPT_MAC SymCryptAesCmacAlgorithm = &SymCryptAesCmacAlgorithm_fast;
VOID
SYMCRYPT_CALL
SymCryptCmacMunge(
_Inout_updates_bytes_(SYMCRYPT_AES_BLOCK_SIZE) BYTE buf[SYMCRYPT_AES_BLOCK_SIZE] )
{
SIZE_T carry = 0;
SIZE_T tmp;
int i;
for( i=15; i>=0; i-- )
{
tmp = buf[i];
buf[i] = ((tmp << 1) | carry) & 0xff;
carry = tmp >> 7;
}
buf[15] ^= (0 - carry) & 0x87; // This is the R_128 value from SP 800-38B 5.3
}
SYMCRYPT_ERROR
SYMCRYPT_CALL
SymCryptAesCmacExpandKey(
_Out_ PSYMCRYPT_AES_CMAC_EXPANDED_KEY pExpandedKey,
_In_reads_(cbKey) PCBYTE pbKey,
SIZE_T cbKey )
{
SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR;
SYMCRYPT_ALIGN BYTE buf[SYMCRYPT_AES_BLOCK_SIZE];
scError = SymCryptAesExpandKey( &pExpandedKey->aesKey, pbKey, cbKey );
if( scError != SYMCRYPT_NO_ERROR )
{
goto cleanup;
}
SymCryptWipeKnownSize( buf, sizeof( buf ) );
SymCryptAesEncrypt( &pExpandedKey->aesKey, buf, buf );
SymCryptCmacMunge( buf );
memcpy( &pExpandedKey->K1, buf, sizeof( buf ) );
SymCryptCmacMunge( buf );
memcpy( &pExpandedKey->K2, buf, sizeof( buf ) );
SymCryptWipeKnownSize( buf, sizeof( buf ) );
SYMCRYPT_SET_MAGIC( pExpandedKey );
cleanup:
return scError;
}
VOID
SYMCRYPT_CALL
SymCryptAesCmacKeyCopy(
_In_ PCSYMCRYPT_AES_CMAC_EXPANDED_KEY pSrc,
_Out_ PSYMCRYPT_AES_CMAC_EXPANDED_KEY pDst )
{
SYMCRYPT_CHECK_MAGIC( pSrc );
SymCryptAesKeyCopy( &pSrc->aesKey, &pDst->aesKey );
memcpy( pDst->K1, pSrc->K1, sizeof( pDst->K1 ) );
memcpy( pDst->K2, pSrc->K2, sizeof( pDst->K2 ) );
SYMCRYPT_SET_MAGIC( pDst );
}
VOID
SYMCRYPT_CALL
SymCryptAesCmac(
_In_ PSYMCRYPT_AES_CMAC_EXPANDED_KEY pExpandedKey,
_In_reads_( cbData ) PCBYTE pbData,
SIZE_T cbData,
_Out_writes_( SYMCRYPT_AES_CMAC_RESULT_SIZE ) PBYTE pbResult )
{
SYMCRYPT_AES_CMAC_STATE state;
SymCryptAesCmacInit( &state, pExpandedKey );
SymCryptAesCmacAppend( &state, pbData, cbData );
SymCryptAesCmacResult( &state, pbResult );
SymCryptWipeKnownSize( &state, sizeof( state ) );
}
VOID
SYMCRYPT_CALL
SymCryptAesCmacStateCopy(
_In_ PCSYMCRYPT_AES_CMAC_STATE pSrc,
_In_opt_ PCSYMCRYPT_AES_CMAC_EXPANDED_KEY pExpandedKey,
_Out_ PSYMCRYPT_AES_CMAC_STATE pDst )
{
SYMCRYPT_CHECK_MAGIC( pSrc );
*pDst = *pSrc;
if( pExpandedKey == NULL )
{
SYMCRYPT_CHECK_MAGIC( pSrc->pKey );
pDst->pKey = pSrc->pKey;
}
else
{
SYMCRYPT_CHECK_MAGIC( pExpandedKey );
pDst->pKey = pExpandedKey;
}
SYMCRYPT_SET_MAGIC( pDst );
}
VOID
SYMCRYPT_CALL
SymCryptAesCmacInit(
_Out_ PSYMCRYPT_AES_CMAC_STATE pState,
_In_ PCSYMCRYPT_AES_CMAC_EXPANDED_KEY pExpandedKey)
{
SYMCRYPT_CHECK_MAGIC( pExpandedKey );
pState->bytesInBuf = 0;
SymCryptWipeKnownSize( pState->chain, sizeof( pState->chain ) );
pState->pKey = pExpandedKey;
SYMCRYPT_SET_MAGIC( pState );
}
VOID
SYMCRYPT_CALL
SymCryptAesCmacAppend(
_Inout_ PSYMCRYPT_AES_CMAC_STATE pState,
_In_reads_( cbData ) PCBYTE pbData,
SIZE_T cbData )
{
SYMCRYPT_CHECK_MAGIC( pState );
if( pState->bytesInBuf != 0 )
{
SIZE_T freeInBuf = SYMCRYPT_AES_BLOCK_SIZE - pState->bytesInBuf;
SYMCRYPT_ASSERT( freeInBuf < SYMCRYPT_AES_BLOCK_SIZE );
if( cbData <= freeInBuf )
{
// Do nothing.
// the data will be copied into the buf at the end of this function
//
}
else
{
memcpy( &pState->buf[pState->bytesInBuf], pbData, freeInBuf );
pbData += freeInBuf;
cbData -= freeInBuf;
SymCryptAesCbcMac( &pState->pKey->aesKey, &pState->chain[0], &pState->buf[0], SYMCRYPT_AES_BLOCK_SIZE );
pState->bytesInBuf = 0;
}
}
//
// At this point, either pState->bytesInBuf == 0, or it is !=0 but cbData is small enough that all the
// data will still fit in the buffer without further processing.
//
if( cbData > SYMCRYPT_AES_BLOCK_SIZE )
{
SIZE_T bytesToDo = (cbData-1) & ~(SIZE_T)(SYMCRYPT_AES_BLOCK_SIZE - 1);
SymCryptAesCbcMac( &pState->pKey->aesKey, &pState->chain[0], pbData, bytesToDo );
pbData += bytesToDo;
cbData -= bytesToDo;
}
if( cbData > 0 )
{
memcpy( &pState->buf[pState->bytesInBuf], pbData, cbData );
pState->bytesInBuf += cbData;
}
}
VOID
SYMCRYPT_CALL
SymCryptAesCmacResult(
_Inout_ PSYMCRYPT_AES_CMAC_STATE pState,
_Out_writes_( SYMCRYPT_AES_CMAC_RESULT_SIZE ) PBYTE pbResult )
{
SYMCRYPT_CHECK_MAGIC( pState );
if( pState->bytesInBuf < SYMCRYPT_AES_BLOCK_SIZE )
{
SymCryptWipe( &pState->buf[pState->bytesInBuf + 1], SYMCRYPT_AES_BLOCK_SIZE - pState->bytesInBuf - 1 );
pState->buf[pState->bytesInBuf] = 0x80;
SymCryptXorBytes( &pState->buf[0], &pState->pKey->K2[0], &pState->buf[0], SYMCRYPT_AES_BLOCK_SIZE );
}
else
{
SymCryptXorBytes( &pState->buf[0], &pState->pKey->K1[0], &pState->buf[0], SYMCRYPT_AES_BLOCK_SIZE );
}
SymCryptAesCbcMac( &pState->pKey->aesKey, &pState->chain[0], &pState->buf[0], SYMCRYPT_AES_BLOCK_SIZE );
memcpy( pbResult, &pState->chain[0], SYMCRYPT_AES_BLOCK_SIZE );
//
// Put the state back in the original starting state,
// and wipe any traces of the data.
//
pState->bytesInBuf = 0;
SymCryptWipeKnownSize( pState->chain, sizeof( pState->chain ) );
SymCryptWipeKnownSize( pState->buf, sizeof( pState->buf ) );
}
static const BYTE aesCmacKat[SYMCRYPT_AES_CMAC_RESULT_SIZE] = {
0x0a, 0x54, 0xa6, 0xa4, 0x25, 0xd4, 0x84, 0x38, 0xc3, 0xf8, 0xbb, 0xe0, 0x9b, 0xf9, 0x44, 0xcc,
};
VOID
SYMCRYPT_CALL
SymCryptAesCmacSelftest(void)
{
SYMCRYPT_AES_CMAC_EXPANDED_KEY xKey;
BYTE res[SYMCRYPT_AES_CMAC_RESULT_SIZE];
SymCryptAesCmacExpandKey( &xKey, SymCryptTestKey32, 16 );
SymCryptAesCmac( &xKey, SymCryptTestMsg3, sizeof( SymCryptTestMsg3 ), res );
SymCryptInjectError( res, sizeof( res ) );
if( memcmp( res, aesCmacKat, sizeof( res ) ) != 0 )
{
SymCryptFatal( 'hsh5' );
}
//
// Normally we would wipe the expanded key structure here,
// but as this is a selftest with known data this is not needed.
//
}