Line | Count | Source (jump to first uncovered line) |
1 | | // |
2 | | // xmss.c XMSS and XMSS^MT implementation |
3 | | // |
4 | | // Copyright (c) Microsoft Corporation. Licensed under the MIT license. |
5 | | // |
6 | | |
7 | | #include "precomp.h" |
8 | | |
9 | | // |
10 | | // See the symcrypt.h file for documentation on what the various functions do. |
11 | | // |
12 | | |
13 | | |
14 | | // Maximum size of the domain separator prefix used in PRFs |
15 | | #define SYMCRYPT_XMSS_MAX_PREFIX_SIZE SYMCRYPT_HASH_MAX_RESULT_SIZE |
16 | | |
17 | | // PRF domain separators |
18 | 0 | #define SYMCRYPT_XMSS_F 0x00 |
19 | 0 | #define SYMCRYPT_XMSS_H 0x01 |
20 | 0 | #define SYMCRYPT_XMSS_H_MSG 0x02 |
21 | 0 | #define SYMCRYPT_XMSS_PRF 0x03 |
22 | 0 | #define SYMCRYPT_XMSS_PRF_KEYGEN 0x04 |
23 | | |
24 | | |
25 | | static const PCSYMCRYPT_HASH* XmssHashArray[] = { |
26 | | &SymCryptSha256Algorithm, // 0 |
27 | | &SymCryptSha512Algorithm, // 1 |
28 | | &SymCryptShake128HashAlgorithm, // 2 |
29 | | &SymCryptShake256HashAlgorithm, // 3 |
30 | | }; |
31 | | |
32 | | |
33 | | typedef enum _SYMCRYPT_XMSS_WOTSP_ALGID |
34 | | { |
35 | | // Hash Fn. RFC-8391 SP800-208 |
36 | | SYMCRYPT_XMSS_WOTSP_SHA2_256 = 0x00000001, // SHA-256 X X |
37 | | SYMCRYPT_XMSS_WOTSP_SHA2_512 = 0x00000002, // SHA-512 X |
38 | | SYMCRYPT_XMSS_WOTSP_SHAKE_256 = 0x00000003, // SHAKE128 X |
39 | | SYMCRYPT_XMSS_WOTSP_SHAKE_512 = 0x00000004, // SHAKE256 X |
40 | | SYMCRYPT_XMSS_WOTSP_SHA2_192 = 0x00000005, // SHA-256 X |
41 | | SYMCRYPT_XMSS_WOTSP_SHAKE256_256 = 0x00000006, // SHAKE256 X |
42 | | SYMCRYPT_XMSS_WOTSP_SHAKE256_192 = 0x00000007, // SHAKE256 X |
43 | | |
44 | | } SYMCRYPT_XMSS_WOTSP_ALGID, *PSYMCRYPT_XMSS_WOTSP_ALGID; |
45 | | |
46 | | |
47 | | typedef struct _SYMCRYPT_XMSS_WOTSP_PARAMS |
48 | | { |
49 | | SYMCRYPT_XMSS_WOTSP_ALGID wotspId; |
50 | | UINT8 hashIndex; |
51 | | UINT8 n; |
52 | | UINT8 w; |
53 | | UINT8 cbPrefix; |
54 | | |
55 | | } SYMCRYPT_XMSS_WOTSP_PARAMS, *PSYMCRYPT_XMSS_WOTSP_PARAMS; |
56 | | |
57 | | |
58 | | static const SYMCRYPT_XMSS_WOTSP_PARAMS XmssWotspParams[] = |
59 | | { |
60 | | // wotspId hashIndex n w cbPrefix |
61 | | { SYMCRYPT_XMSS_WOTSP_SHA2_256, 0, 32, 4, 32 }, // SHA-256 |
62 | | { SYMCRYPT_XMSS_WOTSP_SHA2_512, 1, 64, 4, 64 }, // SHA-512 |
63 | | { SYMCRYPT_XMSS_WOTSP_SHAKE_256, 2, 32, 4, 32 }, // SHAKE128 |
64 | | { SYMCRYPT_XMSS_WOTSP_SHAKE_512, 3, 64, 4, 64 }, // SHAKE256 |
65 | | { SYMCRYPT_XMSS_WOTSP_SHA2_192, 0, 24, 4, 4 }, // SHA-256 |
66 | | { SYMCRYPT_XMSS_WOTSP_SHAKE256_256, 3, 32, 4, 32 }, // SHAKE256 |
67 | | { SYMCRYPT_XMSS_WOTSP_SHAKE256_192, 3, 24, 4, 4 }, // SHAKE256 |
68 | | }; |
69 | | |
70 | | typedef struct _SYMCRYPT_XMSS_PARAMETER_PREDEFINED |
71 | | { |
72 | | UINT32 idAlg; |
73 | | |
74 | | SYMCRYPT_XMSS_WOTSP_ALGID idWotsp; |
75 | | |
76 | | // total tree height (each level has height h/d) |
77 | | UINT8 h; |
78 | | |
79 | | // number of layers (for single tree, d=1) |
80 | | UINT8 d; |
81 | | |
82 | | } SYMCRYPT_XMSS_PARAMETER_PREDEFINED; |
83 | | |
84 | | typedef SYMCRYPT_XMSS_PARAMETER_PREDEFINED* PSYMCRYPT_XMSS_PARAMETER_PREDEFINED; |
85 | | typedef const SYMCRYPT_XMSS_PARAMETER_PREDEFINED* PCSYMCRYPT_XMSS_PARAMETER_PREDEFINED; |
86 | | |
87 | | |
88 | | static const SYMCRYPT_XMSS_PARAMETER_PREDEFINED XmssParametersPredefined[] = { |
89 | | |
90 | | // algId wotspId/wotspIndex h d |
91 | | { SYMCRYPT_XMSS_SHA2_10_256, SYMCRYPT_XMSS_WOTSP_SHA2_256, 10, 1 }, |
92 | | { SYMCRYPT_XMSS_SHA2_16_256, SYMCRYPT_XMSS_WOTSP_SHA2_256, 16, 1 }, |
93 | | { SYMCRYPT_XMSS_SHA2_20_256, SYMCRYPT_XMSS_WOTSP_SHA2_256, 20, 1 }, |
94 | | { SYMCRYPT_XMSS_SHA2_10_512, SYMCRYPT_XMSS_WOTSP_SHA2_512, 10, 1 }, |
95 | | { SYMCRYPT_XMSS_SHA2_16_512, SYMCRYPT_XMSS_WOTSP_SHA2_512, 16, 1 }, |
96 | | { SYMCRYPT_XMSS_SHA2_20_512, SYMCRYPT_XMSS_WOTSP_SHA2_512, 20, 1 }, |
97 | | { SYMCRYPT_XMSS_SHAKE_10_256, SYMCRYPT_XMSS_WOTSP_SHAKE_256, 10, 1 }, |
98 | | { SYMCRYPT_XMSS_SHAKE_16_256, SYMCRYPT_XMSS_WOTSP_SHAKE_256, 16, 1 }, |
99 | | { SYMCRYPT_XMSS_SHAKE_20_256, SYMCRYPT_XMSS_WOTSP_SHAKE_256, 20, 1 }, |
100 | | { SYMCRYPT_XMSS_SHAKE_10_512, SYMCRYPT_XMSS_WOTSP_SHAKE_512, 10, 1 }, |
101 | | { SYMCRYPT_XMSS_SHAKE_16_512, SYMCRYPT_XMSS_WOTSP_SHAKE_512, 16, 1 }, |
102 | | { SYMCRYPT_XMSS_SHAKE_20_512, SYMCRYPT_XMSS_WOTSP_SHAKE_512, 20, 1 }, |
103 | | { SYMCRYPT_XMSS_SHA2_10_192, SYMCRYPT_XMSS_WOTSP_SHA2_192, 10, 1 }, |
104 | | { SYMCRYPT_XMSS_SHA2_16_192, SYMCRYPT_XMSS_WOTSP_SHA2_192, 16, 1 }, |
105 | | { SYMCRYPT_XMSS_SHA2_20_192, SYMCRYPT_XMSS_WOTSP_SHA2_192, 20, 1 }, |
106 | | { SYMCRYPT_XMSS_SHAKE256_10_256, SYMCRYPT_XMSS_WOTSP_SHAKE256_256, 10, 1 }, |
107 | | { SYMCRYPT_XMSS_SHAKE256_16_256, SYMCRYPT_XMSS_WOTSP_SHAKE256_256, 16, 1 }, |
108 | | { SYMCRYPT_XMSS_SHAKE256_20_256, SYMCRYPT_XMSS_WOTSP_SHAKE256_256, 20, 1 }, |
109 | | { SYMCRYPT_XMSS_SHAKE256_10_192, SYMCRYPT_XMSS_WOTSP_SHAKE256_192, 10, 1 }, |
110 | | { SYMCRYPT_XMSS_SHAKE256_16_192, SYMCRYPT_XMSS_WOTSP_SHAKE256_192, 16, 1 }, |
111 | | { SYMCRYPT_XMSS_SHAKE256_20_192, SYMCRYPT_XMSS_WOTSP_SHAKE256_192, 20, 1 }, |
112 | | }; |
113 | | |
114 | | |
115 | | static const SYMCRYPT_XMSS_PARAMETER_PREDEFINED XmssMtParametersPredefined[] = { |
116 | | |
117 | | // algId wotspId/wotspIndex h d |
118 | | { SYMCRYPT_XMSSMT_SHA2_20_2_256, SYMCRYPT_XMSS_WOTSP_SHA2_256, 20, 2 }, |
119 | | { SYMCRYPT_XMSSMT_SHA2_20_4_256, SYMCRYPT_XMSS_WOTSP_SHA2_256, 20, 4 }, |
120 | | { SYMCRYPT_XMSSMT_SHA2_40_2_256, SYMCRYPT_XMSS_WOTSP_SHA2_256, 40, 2 }, |
121 | | { SYMCRYPT_XMSSMT_SHA2_40_4_256, SYMCRYPT_XMSS_WOTSP_SHA2_256, 40, 4 }, |
122 | | { SYMCRYPT_XMSSMT_SHA2_40_8_256, SYMCRYPT_XMSS_WOTSP_SHA2_256, 40, 8 }, |
123 | | { SYMCRYPT_XMSSMT_SHA2_60_3_256, SYMCRYPT_XMSS_WOTSP_SHA2_256, 60, 3 }, |
124 | | { SYMCRYPT_XMSSMT_SHA2_60_6_256, SYMCRYPT_XMSS_WOTSP_SHA2_256, 60, 6 }, |
125 | | { SYMCRYPT_XMSSMT_SHA2_60_12_256, SYMCRYPT_XMSS_WOTSP_SHA2_256, 60, 12 }, |
126 | | |
127 | | { SYMCRYPT_XMSSMT_SHA2_20_2_512, SYMCRYPT_XMSS_WOTSP_SHA2_512, 20, 2 }, |
128 | | { SYMCRYPT_XMSSMT_SHA2_20_4_512, SYMCRYPT_XMSS_WOTSP_SHA2_512, 20, 4 }, |
129 | | { SYMCRYPT_XMSSMT_SHA2_40_2_512, SYMCRYPT_XMSS_WOTSP_SHA2_512, 40, 2 }, |
130 | | { SYMCRYPT_XMSSMT_SHA2_40_4_512, SYMCRYPT_XMSS_WOTSP_SHA2_512, 40, 4 }, |
131 | | { SYMCRYPT_XMSSMT_SHA2_40_8_512, SYMCRYPT_XMSS_WOTSP_SHA2_512, 40, 8 }, |
132 | | { SYMCRYPT_XMSSMT_SHA2_60_3_512, SYMCRYPT_XMSS_WOTSP_SHA2_512, 60, 3 }, |
133 | | { SYMCRYPT_XMSSMT_SHA2_60_6_512, SYMCRYPT_XMSS_WOTSP_SHA2_512, 60, 6 }, |
134 | | { SYMCRYPT_XMSSMT_SHA2_60_12_512, SYMCRYPT_XMSS_WOTSP_SHA2_512, 60, 12 }, |
135 | | |
136 | | { SYMCRYPT_XMSSMT_SHAKE_20_2_256, SYMCRYPT_XMSS_WOTSP_SHAKE_256, 20, 2 }, |
137 | | { SYMCRYPT_XMSSMT_SHAKE_20_4_256, SYMCRYPT_XMSS_WOTSP_SHAKE_256, 20, 4 }, |
138 | | { SYMCRYPT_XMSSMT_SHAKE_40_2_256, SYMCRYPT_XMSS_WOTSP_SHAKE_256, 40, 2 }, |
139 | | { SYMCRYPT_XMSSMT_SHAKE_40_4_256, SYMCRYPT_XMSS_WOTSP_SHAKE_256, 40, 4 }, |
140 | | { SYMCRYPT_XMSSMT_SHAKE_40_8_256, SYMCRYPT_XMSS_WOTSP_SHAKE_256, 40, 8 }, |
141 | | { SYMCRYPT_XMSSMT_SHAKE_60_3_256, SYMCRYPT_XMSS_WOTSP_SHAKE_256, 60, 3 }, |
142 | | { SYMCRYPT_XMSSMT_SHAKE_60_6_256, SYMCRYPT_XMSS_WOTSP_SHAKE_256, 60, 6 }, |
143 | | { SYMCRYPT_XMSSMT_SHAKE_60_12_256, SYMCRYPT_XMSS_WOTSP_SHAKE_256, 60, 12 }, |
144 | | |
145 | | { SYMCRYPT_XMSSMT_SHAKE_20_2_512, SYMCRYPT_XMSS_WOTSP_SHAKE_512, 20, 2 }, |
146 | | { SYMCRYPT_XMSSMT_SHAKE_20_4_512, SYMCRYPT_XMSS_WOTSP_SHAKE_512, 20, 4 }, |
147 | | { SYMCRYPT_XMSSMT_SHAKE_40_2_512, SYMCRYPT_XMSS_WOTSP_SHAKE_512, 40, 2 }, |
148 | | { SYMCRYPT_XMSSMT_SHAKE_40_4_512, SYMCRYPT_XMSS_WOTSP_SHAKE_512, 40, 4 }, |
149 | | { SYMCRYPT_XMSSMT_SHAKE_40_8_512, SYMCRYPT_XMSS_WOTSP_SHAKE_512, 40, 8 }, |
150 | | { SYMCRYPT_XMSSMT_SHAKE_60_3_512, SYMCRYPT_XMSS_WOTSP_SHAKE_512, 60, 3 }, |
151 | | { SYMCRYPT_XMSSMT_SHAKE_60_6_512, SYMCRYPT_XMSS_WOTSP_SHAKE_512, 60, 6 }, |
152 | | { SYMCRYPT_XMSSMT_SHAKE_60_12_512, SYMCRYPT_XMSS_WOTSP_SHAKE_512, 60, 12 }, |
153 | | |
154 | | { SYMCRYPT_XMSSMT_SHA2_20_2_192, SYMCRYPT_XMSS_WOTSP_SHA2_192, 20, 2 }, |
155 | | { SYMCRYPT_XMSSMT_SHA2_20_4_192, SYMCRYPT_XMSS_WOTSP_SHA2_192, 20, 4 }, |
156 | | { SYMCRYPT_XMSSMT_SHA2_40_2_192, SYMCRYPT_XMSS_WOTSP_SHA2_192, 40, 2 }, |
157 | | { SYMCRYPT_XMSSMT_SHA2_40_4_192, SYMCRYPT_XMSS_WOTSP_SHA2_192, 40, 4 }, |
158 | | { SYMCRYPT_XMSSMT_SHA2_40_8_192, SYMCRYPT_XMSS_WOTSP_SHA2_192, 40, 8 }, |
159 | | { SYMCRYPT_XMSSMT_SHA2_60_3_192, SYMCRYPT_XMSS_WOTSP_SHA2_192, 60, 3 }, |
160 | | { SYMCRYPT_XMSSMT_SHA2_60_6_192, SYMCRYPT_XMSS_WOTSP_SHA2_192, 60, 6 }, |
161 | | { SYMCRYPT_XMSSMT_SHA2_60_12_192, SYMCRYPT_XMSS_WOTSP_SHA2_192, 60, 12 }, |
162 | | |
163 | | { SYMCRYPT_XMSSMT_SHAKE256_20_2_256, SYMCRYPT_XMSS_WOTSP_SHAKE256_256, 20, 2 }, |
164 | | { SYMCRYPT_XMSSMT_SHAKE256_20_4_256, SYMCRYPT_XMSS_WOTSP_SHAKE256_256, 20, 4 }, |
165 | | { SYMCRYPT_XMSSMT_SHAKE256_40_2_256, SYMCRYPT_XMSS_WOTSP_SHAKE256_256, 40, 2 }, |
166 | | { SYMCRYPT_XMSSMT_SHAKE256_40_4_256, SYMCRYPT_XMSS_WOTSP_SHAKE256_256, 40, 4 }, |
167 | | { SYMCRYPT_XMSSMT_SHAKE256_40_8_256, SYMCRYPT_XMSS_WOTSP_SHAKE256_256, 40, 8 }, |
168 | | { SYMCRYPT_XMSSMT_SHAKE256_60_3_256, SYMCRYPT_XMSS_WOTSP_SHAKE256_256, 60, 3 }, |
169 | | { SYMCRYPT_XMSSMT_SHAKE256_60_6_256, SYMCRYPT_XMSS_WOTSP_SHAKE256_256, 60, 6 }, |
170 | | { SYMCRYPT_XMSSMT_SHAKE256_60_12_256, SYMCRYPT_XMSS_WOTSP_SHAKE256_256, 60, 12 }, |
171 | | |
172 | | { SYMCRYPT_XMSSMT_SHAKE256_20_2_192, SYMCRYPT_XMSS_WOTSP_SHAKE256_192, 20, 2 }, |
173 | | { SYMCRYPT_XMSSMT_SHAKE256_20_4_192, SYMCRYPT_XMSS_WOTSP_SHAKE256_192, 20, 4 }, |
174 | | { SYMCRYPT_XMSSMT_SHAKE256_40_2_192, SYMCRYPT_XMSS_WOTSP_SHAKE256_192, 40, 2 }, |
175 | | { SYMCRYPT_XMSSMT_SHAKE256_40_4_192, SYMCRYPT_XMSS_WOTSP_SHAKE256_192, 40, 4 }, |
176 | | { SYMCRYPT_XMSSMT_SHAKE256_40_8_192, SYMCRYPT_XMSS_WOTSP_SHAKE256_192, 40, 8 }, |
177 | | { SYMCRYPT_XMSSMT_SHAKE256_60_3_192, SYMCRYPT_XMSS_WOTSP_SHAKE256_192, 60, 3 }, |
178 | | { SYMCRYPT_XMSSMT_SHAKE256_60_6_192, SYMCRYPT_XMSS_WOTSP_SHAKE256_192, 60, 6 }, |
179 | | { SYMCRYPT_XMSSMT_SHAKE256_60_12_192, SYMCRYPT_XMSS_WOTSP_SHAKE256_192, 60, 12 }, |
180 | | }; |
181 | | |
182 | | // |
183 | | // Compute the number of chains for an n-byte input and its checksum |
184 | | // for Winternitz parameter w (i.e., using w-bit blocks) in an OTS scheme |
185 | | // |
186 | | VOID |
187 | | SYMCRYPT_CALL |
188 | | SymCryptHbsGetWinternitzLengths( |
189 | | UINT32 n, |
190 | | UINT32 w, |
191 | | _Out_ PUINT32 puLen1, |
192 | | _Out_ PUINT32 puLen2 |
193 | | ) |
194 | 0 | { |
195 | 0 | UINT32 len1; |
196 | 0 | UINT32 len2; |
197 | 0 | UINT32 maxChecksum; |
198 | 0 | ULONG msb; |
199 | |
|
200 | 0 | SYMCRYPT_ASSERT(n > 0); |
201 | 0 | SYMCRYPT_ASSERT(w >= 1 && w <= 8); |
202 | | |
203 | | // number of w-bit digits in an n-byte input |
204 | 0 | len1 = (8 * n + (w - 1)) / w; |
205 | | |
206 | | // maximum value the checksum can take (each w-bit digit can have value at most 2^w-1) |
207 | 0 | maxChecksum = len1 * ((1 << w) - 1); |
208 | |
|
209 | 0 | msb = 31 - SymCryptCountLeadingZeros32(maxChecksum); |
210 | | |
211 | | // msb + 1 bits are required to store the maxChecksum, |
212 | | // calculate the number of w-bit blocks to represent that |
213 | 0 | len2 = (msb + 1 + (w - 1)) / w; |
214 | |
|
215 | 0 | *puLen1 = len1; |
216 | 0 | *puLen2 = len2; |
217 | 0 | } |
218 | | |
219 | | SYMCRYPT_ERROR |
220 | | SYMCRYPT_CALL |
221 | | SymCryptXmssGetWotspParams( |
222 | | SYMCRYPT_XMSS_WOTSP_ALGID id, |
223 | | _Out_ PSYMCRYPT_XMSS_PARAMS pParams ) |
224 | 0 | { |
225 | 0 | SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; |
226 | |
|
227 | 0 | for (UINT32 i = 0; i < SYMCRYPT_ARRAY_SIZE(XmssWotspParams); i++) |
228 | 0 | { |
229 | 0 | if (XmssWotspParams[i].wotspId == id) |
230 | 0 | { |
231 | 0 | SYMCRYPT_ASSERT(XmssWotspParams[i].hashIndex < SYMCRYPT_ARRAY_SIZE(XmssHashArray)); |
232 | 0 | pParams->hash = *XmssHashArray[XmssWotspParams[i].hashIndex]; |
233 | 0 | pParams->cbHashOutput = XmssWotspParams[i].n; |
234 | 0 | pParams->nWinternitzWidth = XmssWotspParams[i].w; |
235 | 0 | pParams->cbPrefix = XmssWotspParams[i].cbPrefix; |
236 | 0 | goto cleanup; |
237 | 0 | } |
238 | 0 | } |
239 | | |
240 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
241 | |
|
242 | 0 | cleanup: |
243 | |
|
244 | 0 | return scError; |
245 | 0 | } |
246 | | |
247 | | // |
248 | | // Derive XMSS parameters that can be computed from others |
249 | | // |
250 | | // SYMCRYPT_XMSS_PARAMS structure must be initialized with either predefined |
251 | | // or user defined parameters before this function is called. |
252 | | // |
253 | | VOID |
254 | | SYMCRYPT_CALL |
255 | | SymCryptXmssDeriveParams( |
256 | | _Inout_ PSYMCRYPT_XMSS_PARAMS pParams ) |
257 | 0 | { |
258 | 0 | SymCryptHbsGetWinternitzLengths( |
259 | 0 | pParams->cbHashOutput, |
260 | 0 | pParams->nWinternitzWidth, |
261 | 0 | &pParams->len1, |
262 | 0 | &pParams->len2); |
263 | |
|
264 | 0 | pParams->len = pParams->len1 + pParams->len2; |
265 | |
|
266 | 0 | UINT32 nChecksumBits = pParams->len2 * pParams->nWinternitzWidth; |
267 | 0 | SYMCRYPT_ASSERT(nChecksumBits <= 32); |
268 | 0 | pParams->nLeftShift32 = (UINT8)(32 - nChecksumBits); |
269 | |
|
270 | 0 | if (pParams->nLayers == 1) |
271 | 0 | { |
272 | | // single trees have a 32-bit Idx value |
273 | 0 | pParams->cbIdx = 4; |
274 | 0 | } |
275 | 0 | else |
276 | 0 | { |
277 | | // number of bytes to store h-bits for Idx |
278 | 0 | pParams->cbIdx = (pParams->nTotalTreeHeight + 7) / 8; |
279 | 0 | } |
280 | |
|
281 | 0 | pParams->nLayerHeight = pParams->nTotalTreeHeight / pParams->nLayers; |
282 | 0 | } |
283 | | |
284 | | |
285 | | // |
286 | | // Fill a SYMCRYPT_XMSS_PARAMS structure from either an XMSS algorithm ID or |
287 | | // XMSS^MT algorithm ID from predefined parameter sets. |
288 | | // |
289 | | SYMCRYPT_ERROR |
290 | | SYMCRYPT_CALL |
291 | | SymCryptXmssParamsFromAlgIdCommon( |
292 | | UINT32 id, |
293 | | BOOLEAN isMultiTree, |
294 | | _Out_ PSYMCRYPT_XMSS_PARAMS pParams ) |
295 | 0 | { |
296 | 0 | SYMCRYPT_ERROR scError = SYMCRYPT_INVALID_ARGUMENT; |
297 | 0 | PCSYMCRYPT_XMSS_PARAMETER_PREDEFINED pParameters = NULL; |
298 | 0 | SIZE_T uParameterCount; |
299 | |
|
300 | 0 | SymCryptWipeKnownSize(pParams, sizeof(*pParams)); |
301 | |
|
302 | 0 | if (isMultiTree) |
303 | 0 | { |
304 | 0 | pParameters = XmssMtParametersPredefined; |
305 | 0 | uParameterCount = SYMCRYPT_ARRAY_SIZE(XmssMtParametersPredefined); |
306 | 0 | } |
307 | 0 | else |
308 | 0 | { |
309 | 0 | pParameters = XmssParametersPredefined; |
310 | 0 | uParameterCount = SYMCRYPT_ARRAY_SIZE(XmssParametersPredefined); |
311 | 0 | } |
312 | |
|
313 | 0 | for (UINT32 i = 0; i < uParameterCount; i++) |
314 | 0 | { |
315 | 0 | if (pParameters[i].idAlg == id) |
316 | 0 | { |
317 | 0 | scError = SymCryptXmssGetWotspParams(pParameters[i].idWotsp, pParams); |
318 | |
|
319 | 0 | if (scError == SYMCRYPT_NO_ERROR) |
320 | 0 | { |
321 | 0 | SYMCRYPT_ASSERT(pParams->cbHashOutput <= SYMCRYPT_HASH_MAX_RESULT_SIZE); |
322 | |
|
323 | 0 | pParams->id = id; |
324 | 0 | pParams->nTotalTreeHeight = pParameters[i].h; |
325 | 0 | pParams->nLayers = pParameters[i].d; |
326 | 0 | SymCryptXmssDeriveParams(pParams); |
327 | 0 | } |
328 | |
|
329 | 0 | break; |
330 | 0 | } |
331 | 0 | } |
332 | |
|
333 | 0 | return scError; |
334 | 0 | } |
335 | | |
336 | | |
337 | | SYMCRYPT_ERROR |
338 | | SYMCRYPT_CALL |
339 | | SymCryptXmssParamsFromAlgId( |
340 | | SYMCRYPT_XMSS_ALGID id, |
341 | | _Out_ PSYMCRYPT_XMSS_PARAMS pParams ) |
342 | 0 | { |
343 | 0 | return SymCryptXmssParamsFromAlgIdCommon(id, FALSE, pParams); |
344 | 0 | } |
345 | | |
346 | | |
347 | | SYMCRYPT_ERROR |
348 | | SYMCRYPT_CALL |
349 | | SymCryptXmssMtParamsFromAlgId( |
350 | | SYMCRYPT_XMSSMT_ALGID id, |
351 | | _Out_ PSYMCRYPT_XMSS_PARAMS pParams) |
352 | 0 | { |
353 | 0 | return SymCryptXmssParamsFromAlgIdCommon(id, TRUE, pParams); |
354 | 0 | } |
355 | | |
356 | | |
357 | | // |
358 | | // Set custom XMSS/XMSS^MT parameters |
359 | | // |
360 | | // This function can be used to initialize SYMCRYPT_XMSS_PARAMS with |
361 | | // custom parameters that are not defined by the standards. |
362 | | // |
363 | | SYMCRYPT_ERROR |
364 | | SYMCRYPT_CALL |
365 | | SymCryptXmssSetParams( |
366 | | _Out_ PSYMCRYPT_XMSS_PARAMS pParams, |
367 | | UINT32 id, |
368 | | _In_ PCSYMCRYPT_HASH pHash, // hash algorithm |
369 | | UINT32 cbHashOutput, // hash output size |
370 | | UINT32 nWinternitzWidth, // Winternitz parameter |
371 | | UINT32 nTotalTreeHeight, // total tree height |
372 | | UINT32 nLayers, // number of layers |
373 | | UINT32 cbPrefix // domain separater prefix length |
374 | | ) |
375 | 0 | { |
376 | 0 | SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; |
377 | |
|
378 | 0 | if (pParams == NULL) |
379 | 0 | { |
380 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
381 | 0 | goto cleanup; |
382 | 0 | } |
383 | | |
384 | 0 | SymCryptWipeKnownSize(pParams, sizeof(*pParams)); |
385 | |
|
386 | 0 | if (pHash == NULL) |
387 | 0 | { |
388 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
389 | 0 | goto cleanup; |
390 | 0 | } |
391 | | |
392 | | // Output size n can at most be equal to the hash output size |
393 | 0 | if (cbHashOutput == 0 || |
394 | 0 | cbHashOutput > pHash->resultSize || |
395 | 0 | cbHashOutput > SYMCRYPT_HASH_MAX_RESULT_SIZE) |
396 | 0 | { |
397 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
398 | 0 | goto cleanup; |
399 | 0 | } |
400 | | |
401 | | // Winternitz parameter must be one of 1, 2, 4, or 8 |
402 | 0 | if (nWinternitzWidth == 0 || |
403 | 0 | nWinternitzWidth > 8 || |
404 | 0 | (nWinternitzWidth & (nWinternitzWidth - 1)) != 0) |
405 | 0 | { |
406 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
407 | 0 | goto cleanup; |
408 | 0 | } |
409 | | |
410 | | // nTotalTreeHeight and nLayers must both be positive and |
411 | | // nLayers must divide nTotalTreeHeight |
412 | 0 | if (nTotalTreeHeight == 0 || |
413 | 0 | nLayers == 0 || |
414 | 0 | (nTotalTreeHeight % nLayers) != 0) |
415 | 0 | { |
416 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
417 | 0 | goto cleanup; |
418 | 0 | } |
419 | | |
420 | | // Layer height (tree height of one layer) can be at most 32 |
421 | 0 | if ((nTotalTreeHeight / nLayers) > 32) |
422 | 0 | { |
423 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
424 | 0 | goto cleanup; |
425 | 0 | } |
426 | | |
427 | | // Total tree height can be at most 63 |
428 | 0 | if (nTotalTreeHeight > 63) |
429 | 0 | { |
430 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
431 | 0 | goto cleanup; |
432 | 0 | } |
433 | | |
434 | 0 | if (cbPrefix == 0) |
435 | 0 | { |
436 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
437 | 0 | goto cleanup; |
438 | 0 | } |
439 | | |
440 | 0 | pParams->id = id; |
441 | 0 | pParams->hash = pHash; |
442 | 0 | pParams->cbHashOutput = cbHashOutput; |
443 | 0 | pParams->nWinternitzWidth = nWinternitzWidth; |
444 | 0 | pParams->nTotalTreeHeight = nTotalTreeHeight; |
445 | 0 | pParams->nLayers = nLayers; |
446 | 0 | SymCryptXmssDeriveParams(pParams); |
447 | |
|
448 | 0 | pParams->cbPrefix = cbPrefix; |
449 | |
|
450 | 0 | cleanup: |
451 | |
|
452 | 0 | return scError; |
453 | 0 | } |
454 | | |
455 | | |
456 | | // |
457 | | // Updates the type field in ADRS structure and clears the |
458 | | // subsequent fields. |
459 | | // |
460 | | // Does not modify the first two fields (Layer and Tree) of |
461 | | // the ADRS structure. |
462 | | // |
463 | | VOID |
464 | | SYMCRYPT_CALL |
465 | | SymCryptXmssSetAdrsType( |
466 | | _Out_ PXMSS_ADRS adrs, |
467 | | UINT32 type ) |
468 | 0 | { |
469 | 0 | SYMCRYPT_STORE_MSBFIRST32(adrs->en32Type, type); |
470 | 0 | SymCryptWipeKnownSize(&adrs->u, sizeof(adrs->u)); |
471 | 0 | SYMCRYPT_STORE_MSBFIRST32(adrs->en32KeyAndMask, 0); |
472 | 0 | } |
473 | | |
474 | | |
475 | | SIZE_T |
476 | | SYMCRYPT_CALL |
477 | | SymCryptXmssSizeofSignatureFromParams( |
478 | | _In_ PCSYMCRYPT_XMSS_PARAMS pParams ) |
479 | 0 | { |
480 | 0 | SYMCRYPT_ASSERT(pParams->nLayers != 0); |
481 | 0 | SYMCRYPT_ASSERT((pParams->nTotalTreeHeight % pParams->nLayers) == 0); |
482 | 0 | SYMCRYPT_ASSERT(pParams->nLayerHeight > 0); |
483 | |
|
484 | 0 | SIZE_T size = 0; |
485 | 0 | size += pParams->cbIdx; // idx |
486 | 0 | size += pParams->cbHashOutput; // randomness |
487 | | |
488 | | // WOTSP signature + authentication path for each layer |
489 | 0 | size += pParams->nLayers * ( pParams->cbHashOutput * (pParams->len + pParams->nLayerHeight) ); |
490 | |
|
491 | 0 | return size; |
492 | 0 | } |
493 | | |
494 | | |
495 | | SYMCRYPT_ERROR |
496 | | SYMCRYPT_CALL |
497 | | SymCryptXmssSizeofKeyBlobFromParams( |
498 | | _In_ PCSYMCRYPT_XMSS_PARAMS pParams, |
499 | | SYMCRYPT_XMSSKEY_TYPE keyType, |
500 | | _Out_ SIZE_T* pcbKey ) |
501 | 0 | { |
502 | 0 | SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; |
503 | 0 | SIZE_T cbPublicKey = 0; |
504 | 0 | SIZE_T cbPrivateKey = 0; |
505 | | |
506 | | // Public Key |
507 | 0 | cbPublicKey += sizeof(UINT32); // Alg ID |
508 | 0 | cbPublicKey += 2 * pParams->cbHashOutput; // Root and Seed |
509 | | |
510 | | // Private Key (on top of the public key) |
511 | 0 | cbPrivateKey = cbPublicKey; |
512 | 0 | cbPrivateKey += sizeof(UINT64); // Idx |
513 | 0 | cbPrivateKey += 2 * pParams->cbHashOutput; // SK_XMSS and SK_PRF |
514 | |
|
515 | 0 | switch (keyType) |
516 | 0 | { |
517 | 0 | case SYMCRYPT_XMSSKEY_TYPE_PUBLIC: |
518 | 0 | *pcbKey = cbPublicKey; |
519 | 0 | break; |
520 | | |
521 | 0 | case SYMCRYPT_XMSSKEY_TYPE_PRIVATE: |
522 | 0 | *pcbKey = cbPrivateKey; |
523 | 0 | break; |
524 | | |
525 | 0 | default: |
526 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
527 | 0 | break; |
528 | 0 | } |
529 | | |
530 | 0 | return scError; |
531 | 0 | } |
532 | | |
533 | | PSYMCRYPT_XMSS_KEY |
534 | | SYMCRYPT_CALL |
535 | | SymCryptXmsskeyAllocate( |
536 | | _In_ PCSYMCRYPT_XMSS_PARAMS pParams, |
537 | | UINT32 flags ) |
538 | 0 | { |
539 | 0 | PSYMCRYPT_XMSS_KEY pKey = NULL; |
540 | | |
541 | | // No flags allowed |
542 | 0 | if (flags != 0) |
543 | 0 | { |
544 | 0 | goto cleanup; |
545 | 0 | } |
546 | | |
547 | 0 | SIZE_T cbSize = sizeof(SYMCRYPT_XMSS_KEY); |
548 | |
|
549 | 0 | pKey = SymCryptCallbackAlloc(cbSize); |
550 | |
|
551 | 0 | if (pKey == NULL) |
552 | 0 | { |
553 | 0 | goto cleanup; |
554 | 0 | } |
555 | | |
556 | 0 | SymCryptWipe(pKey, cbSize); |
557 | 0 | pKey->version = 1; |
558 | 0 | pKey->keyType = SYMCRYPT_XMSSKEY_TYPE_NONE; |
559 | 0 | pKey->params = *pParams; |
560 | |
|
561 | 0 | SYMCRYPT_SET_MAGIC(pKey); |
562 | |
|
563 | 0 | cleanup: |
564 | |
|
565 | 0 | return pKey; |
566 | 0 | } |
567 | | |
568 | | |
569 | | VOID |
570 | | SYMCRYPT_CALL |
571 | | SymCryptXmsskeyFree( |
572 | | _Inout_ PSYMCRYPT_XMSS_KEY pKey ) |
573 | 0 | { |
574 | 0 | SYMCRYPT_CHECK_MAGIC(pKey); |
575 | 0 | SymCryptWipeKnownSize(pKey, sizeof(*pKey)); |
576 | 0 | SymCryptCallbackFree(pKey); |
577 | 0 | } |
578 | | |
579 | | |
580 | | PSYMCRYPT_INCREMENTAL_TREEHASH |
581 | | SYMCRYPT_CALL |
582 | | SymCryptHbsIncrementalTreehashInit( |
583 | | UINT32 nLeaves, |
584 | | PBYTE pbBuffer, |
585 | | SIZE_T cbBuffer, |
586 | | UINT32 cbHashResult, |
587 | | PSYMCRYPT_INCREMENTAL_TREEHASH_FUNC funcCompressNodes, |
588 | | PSYMCRYPT_XMSS_INCREMENTAL_TREEHASH_CONTEXT pContext ) |
589 | 0 | { |
590 | 0 | UNREFERENCED_PARAMETER(cbBuffer); |
591 | |
|
592 | 0 | SYMCRYPT_ASSERT(cbBuffer >= SymCryptHbsSizeofScratchBytesForIncrementalTreehash(cbHashResult, nLeaves)); |
593 | |
|
594 | 0 | PSYMCRYPT_INCREMENTAL_TREEHASH pIncHash = (PSYMCRYPT_INCREMENTAL_TREEHASH)pbBuffer; |
595 | |
|
596 | 0 | pIncHash->cbNode = 2 * sizeof(UINT32) + cbHashResult; |
597 | 0 | pIncHash->nSize = 0; |
598 | 0 | pIncHash->nCapacity = SymCryptHbsIncrementalTreehashStackDepth(nLeaves); |
599 | 0 | pIncHash->nLastLeafIndex = 0; |
600 | 0 | pIncHash->funcCompressNodes = funcCompressNodes; |
601 | 0 | pIncHash->pContext = pContext; |
602 | |
|
603 | 0 | return pIncHash; |
604 | 0 | } |
605 | | |
606 | | |
607 | | PSYMCRYPT_TREEHASH_NODE |
608 | | SYMCRYPT_CALL |
609 | | SymCryptHbsIncrementalTreehashGetNode( |
610 | | _In_ PSYMCRYPT_INCREMENTAL_TREEHASH pIncHash, |
611 | | SIZE_T index ) |
612 | 0 | { |
613 | 0 | PBYTE pNode = (PBYTE)pIncHash->arrNodes; |
614 | |
|
615 | 0 | pNode += index * pIncHash->cbNode; |
616 | |
|
617 | 0 | return (PSYMCRYPT_TREEHASH_NODE)pNode; |
618 | 0 | } |
619 | | |
620 | | |
621 | | PSYMCRYPT_TREEHASH_NODE |
622 | | SYMCRYPT_CALL |
623 | | SymCryptHbsIncrementalTreehashAllocNode( |
624 | | _Inout_ PSYMCRYPT_INCREMENTAL_TREEHASH pIncHash, |
625 | | UINT32 nLeafIndex ) |
626 | 0 | { |
627 | 0 | SYMCRYPT_ASSERT(pIncHash->nSize < pIncHash->nCapacity); |
628 | |
|
629 | 0 | PSYMCRYPT_TREEHASH_NODE pNode = SymCryptHbsIncrementalTreehashGetNode(pIncHash, pIncHash->nSize); |
630 | |
|
631 | 0 | pNode->height = 0; |
632 | 0 | pNode->index = nLeafIndex; |
633 | |
|
634 | 0 | pIncHash->nSize++; |
635 | |
|
636 | 0 | return pNode; |
637 | 0 | } |
638 | | |
639 | | |
640 | | VOID |
641 | | SYMCRYPT_CALL |
642 | | SymCryptHbsIncrementalTreehashGetTopNodes( |
643 | | _Inout_ PSYMCRYPT_INCREMENTAL_TREEHASH pIncHash, |
644 | | _Out_ PSYMCRYPT_TREEHASH_NODE *ppNodeLeft, |
645 | | _Out_ PSYMCRYPT_TREEHASH_NODE *ppNodeRight ) |
646 | 0 | { |
647 | 0 | *ppNodeRight = (pIncHash->nSize < 1) ? NULL : SymCryptHbsIncrementalTreehashGetNode(pIncHash, pIncHash->nSize - 1); |
648 | |
|
649 | 0 | *ppNodeLeft = (pIncHash->nSize < 2) ? NULL : SymCryptHbsIncrementalTreehashGetNode(pIncHash, pIncHash->nSize - 2); |
650 | 0 | } |
651 | | |
652 | | |
653 | | PSYMCRYPT_TREEHASH_NODE |
654 | | SYMCRYPT_CALL |
655 | | SymCryptHbsIncrementalTreehashProcessCommon( |
656 | | _Inout_ PSYMCRYPT_INCREMENTAL_TREEHASH pIncHash, |
657 | | BOOLEAN fFinal ) |
658 | 0 | { |
659 | 0 | PSYMCRYPT_TREEHASH_NODE pNodeLeft = NULL; |
660 | 0 | PSYMCRYPT_TREEHASH_NODE pNodeRight = NULL; |
661 | |
|
662 | 0 | SYMCRYPT_ASSERT(pIncHash->nSize > 0); |
663 | |
|
664 | 0 | SymCryptHbsIncrementalTreehashGetTopNodes(pIncHash, &pNodeLeft, &pNodeRight); |
665 | |
|
666 | 0 | while ( pNodeLeft && |
667 | 0 | (fFinal || (pNodeLeft->height == pNodeRight->height)) ) |
668 | 0 | { |
669 | 0 | pIncHash->funcCompressNodes( |
670 | 0 | pNodeLeft, |
671 | 0 | pNodeRight, |
672 | 0 | pNodeLeft, |
673 | 0 | pIncHash->pContext); |
674 | |
|
675 | 0 | pIncHash->nSize--; |
676 | |
|
677 | 0 | SymCryptHbsIncrementalTreehashGetTopNodes(pIncHash, &pNodeLeft, &pNodeRight); |
678 | 0 | } |
679 | |
|
680 | 0 | return pNodeRight; |
681 | 0 | } |
682 | | |
683 | | |
684 | | PSYMCRYPT_TREEHASH_NODE |
685 | | SYMCRYPT_CALL |
686 | | SymCryptHbsIncrementalTreehashProcess( |
687 | | _Inout_ PSYMCRYPT_INCREMENTAL_TREEHASH pIncHash) |
688 | 0 | { |
689 | 0 | return SymCryptHbsIncrementalTreehashProcessCommon(pIncHash, FALSE); |
690 | 0 | } |
691 | | |
692 | | |
693 | | PSYMCRYPT_TREEHASH_NODE |
694 | | SYMCRYPT_CALL |
695 | | SymCryptHbsIncrementalTreehashFinalize( |
696 | | _Inout_ PSYMCRYPT_INCREMENTAL_TREEHASH pIncHash ) |
697 | 0 | { |
698 | 0 | return SymCryptHbsIncrementalTreehashProcessCommon(pIncHash, TRUE); |
699 | 0 | } |
700 | | |
701 | | |
702 | | UINT32 |
703 | | SYMCRYPT_CALL |
704 | | SymCryptHbsIncrementalTreehashStackDepth( |
705 | | UINT32 nLeaves) |
706 | 0 | { |
707 | 0 | ULONG h; |
708 | | |
709 | | // Minimum height binary tree that contains nLeaves many leaves is h+1 |
710 | 0 | h = 31 - SymCryptCountLeadingZeros32(nLeaves); |
711 | | |
712 | | // Tree root computation will require a stack of depth equal to tree height plus 1 |
713 | 0 | return (h + 2); |
714 | 0 | } |
715 | | |
716 | | |
717 | | SIZE_T |
718 | | SYMCRYPT_CALL |
719 | | SymCryptHbsSizeofScratchBytesForIncrementalTreehash( |
720 | | UINT32 cbNode, |
721 | | UINT32 nLeaves) |
722 | 0 | { |
723 | 0 | SIZE_T nodeSize = (cbNode + 2 * sizeof(UINT32)) + sizeof(SYMCRYPT_INCREMENTAL_TREEHASH); |
724 | |
|
725 | 0 | return nodeSize * SymCryptHbsIncrementalTreehashStackDepth(nLeaves); |
726 | 0 | } |
727 | | |
728 | | |
729 | | VOID |
730 | | SYMCRYPT_CALL |
731 | | SymCryptXmssPrfInit( |
732 | | _In_ PCSYMCRYPT_HASH hash, |
733 | | BYTE PrfType, |
734 | | SIZE_T prefixLength, |
735 | | _Out_ PSYMCRYPT_HASH_STATE state ) |
736 | 0 | { |
737 | 0 | BYTE prefix[SYMCRYPT_XMSS_MAX_PREFIX_SIZE]; |
738 | |
|
739 | 0 | SYMCRYPT_ASSERT(prefixLength <= SYMCRYPT_XMSS_MAX_PREFIX_SIZE); |
740 | |
|
741 | 0 | SymCryptWipe(prefix, prefixLength); |
742 | 0 | prefix[prefixLength - 1] = PrfType; |
743 | |
|
744 | 0 | SymCryptHashInit(hash, state); |
745 | 0 | SymCryptHashAppend(hash, state, prefix, prefixLength); |
746 | 0 | } |
747 | | |
748 | | |
749 | | VOID |
750 | | SYMCRYPT_CALL |
751 | | SymCryptXmssPrfKey( |
752 | | _In_ PCSYMCRYPT_XMSS_PARAMS pParams, |
753 | | _In_reads_bytes_( cbKey ) PCBYTE pbKey, |
754 | | SIZE_T cbKey, |
755 | | _Out_ SYMCRYPT_HASH_STATE *pState ) |
756 | 0 | { |
757 | 0 | SymCryptXmssPrfInit(pParams->hash, SYMCRYPT_XMSS_PRF, pParams->cbPrefix, pState); |
758 | 0 | SymCryptHashAppend(pParams->hash, pState, pbKey, cbKey); |
759 | 0 | } |
760 | | |
761 | | VOID |
762 | | SYMCRYPT_CALL |
763 | | SymCryptXmssPrf( |
764 | | _In_ PCSYMCRYPT_XMSS_PARAMS pParams, |
765 | | BYTE PrfType, |
766 | | _In_reads_bytes_( cbKey ) PCBYTE pbKey, |
767 | | SIZE_T cbKey, |
768 | | _In_reads_bytes_( cbMsg ) PCBYTE pbMsg, |
769 | | SIZE_T cbMsg, |
770 | | _Out_writes_bytes_( pParams->cbHashOutput ) PBYTE pbOutput ) |
771 | 0 | { |
772 | 0 | SYMCRYPT_HASH_STATE state; |
773 | | |
774 | 0 | SymCryptXmssPrfInit(pParams->hash, PrfType, pParams->cbPrefix, &state); |
775 | 0 | SymCryptHashAppend(pParams->hash, &state, pbKey, cbKey); |
776 | 0 | SymCryptHashAppend(pParams->hash, &state, pbMsg, cbMsg); |
777 | 0 | SymCryptHashResult(pParams->hash, &state, pbOutput, pParams->cbHashOutput); |
778 | 0 | } |
779 | | |
780 | | |
781 | | VOID |
782 | | SYMCRYPT_CALL |
783 | | SymCryptXmssRandHash( |
784 | | _In_ PCSYMCRYPT_XMSS_PARAMS pParams, |
785 | | _Inout_ XMSS_ADRS *adrs, |
786 | | _In_reads_bytes_( pParams->cbHashOutput ) PCBYTE pbSeed, |
787 | | _In_reads_bytes_( pParams->cbHashOutput ) PCBYTE pbLeft, |
788 | | _In_reads_bytes_( pParams->cbHashOutput ) PCBYTE pbRight, |
789 | | _Out_writes_bytes_( pParams->cbHashOutput ) PBYTE pbOutput ) |
790 | 0 | { |
791 | 0 | BYTE key[SYMCRYPT_HASH_MAX_RESULT_SIZE]; |
792 | 0 | BYTE bitmask[2 * SYMCRYPT_HASH_MAX_RESULT_SIZE]; |
793 | 0 | SYMCRYPT_HASH_STATE stateKeyed; |
794 | 0 | SYMCRYPT_HASH_STATE stateMask; |
795 | |
|
796 | 0 | SYMCRYPT_ASSERT(pParams->cbHashOutput <= SYMCRYPT_HASH_MAX_RESULT_SIZE); |
797 | |
|
798 | 0 | SymCryptXmssPrfKey(pParams, pbSeed, pParams->cbHashOutput, &stateKeyed); |
799 | |
|
800 | 0 | SYMCRYPT_STORE_MSBFIRST32(adrs->en32KeyAndMask, 1); |
801 | 0 | SymCryptHashStateCopy(pParams->hash, &stateKeyed, &stateMask); |
802 | 0 | SymCryptHashAppend(pParams->hash, &stateMask, (PCBYTE)adrs, sizeof(*adrs)); |
803 | 0 | SymCryptHashResult(pParams->hash, &stateMask, &bitmask[0], pParams->cbHashOutput); |
804 | |
|
805 | 0 | SYMCRYPT_STORE_MSBFIRST32(adrs->en32KeyAndMask, 2); |
806 | 0 | SymCryptHashStateCopy(pParams->hash, &stateKeyed, &stateMask); |
807 | 0 | SymCryptHashAppend(pParams->hash, &stateMask, (PCBYTE)adrs, sizeof(*adrs)); |
808 | 0 | SymCryptHashResult(pParams->hash, &stateMask, &bitmask[pParams->cbHashOutput], pParams->cbHashOutput); |
809 | |
|
810 | 0 | SYMCRYPT_STORE_MSBFIRST32(adrs->en32KeyAndMask, 0); |
811 | 0 | SymCryptHashAppend(pParams->hash, &stateKeyed, (PCBYTE)adrs, sizeof(*adrs)); |
812 | 0 | SymCryptHashResult(pParams->hash, &stateKeyed, key, pParams->cbHashOutput); |
813 | |
|
814 | 0 | SymCryptXorBytes(&bitmask[0], pbLeft, &bitmask[0], pParams->cbHashOutput); |
815 | 0 | SymCryptXorBytes(&bitmask[pParams->cbHashOutput], pbRight, &bitmask[pParams->cbHashOutput], pParams->cbHashOutput); |
816 | |
|
817 | 0 | SymCryptXmssPrf(pParams, SYMCRYPT_XMSS_H, key, pParams->cbHashOutput, bitmask, 2 * pParams->cbHashOutput, pbOutput); |
818 | 0 | } |
819 | | |
820 | | |
821 | | VOID |
822 | | SYMCRYPT_CALL |
823 | | SymCryptXmssTreeNodeCompress( |
824 | | _In_ PSYMCRYPT_TREEHASH_NODE pNodeLeft, |
825 | | _In_ PSYMCRYPT_TREEHASH_NODE pNodeRight, |
826 | | _Out_ PSYMCRYPT_TREEHASH_NODE pNodeOut, |
827 | | _Inout_ PSYMCRYPT_XMSS_INCREMENTAL_TREEHASH_CONTEXT pCtxIncHash ) |
828 | 0 | { |
829 | 0 | SYMCRYPT_STORE_MSBFIRST32(pCtxIncHash->adrs.u.hashtree.en32Height, pNodeLeft->height); |
830 | 0 | SYMCRYPT_STORE_MSBFIRST32(pCtxIncHash->adrs.u.hashtree.en32Index, pNodeLeft->index / 2); |
831 | |
|
832 | 0 | SymCryptXmssRandHash( |
833 | 0 | pCtxIncHash->pParams, |
834 | 0 | &pCtxIncHash->adrs, |
835 | 0 | pCtxIncHash->pbSeed, |
836 | 0 | pNodeLeft->value, |
837 | 0 | pNodeRight->value, |
838 | 0 | pNodeOut->value); |
839 | |
|
840 | 0 | pNodeOut->index = pNodeLeft->index / 2; |
841 | 0 | pNodeOut->height = pNodeLeft->height + 1; |
842 | 0 | } |
843 | | |
844 | | VOID |
845 | | SYMCRYPT_CALL |
846 | | SymCryptXmssLtreeNodeCompress( |
847 | | _In_ PSYMCRYPT_TREEHASH_NODE pNodeLeft, |
848 | | _In_ PSYMCRYPT_TREEHASH_NODE pNodeRight, |
849 | | _Out_ PSYMCRYPT_TREEHASH_NODE pNodeOut, |
850 | | _Inout_ PSYMCRYPT_XMSS_INCREMENTAL_TREEHASH_CONTEXT pCtxIncHash ) |
851 | 0 | { |
852 | 0 | SYMCRYPT_STORE_MSBFIRST32(pCtxIncHash->adrs.u.ltree.en32Height, pNodeLeft->height); |
853 | 0 | SYMCRYPT_STORE_MSBFIRST32(pCtxIncHash->adrs.u.ltree.en32Index, pNodeLeft->index / 2); |
854 | | |
855 | 0 | SymCryptXmssRandHash( |
856 | 0 | pCtxIncHash->pParams, |
857 | 0 | &pCtxIncHash->adrs, |
858 | 0 | pCtxIncHash->pbSeed, |
859 | 0 | pNodeLeft->value, |
860 | 0 | pNodeRight->value, |
861 | 0 | pNodeOut->value); |
862 | |
|
863 | 0 | pNodeOut->index = pNodeLeft->index / 2; |
864 | 0 | pNodeOut->height = pNodeLeft->height + 1; |
865 | 0 | } |
866 | | |
867 | | VOID |
868 | | SYMCRYPT_CALL |
869 | | SymCryptXmssCreateWotspSecret( |
870 | | _In_ PCSYMCRYPT_XMSS_PARAMS pParams, |
871 | | _In_reads_bytes_( pParams->cbHashOutput ) PCBYTE pbSkXmss, |
872 | | _In_reads_bytes_( pParams->cbHashOutput ) PCBYTE pbSeed, |
873 | | _Inout_ XMSS_ADRS *adrs, |
874 | | _Out_writes_bytes_( pParams->cbHashOutput ) PBYTE pbOutput ) |
875 | 0 | { |
876 | 0 | SYMCRYPT_HASH_STATE state; |
877 | |
|
878 | 0 | SymCryptXmssPrfInit(pParams->hash, SYMCRYPT_XMSS_PRF_KEYGEN, pParams->cbPrefix, &state); |
879 | 0 | SymCryptHashAppend(pParams->hash, &state, pbSkXmss, pParams->cbHashOutput); |
880 | 0 | SymCryptHashAppend(pParams->hash, &state, pbSeed, pParams->cbHashOutput); |
881 | 0 | SymCryptHashAppend(pParams->hash, &state, (PCBYTE)adrs, sizeof(*adrs)); |
882 | 0 | SymCryptHashResult(pParams->hash, &state, pbOutput, pParams->cbHashOutput); |
883 | 0 | } |
884 | | |
885 | | VOID |
886 | | SYMCRYPT_CALL |
887 | | SymCryptXmssChain( |
888 | | _In_ PCSYMCRYPT_XMSS_PARAMS pParams, |
889 | | _In_reads_bytes_( pParams->cbHashOutput ) PCBYTE pbInput, |
890 | | UINT32 startIndex, |
891 | | UINT32 steps, |
892 | | _In_reads_bytes_( pParams->cbHashOutput ) PCBYTE pbSeed, |
893 | | _Inout_ XMSS_ADRS *adrs, |
894 | | _Out_writes_bytes_( pParams->cbHashOutput ) PBYTE pbOutput ) |
895 | 0 | { |
896 | 0 | BYTE tmp[SYMCRYPT_HASH_MAX_RESULT_SIZE]; |
897 | 0 | BYTE key[SYMCRYPT_HASH_MAX_RESULT_SIZE]; |
898 | 0 | BYTE bm[SYMCRYPT_HASH_MAX_RESULT_SIZE]; |
899 | 0 | SYMCRYPT_HASH_STATE stateKey; |
900 | 0 | SYMCRYPT_HASH_STATE stateMask; |
901 | |
|
902 | 0 | memcpy(tmp, pbInput, pParams->cbHashOutput); |
903 | |
|
904 | 0 | for (UINT32 i = startIndex; i < startIndex + steps; i++) |
905 | 0 | { |
906 | 0 | SYMCRYPT_STORE_MSBFIRST32(adrs->u.ots.en32Hash, i); |
907 | |
|
908 | 0 | SymCryptXmssPrfKey(pParams, pbSeed, pParams->cbHashOutput, &stateKey); |
909 | 0 | SymCryptHashStateCopy(pParams->hash, &stateKey, &stateMask); |
910 | |
|
911 | 0 | SYMCRYPT_STORE_MSBFIRST32(adrs->en32KeyAndMask, 0); |
912 | 0 | SymCryptHashAppend(pParams->hash, &stateKey, (PCBYTE)adrs, sizeof(*adrs)); |
913 | 0 | SymCryptHashResult(pParams->hash, &stateKey, key, pParams->cbHashOutput); |
914 | |
|
915 | 0 | SYMCRYPT_STORE_MSBFIRST32(adrs->en32KeyAndMask, 1); |
916 | 0 | SymCryptHashAppend(pParams->hash, &stateMask, (PCBYTE)adrs, sizeof(*adrs)); |
917 | 0 | SymCryptHashResult(pParams->hash, &stateMask, bm, pParams->cbHashOutput); |
918 | |
|
919 | 0 | SymCryptXorBytes(tmp, bm, tmp, pParams->cbHashOutput); |
920 | |
|
921 | 0 | SymCryptXmssPrf(pParams, SYMCRYPT_XMSS_F, key, pParams->cbHashOutput, tmp, pParams->cbHashOutput, tmp); |
922 | 0 | } |
923 | | |
924 | | // reset used ADRS fields |
925 | 0 | SYMCRYPT_STORE_MSBFIRST32(adrs->u.ots.en32Hash, 0); |
926 | 0 | SYMCRYPT_STORE_MSBFIRST32(adrs->en32KeyAndMask, 0); |
927 | |
|
928 | 0 | memcpy(pbOutput, tmp, pParams->cbHashOutput); |
929 | 0 | } |
930 | | |
931 | | |
932 | | VOID |
933 | | SYMCRYPT_CALL |
934 | | SymCryptXmssCreateWotspPublickey( |
935 | | _In_ PCSYMCRYPT_XMSS_PARAMS pParams, |
936 | | _Inout_ XMSS_ADRS *adrs, |
937 | | UINT32 uLeaf, |
938 | | _In_reads_bytes_( pParams->cbHashOutput ) PCBYTE pbSkXmss, |
939 | | _In_reads_bytes_( pParams->cbHashOutput ) PCBYTE pbSeed, |
940 | | _Out_writes_bytes_opt_( cbScratch ) PBYTE pbScratch, |
941 | | SIZE_T cbScratch, |
942 | | _Out_writes_bytes_( pParams->cbHashOutput ) PBYTE pbOutput ) |
943 | 0 | { |
944 | 0 | PSYMCRYPT_INCREMENTAL_TREEHASH pIncHash = NULL; |
945 | 0 | PSYMCRYPT_TREEHASH_NODE pNode = NULL; |
946 | 0 | SYMCRYPT_XMSS_INCREMENTAL_TREEHASH_CONTEXT ctxIncHash; |
947 | |
|
948 | 0 | SYMCRYPT_ASSERT(cbScratch >= SymCryptHbsSizeofScratchBytesForIncrementalTreehash(pParams->cbHashOutput, pParams->len)); |
949 | |
|
950 | 0 | SymCryptXmssSetAdrsType(adrs, XMSS_ADRS_TYPE_LTREE); |
951 | 0 | SYMCRYPT_STORE_MSBFIRST32(adrs->u.ltree.en32Leaf, uLeaf); |
952 | |
|
953 | 0 | ctxIncHash.adrs = *adrs; |
954 | 0 | ctxIncHash.pParams = pParams; |
955 | 0 | ctxIncHash.pbSeed = pbSeed; |
956 | |
|
957 | 0 | pIncHash = SymCryptHbsIncrementalTreehashInit( |
958 | 0 | pParams->len, |
959 | 0 | pbScratch, |
960 | 0 | cbScratch, |
961 | 0 | pParams->cbHashOutput, |
962 | 0 | SymCryptXmssLtreeNodeCompress, |
963 | 0 | &ctxIncHash); |
964 | |
|
965 | 0 | for (UINT32 i = 0; i < pParams->len; i++) |
966 | 0 | { |
967 | 0 | pNode = SymCryptHbsIncrementalTreehashAllocNode(pIncHash, i); |
968 | |
|
969 | 0 | SymCryptXmssSetAdrsType(adrs, XMSS_ADRS_TYPE_OTS); |
970 | 0 | SYMCRYPT_STORE_MSBFIRST32(adrs->u.ots.en32Leaf, uLeaf); |
971 | 0 | SYMCRYPT_STORE_MSBFIRST32(adrs->u.ots.en32Chain, i); |
972 | |
|
973 | 0 | SymCryptXmssCreateWotspSecret( |
974 | 0 | pParams, |
975 | 0 | pbSkXmss, |
976 | 0 | pbSeed, |
977 | 0 | adrs, |
978 | 0 | pNode->value); |
979 | |
|
980 | 0 | SymCryptXmssChain( |
981 | 0 | pParams, |
982 | 0 | pNode->value, |
983 | 0 | 0, |
984 | 0 | (1 << pParams->nWinternitzWidth) - 1, |
985 | 0 | pbSeed, |
986 | 0 | adrs, |
987 | 0 | pNode->value); |
988 | |
|
989 | 0 | SymCryptHbsIncrementalTreehashProcess(pIncHash); |
990 | |
|
991 | 0 | } |
992 | |
|
993 | 0 | pNode = SymCryptHbsIncrementalTreehashFinalize(pIncHash); |
994 | |
|
995 | 0 | memcpy(pbOutput, pNode->value, pParams->cbHashOutput); |
996 | 0 | } |
997 | | |
998 | | |
999 | | VOID |
1000 | | SYMCRYPT_CALL |
1001 | | SymCryptXmssComputeSubtreeRoot( |
1002 | | _In_ PCSYMCRYPT_XMSS_PARAMS pParams, |
1003 | | _In_ XMSS_ADRS *adrs, |
1004 | | _In_reads_bytes_( pParams->cbHashOutput ) PCBYTE pbSkXmss, |
1005 | | _In_reads_bytes_( pParams->cbHashOutput ) PCBYTE pbSeed, |
1006 | | UINT32 uLeaf, |
1007 | | UINT32 uHeight, |
1008 | | _Out_writes_bytes_opt_( cbScratch ) PBYTE pbScratch, |
1009 | | SIZE_T cbScratch, |
1010 | | _Out_writes_bytes_( pParams->cbHashOutput ) PBYTE pbRoot ) |
1011 | 0 | { |
1012 | 0 | UNREFERENCED_PARAMETER(cbScratch); |
1013 | |
|
1014 | 0 | PSYMCRYPT_INCREMENTAL_TREEHASH pIncHash = NULL; |
1015 | 0 | PSYMCRYPT_TREEHASH_NODE pNode = NULL; |
1016 | 0 | SYMCRYPT_XMSS_INCREMENTAL_TREEHASH_CONTEXT ctxIncHash; |
1017 | | |
1018 | | // uLeaf must be a multiple of 2^uHeight |
1019 | 0 | SYMCRYPT_ASSERT((uLeaf & ((1UL << uHeight) - 1)) == 0); |
1020 | |
|
1021 | 0 | SIZE_T cbScratchTree = SymCryptHbsSizeofScratchBytesForIncrementalTreehash(pParams->cbHashOutput, 1ULL << pParams->nLayerHeight); |
1022 | 0 | SIZE_T cbScratchLtree = SymCryptHbsSizeofScratchBytesForIncrementalTreehash(pParams->cbHashOutput, pParams->len); |
1023 | |
|
1024 | 0 | SYMCRYPT_ASSERT(cbScratch >= (cbScratchTree + cbScratchLtree)); |
1025 | |
|
1026 | 0 | PBYTE pbScratchTree = pbScratch; |
1027 | 0 | PBYTE pbScratchLtree = pbScratch + cbScratchTree; |
1028 | |
|
1029 | 0 | SymCryptXmssSetAdrsType(adrs, XMSS_ADRS_TYPE_HASH_TREE); |
1030 | |
|
1031 | 0 | ctxIncHash.adrs = *adrs; |
1032 | 0 | ctxIncHash.pParams = pParams; |
1033 | 0 | ctxIncHash.pbSeed = pbSeed; |
1034 | |
|
1035 | 0 | pIncHash = SymCryptHbsIncrementalTreehashInit( |
1036 | 0 | 1ULL << uHeight, |
1037 | 0 | pbScratchTree, |
1038 | 0 | cbScratchTree, |
1039 | 0 | pParams->cbHashOutput, |
1040 | 0 | SymCryptXmssTreeNodeCompress, |
1041 | 0 | &ctxIncHash); |
1042 | |
|
1043 | 0 | for (UINT32 nLeafIndex = uLeaf; nLeafIndex < uLeaf + (1UL << uHeight); nLeafIndex++) |
1044 | 0 | { |
1045 | 0 | pNode = SymCryptHbsIncrementalTreehashAllocNode(pIncHash, nLeafIndex); |
1046 | |
|
1047 | 0 | SymCryptXmssCreateWotspPublickey(pParams, |
1048 | 0 | adrs, |
1049 | 0 | nLeafIndex, |
1050 | 0 | pbSkXmss, |
1051 | 0 | pbSeed, |
1052 | 0 | pbScratchLtree, |
1053 | 0 | cbScratchLtree, |
1054 | 0 | pNode->value ); |
1055 | | |
1056 | 0 | SymCryptHbsIncrementalTreehashProcess(pIncHash); |
1057 | 0 | } |
1058 | |
|
1059 | 0 | pNode = SymCryptHbsIncrementalTreehashFinalize(pIncHash); |
1060 | | |
1061 | 0 | memcpy(pbRoot, pNode->value, pParams->cbHashOutput); |
1062 | 0 | } |
1063 | | |
1064 | | |
1065 | | SYMCRYPT_ERROR |
1066 | | SYMCRYPT_CALL |
1067 | | SymCryptXmssComputePublicRoot( |
1068 | | _In_ PCSYMCRYPT_XMSS_PARAMS pParams, |
1069 | | _In_reads_bytes_( cbSeed ) PCBYTE pbSeed, |
1070 | | SIZE_T cbSeed, |
1071 | | _In_reads_bytes_( cbSkXmss ) PCBYTE pbSkXmss, |
1072 | | SIZE_T cbSkXmss, |
1073 | | _Out_writes_bytes_( cbRoot ) PBYTE pbRoot, |
1074 | | SIZE_T cbRoot ) |
1075 | 0 | { |
1076 | 0 | SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; |
1077 | 0 | PBYTE pbScratch = NULL; |
1078 | 0 | SIZE_T cbScratch = 0; |
1079 | 0 | XMSS_ADRS adrs; |
1080 | |
|
1081 | 0 | if (pbRoot == NULL || cbRoot != pParams->cbHashOutput || |
1082 | 0 | pbSeed == NULL || cbSeed != pParams->cbHashOutput || |
1083 | 0 | pbSkXmss == NULL || cbSkXmss != pParams->cbHashOutput) |
1084 | 0 | { |
1085 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
1086 | 0 | goto cleanup; |
1087 | 0 | } |
1088 | | |
1089 | 0 | cbScratch += SymCryptHbsSizeofScratchBytesForIncrementalTreehash(pParams->cbHashOutput, 1ULL << pParams->nLayerHeight); |
1090 | 0 | cbScratch += SymCryptHbsSizeofScratchBytesForIncrementalTreehash(pParams->cbHashOutput, pParams->len); |
1091 | |
|
1092 | 0 | SYMCRYPT_ASSERT(cbScratch > 0); |
1093 | 0 | pbScratch = SymCryptCallbackAlloc(cbScratch); |
1094 | |
|
1095 | 0 | if (pbScratch == NULL) |
1096 | 0 | { |
1097 | 0 | scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE; |
1098 | 0 | goto cleanup; |
1099 | 0 | } |
1100 | | |
1101 | 0 | SymCryptWipeKnownSize(&adrs, sizeof(XMSS_ADRS)); |
1102 | 0 | SYMCRYPT_STORE_MSBFIRST32(adrs.en32Layer, pParams->nLayers - 1); |
1103 | |
|
1104 | 0 | SymCryptXmssComputeSubtreeRoot( |
1105 | 0 | pParams, |
1106 | 0 | &adrs, |
1107 | 0 | pbSkXmss, |
1108 | 0 | pbSeed, |
1109 | 0 | 0, |
1110 | 0 | pParams->nLayerHeight, |
1111 | 0 | pbScratch, |
1112 | 0 | cbScratch, |
1113 | 0 | pbRoot ); |
1114 | |
|
1115 | 0 | cleanup: |
1116 | |
|
1117 | 0 | if (pbScratch != NULL) |
1118 | 0 | { |
1119 | 0 | SymCryptWipe(pbScratch, cbScratch); |
1120 | 0 | SymCryptCallbackFree(pbScratch); |
1121 | 0 | } |
1122 | |
|
1123 | 0 | return scError; |
1124 | 0 | } |
1125 | | |
1126 | | |
1127 | | SYMCRYPT_ERROR |
1128 | | SYMCRYPT_CALL |
1129 | | SymCryptXmsskeyVerifyRoot( |
1130 | | _In_ PCSYMCRYPT_XMSS_KEY pKey) |
1131 | 0 | { |
1132 | 0 | BYTE Root[SYMCRYPT_HASH_MAX_RESULT_SIZE]; |
1133 | 0 | SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; |
1134 | |
|
1135 | 0 | SYMCRYPT_CHECK_MAGIC(pKey); |
1136 | | |
1137 | | // key to be verified has to be a private key |
1138 | 0 | if (pKey->keyType != SYMCRYPT_XMSSKEY_TYPE_PRIVATE) |
1139 | 0 | { |
1140 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
1141 | 0 | goto cleanup; |
1142 | 0 | } |
1143 | | |
1144 | 0 | SymCryptWipeKnownSize(Root, sizeof(Root)); |
1145 | |
|
1146 | 0 | scError = SymCryptXmssComputePublicRoot( |
1147 | 0 | &pKey->params, |
1148 | 0 | pKey->Seed, |
1149 | 0 | pKey->params.cbHashOutput, |
1150 | 0 | pKey->SkXmss, |
1151 | 0 | pKey->params.cbHashOutput, |
1152 | 0 | Root, |
1153 | 0 | pKey->params.cbHashOutput); |
1154 | |
|
1155 | 0 | if (scError != SYMCRYPT_NO_ERROR) |
1156 | 0 | { |
1157 | 0 | goto cleanup; |
1158 | 0 | } |
1159 | | |
1160 | 0 | if (!SymCryptEqual(Root, pKey->Root, pKey->params.cbHashOutput)) |
1161 | 0 | { |
1162 | 0 | scError = SYMCRYPT_HBS_PUBLIC_ROOT_MISMATCH; |
1163 | 0 | } |
1164 | |
|
1165 | 0 | cleanup: |
1166 | |
|
1167 | 0 | return scError; |
1168 | 0 | } |
1169 | | |
1170 | | |
1171 | | SYMCRYPT_ERROR |
1172 | | SYMCRYPT_CALL |
1173 | | SymCryptXmsskeyGenerate( |
1174 | | _Inout_ PSYMCRYPT_XMSS_KEY pKey, |
1175 | | UINT32 flags) |
1176 | 0 | { |
1177 | 0 | SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; |
1178 | |
|
1179 | 0 | SYMCRYPT_CHECK_MAGIC(pKey); |
1180 | |
|
1181 | 0 | if (flags != 0) |
1182 | 0 | { |
1183 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
1184 | 0 | goto cleanup; |
1185 | 0 | } |
1186 | | |
1187 | | // Wipe private key material |
1188 | 0 | SymCryptWipeKnownSize(pKey->SkPrf, sizeof(pKey->SkPrf)); |
1189 | 0 | SymCryptWipeKnownSize(pKey->SkXmss, sizeof(pKey->SkXmss)); |
1190 | |
|
1191 | 0 | pKey->Idx = 0; |
1192 | 0 | SymCryptCallbackRandom(pKey->SkPrf, pKey->params.cbHashOutput); |
1193 | 0 | SymCryptCallbackRandom(pKey->SkXmss, pKey->params.cbHashOutput); |
1194 | 0 | SymCryptCallbackRandom(pKey->Seed, pKey->params.cbHashOutput); |
1195 | | |
1196 | | // Compute public root from the private key |
1197 | 0 | scError = SymCryptXmssComputePublicRoot( |
1198 | 0 | &pKey->params, |
1199 | 0 | pKey->Seed, |
1200 | 0 | pKey->params.cbHashOutput, |
1201 | 0 | pKey->SkXmss, |
1202 | 0 | pKey->params.cbHashOutput, |
1203 | 0 | pKey->Root, |
1204 | 0 | pKey->params.cbHashOutput); |
1205 | |
|
1206 | 0 | if (scError != SYMCRYPT_NO_ERROR) |
1207 | 0 | { |
1208 | 0 | goto cleanup; |
1209 | 0 | } |
1210 | | |
1211 | 0 | pKey->keyType = SYMCRYPT_XMSSKEY_TYPE_PRIVATE; |
1212 | |
|
1213 | 0 | cleanup: |
1214 | |
|
1215 | 0 | if (scError != SYMCRYPT_NO_ERROR) |
1216 | 0 | { |
1217 | 0 | SymCryptWipeKnownSize(pKey->SkPrf, sizeof(pKey->SkPrf)); |
1218 | 0 | SymCryptWipeKnownSize(pKey->SkXmss, sizeof(pKey->SkXmss)); |
1219 | 0 | pKey->keyType = SYMCRYPT_XMSSKEY_TYPE_NONE; |
1220 | 0 | } |
1221 | |
|
1222 | 0 | return scError; |
1223 | 0 | } |
1224 | | |
1225 | | |
1226 | | SYMCRYPT_ERROR |
1227 | | SYMCRYPT_CALL |
1228 | | SymCryptXmsskeySetValue( |
1229 | | _In_reads_bytes_( cbInput ) PCBYTE pbInput, |
1230 | | SIZE_T cbInput, |
1231 | | SYMCRYPT_XMSSKEY_TYPE keyType, |
1232 | | UINT32 flags, |
1233 | | _Inout_ PSYMCRYPT_XMSS_KEY pKey ) |
1234 | 0 | { |
1235 | 0 | SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; |
1236 | 0 | UINT32 uAlgId; |
1237 | 0 | SIZE_T cbKey; |
1238 | |
|
1239 | 0 | SYMCRYPT_ASSERT(keyType == SYMCRYPT_XMSSKEY_TYPE_PUBLIC || keyType == SYMCRYPT_XMSSKEY_TYPE_PRIVATE); |
1240 | |
|
1241 | 0 | SYMCRYPT_CHECK_MAGIC(pKey); |
1242 | |
|
1243 | 0 | if(flags & (~SYMCRYPT_FLAG_XMSSKEY_VERIFY_ROOT)) |
1244 | 0 | { |
1245 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
1246 | 0 | goto cleanup; |
1247 | 0 | } |
1248 | | |
1249 | | // Public root validation can only be performed for private keys |
1250 | 0 | if ((flags & SYMCRYPT_FLAG_XMSSKEY_VERIFY_ROOT) != 0 && |
1251 | 0 | keyType != SYMCRYPT_XMSSKEY_TYPE_PRIVATE) |
1252 | 0 | { |
1253 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
1254 | 0 | goto cleanup; |
1255 | 0 | } |
1256 | | |
1257 | 0 | SymCryptXmssSizeofKeyBlobFromParams(&pKey->params, keyType, &cbKey); |
1258 | |
|
1259 | 0 | if (cbInput != cbKey) |
1260 | 0 | { |
1261 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
1262 | 0 | goto cleanup; |
1263 | 0 | } |
1264 | | |
1265 | 0 | uAlgId = SYMCRYPT_LOAD_MSBFIRST32(pbInput); |
1266 | 0 | pbInput += sizeof(UINT32); |
1267 | |
|
1268 | 0 | if (uAlgId != pKey->params.id) |
1269 | 0 | { |
1270 | 0 | scError = SYMCRYPT_INVALID_BLOB; |
1271 | 0 | goto cleanup; |
1272 | 0 | } |
1273 | | |
1274 | | // Wipe private key material |
1275 | 0 | pKey->Idx = 0; |
1276 | 0 | SymCryptWipeKnownSize(pKey->SkPrf, sizeof(pKey->SkPrf)); |
1277 | 0 | SymCryptWipeKnownSize(pKey->SkXmss, sizeof(pKey->SkXmss)); |
1278 | |
|
1279 | 0 | pKey->keyType = keyType; |
1280 | |
|
1281 | 0 | memcpy(pKey->Root, pbInput, pKey->params.cbHashOutput); |
1282 | 0 | pbInput += pKey->params.cbHashOutput; |
1283 | |
|
1284 | 0 | memcpy(pKey->Seed, pbInput, pKey->params.cbHashOutput); |
1285 | 0 | pbInput += pKey->params.cbHashOutput; |
1286 | |
|
1287 | 0 | if (keyType == SYMCRYPT_XMSSKEY_TYPE_PRIVATE) |
1288 | 0 | { |
1289 | 0 | pKey->Idx = SYMCRYPT_LOAD_MSBFIRST64(pbInput); |
1290 | 0 | pbInput += sizeof(UINT64); |
1291 | |
|
1292 | 0 | memcpy(pKey->SkXmss, pbInput, pKey->params.cbHashOutput); |
1293 | 0 | pbInput += pKey->params.cbHashOutput; |
1294 | |
|
1295 | 0 | memcpy(pKey->SkPrf, pbInput, pKey->params.cbHashOutput); |
1296 | 0 | pbInput += pKey->params.cbHashOutput; |
1297 | |
|
1298 | 0 | if (flags & SYMCRYPT_FLAG_XMSSKEY_VERIFY_ROOT) |
1299 | 0 | { |
1300 | | // pKey has been initialized by now |
1301 | 0 | scError = SymCryptXmsskeyVerifyRoot(pKey); |
1302 | |
|
1303 | 0 | if (scError != SYMCRYPT_NO_ERROR) |
1304 | 0 | { |
1305 | 0 | goto cleanup; |
1306 | 0 | } |
1307 | 0 | } |
1308 | 0 | } |
1309 | | |
1310 | 0 | cleanup: |
1311 | |
|
1312 | 0 | if (scError != SYMCRYPT_NO_ERROR) |
1313 | 0 | { |
1314 | 0 | SymCryptWipeKnownSize(pKey->SkPrf, sizeof(pKey->SkPrf)); |
1315 | 0 | SymCryptWipeKnownSize(pKey->SkXmss, sizeof(pKey->SkXmss)); |
1316 | 0 | pKey->keyType = SYMCRYPT_XMSSKEY_TYPE_NONE; |
1317 | 0 | } |
1318 | |
|
1319 | 0 | return scError; |
1320 | 0 | } |
1321 | | |
1322 | | |
1323 | | SYMCRYPT_ERROR |
1324 | | SYMCRYPT_CALL |
1325 | | SymCryptXmsskeyGetValue( |
1326 | | _In_ PCSYMCRYPT_XMSS_KEY pKey, |
1327 | | SYMCRYPT_XMSSKEY_TYPE keyType, |
1328 | | UINT32 flags, |
1329 | | _Out_writes_bytes_( cbOutput ) PBYTE pbOutput, |
1330 | | SIZE_T cbOutput) |
1331 | 0 | { |
1332 | 0 | SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; |
1333 | 0 | SIZE_T cbKey; |
1334 | |
|
1335 | 0 | SYMCRYPT_ASSERT(keyType == SYMCRYPT_XMSSKEY_TYPE_PUBLIC || keyType == SYMCRYPT_XMSSKEY_TYPE_PRIVATE); |
1336 | |
|
1337 | 0 | SYMCRYPT_CHECK_MAGIC(pKey); |
1338 | |
|
1339 | 0 | if (flags != 0 || |
1340 | 0 | pKey->keyType == SYMCRYPT_XMSSKEY_TYPE_NONE) |
1341 | 0 | { |
1342 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
1343 | 0 | goto cleanup; |
1344 | 0 | } |
1345 | | |
1346 | 0 | SymCryptXmssSizeofKeyBlobFromParams(&pKey->params, keyType, &cbKey); |
1347 | |
|
1348 | 0 | if (cbOutput != cbKey) |
1349 | 0 | { |
1350 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
1351 | 0 | goto cleanup; |
1352 | 0 | } |
1353 | | |
1354 | | // |
1355 | | // Public Key |
1356 | | // |
1357 | | |
1358 | | // Alg Id |
1359 | 0 | SYMCRYPT_STORE_MSBFIRST32(pbOutput, pKey->params.id); |
1360 | 0 | pbOutput += sizeof(UINT32); |
1361 | | |
1362 | | // Root |
1363 | 0 | memcpy(pbOutput, pKey->Root, pKey->params.cbHashOutput); |
1364 | 0 | pbOutput += pKey->params.cbHashOutput; |
1365 | | |
1366 | | // Seed |
1367 | 0 | memcpy(pbOutput, pKey->Seed, pKey->params.cbHashOutput); |
1368 | 0 | pbOutput += pKey->params.cbHashOutput; |
1369 | |
|
1370 | 0 | if (keyType == SYMCRYPT_XMSSKEY_TYPE_PRIVATE) |
1371 | 0 | { |
1372 | | // |
1373 | | // Private Key |
1374 | | // |
1375 | | |
1376 | | // Idx |
1377 | 0 | SYMCRYPT_STORE_MSBFIRST64(pbOutput, pKey->Idx); |
1378 | 0 | pbOutput += sizeof(pKey->Idx); |
1379 | | |
1380 | | // SK_XMSS |
1381 | 0 | memcpy(pbOutput, pKey->SkXmss, pKey->params.cbHashOutput); |
1382 | 0 | pbOutput += pKey->params.cbHashOutput; |
1383 | | |
1384 | | // SK_PRF |
1385 | 0 | memcpy(pbOutput, pKey->SkPrf, pKey->params.cbHashOutput); |
1386 | 0 | pbOutput += pKey->params.cbHashOutput; |
1387 | 0 | } |
1388 | |
|
1389 | 0 | cleanup: |
1390 | |
|
1391 | 0 | return scError; |
1392 | 0 | } |
1393 | | |
1394 | | |
1395 | | UINT32 |
1396 | | SYMCRYPT_CALL |
1397 | | SymCryptHbsGetDigit( |
1398 | | UINT32 width, |
1399 | | _In_ PCBYTE pbBuffer, |
1400 | | SIZE_T cbBuffer, |
1401 | | UINT32 index ) |
1402 | 0 | { |
1403 | 0 | UNREFERENCED_PARAMETER(cbBuffer); |
1404 | |
|
1405 | 0 | SYMCRYPT_ASSERT(width == 1 || width == 2 || width == 4 || width == 8); |
1406 | 0 | SYMCRYPT_ASSERT(index < ((cbBuffer * 8) / width)); |
1407 | |
|
1408 | 0 | UINT32 digitsPerByte = 8 / width; |
1409 | |
|
1410 | 0 | BYTE value = pbBuffer[index / digitsPerByte]; |
1411 | |
|
1412 | 0 | value >>= width * (digitsPerByte - 1 - (index % digitsPerByte)); |
1413 | |
|
1414 | 0 | value &= (1 << width) - 1; |
1415 | |
|
1416 | 0 | return value; |
1417 | 0 | } |
1418 | | |
1419 | | |
1420 | | VOID |
1421 | | SYMCRYPT_CALL |
1422 | | SymCryptXmssTreeRootFromAuthenticationPath( |
1423 | | _In_ PCSYMCRYPT_XMSS_PARAMS pParams, |
1424 | | _Inout_ XMSS_ADRS *adrs, |
1425 | | UINT32 uLeaf, |
1426 | | _In_reads_bytes_( pParams->cbHashOutput ) |
1427 | | PCBYTE pbStartingNode, |
1428 | | _In_reads_bytes_( pParams->cbHashOutput * pParams->nLayerHeight ) |
1429 | | PCBYTE pbAuthNodes, |
1430 | | _In_reads_bytes_( pParams->cbHashOutput ) |
1431 | | PCBYTE pbSeed, |
1432 | | _Out_writes_bytes_( pParams->cbHashOutput ) |
1433 | | PBYTE pbOutput ) |
1434 | 0 | { |
1435 | 0 | BYTE node[SYMCRYPT_HASH_MAX_RESULT_SIZE]; |
1436 | 0 | BYTE tmp[SYMCRYPT_HASH_MAX_RESULT_SIZE]; |
1437 | 0 | UINT32 uNodeIndex = uLeaf; |
1438 | | |
1439 | 0 | memcpy(node, pbStartingNode, pParams->cbHashOutput); |
1440 | |
|
1441 | 0 | SymCryptXmssSetAdrsType(adrs, XMSS_ADRS_TYPE_HASH_TREE); |
1442 | 0 | SYMCRYPT_STORE_MSBFIRST32(adrs->u.hashtree.en32Index, uNodeIndex); |
1443 | |
|
1444 | 0 | for (UINT32 i = 0; i < pParams->nLayerHeight; i++) |
1445 | 0 | { |
1446 | 0 | SYMCRYPT_STORE_MSBFIRST32(adrs->u.hashtree.en32Height, i); |
1447 | |
|
1448 | 0 | if ( ((uLeaf >> i) & 1) == 0 ) |
1449 | 0 | { |
1450 | 0 | uNodeIndex = uNodeIndex / 2; |
1451 | 0 | SYMCRYPT_STORE_MSBFIRST32(adrs->u.hashtree.en32Index, uNodeIndex); |
1452 | 0 | SymCryptXmssRandHash(pParams, adrs, pbSeed, node, &pbAuthNodes[pParams->cbHashOutput * i], tmp); |
1453 | 0 | } |
1454 | 0 | else |
1455 | 0 | { |
1456 | 0 | uNodeIndex = (uNodeIndex - 1) / 2; |
1457 | 0 | SYMCRYPT_STORE_MSBFIRST32(adrs->u.hashtree.en32Index, uNodeIndex); |
1458 | 0 | SymCryptXmssRandHash(pParams, adrs, pbSeed, &pbAuthNodes[pParams->cbHashOutput * i], node, tmp); |
1459 | 0 | } |
1460 | |
|
1461 | 0 | memcpy(node, tmp, pParams->cbHashOutput); |
1462 | 0 | } |
1463 | |
|
1464 | 0 | memcpy(pbOutput, node, pParams->cbHashOutput); |
1465 | 0 | } |
1466 | | |
1467 | | VOID |
1468 | | SYMCRYPT_CALL |
1469 | | SymCryptXmssRandomizedHash( |
1470 | | _In_ PCSYMCRYPT_XMSS_PARAMS pParams, |
1471 | | UINT64 Idx, |
1472 | | _In_reads_bytes_( pParams->cbHashOutput ) PCBYTE pbRandomizer, |
1473 | | _In_reads_bytes_( pParams->cbHashOutput ) PCBYTE pbRoot, |
1474 | | _In_reads_bytes_( pParams->cbHashOutput ) PCBYTE pbMsg, |
1475 | | SIZE_T cbMsg, |
1476 | | _Out_writes_bytes_( pParams->cbHashOutput ) PBYTE pbOutput ) |
1477 | 0 | { |
1478 | 0 | SYMCRYPT_HASH_STATE state; |
1479 | 0 | BYTE idxBuf[SYMCRYPT_HASH_MAX_RESULT_SIZE]; |
1480 | |
|
1481 | 0 | SymCryptWipe(idxBuf, pParams->cbHashOutput); |
1482 | 0 | SYMCRYPT_STORE_MSBFIRST64(&idxBuf[pParams->cbHashOutput - sizeof(Idx)], Idx); |
1483 | |
|
1484 | 0 | SymCryptXmssPrfInit(pParams->hash, SYMCRYPT_XMSS_H_MSG, pParams->cbPrefix, &state); |
1485 | 0 | SymCryptHashAppend(pParams->hash, &state, pbRandomizer, pParams->cbHashOutput); |
1486 | 0 | SymCryptHashAppend(pParams->hash, &state, pbRoot, pParams->cbHashOutput); |
1487 | 0 | SymCryptHashAppend(pParams->hash, &state, idxBuf, pParams->cbHashOutput); |
1488 | 0 | SymCryptHashAppend(pParams->hash, &state, pbMsg, cbMsg); |
1489 | 0 | SymCryptHashResult(pParams->hash, &state, pbOutput, pParams->cbHashOutput); |
1490 | 0 | } |
1491 | | |
1492 | | |
1493 | | VOID |
1494 | | SYMCRYPT_CALL |
1495 | | SymCryptXmssWotspPublickeyFromSignature( |
1496 | | _In_ PCSYMCRYPT_XMSS_PARAMS pParams, |
1497 | | _Inout_ XMSS_ADRS *adrs, |
1498 | | UINT32 idx, |
1499 | | _In_reads_bytes_( pParams->cbHashOutput ) |
1500 | | PCBYTE pbMsg, |
1501 | | _In_reads_bytes_( pParams->cbHashOutput ) |
1502 | | PCBYTE pbSeed, |
1503 | | _In_reads_bytes_( pParams->cbHashOutput * pParams->len ) |
1504 | | PCBYTE pbSignature, |
1505 | | _Out_writes_bytes_( cbScratch ) |
1506 | | PBYTE pbScratch, |
1507 | | SIZE_T cbScratch, |
1508 | | _Out_writes_bytes_( pParams->cbHashOutput ) |
1509 | | PBYTE pbOutput ) |
1510 | 0 | { |
1511 | |
|
1512 | 0 | UINT32 digit; |
1513 | 0 | UINT32 checksum = 0; |
1514 | 0 | BYTE en32Checksum[4]; |
1515 | 0 | const UINT32 maxChainIndex = (1 << pParams->nWinternitzWidth) - 1; |
1516 | 0 | PSYMCRYPT_INCREMENTAL_TREEHASH pIncHash = NULL; |
1517 | 0 | PSYMCRYPT_TREEHASH_NODE pNode = NULL; |
1518 | 0 | SYMCRYPT_XMSS_INCREMENTAL_TREEHASH_CONTEXT ctxIncHash; |
1519 | | |
1520 | 0 | SymCryptXmssSetAdrsType(adrs, XMSS_ADRS_TYPE_LTREE); |
1521 | 0 | SYMCRYPT_STORE_MSBFIRST32(adrs->u.ltree.en32Leaf, idx); |
1522 | |
|
1523 | 0 | ctxIncHash.adrs = *adrs; |
1524 | 0 | ctxIncHash.pParams = pParams; |
1525 | 0 | ctxIncHash.pbSeed = pbSeed; |
1526 | |
|
1527 | 0 | pIncHash = SymCryptHbsIncrementalTreehashInit( |
1528 | 0 | pParams->len, |
1529 | 0 | pbScratch, |
1530 | 0 | cbScratch, |
1531 | 0 | pParams->cbHashOutput, |
1532 | 0 | SymCryptXmssLtreeNodeCompress, |
1533 | 0 | &ctxIncHash); |
1534 | |
|
1535 | 0 | for (UINT32 i = 0; i < pParams->len; i++) |
1536 | 0 | { |
1537 | 0 | if (i < pParams->len1) |
1538 | 0 | { |
1539 | 0 | digit = SymCryptHbsGetDigit(pParams->nWinternitzWidth, pbMsg, pParams->cbHashOutput, i); |
1540 | |
|
1541 | 0 | checksum += maxChainIndex - digit; |
1542 | 0 | } |
1543 | 0 | else |
1544 | 0 | { |
1545 | 0 | if (i == pParams->len1) |
1546 | 0 | { |
1547 | 0 | checksum <<= pParams->nLeftShift32; |
1548 | 0 | SYMCRYPT_STORE_MSBFIRST32(en32Checksum, checksum); |
1549 | 0 | } |
1550 | |
|
1551 | 0 | digit = SymCryptHbsGetDigit(pParams->nWinternitzWidth, en32Checksum, sizeof(en32Checksum), i - pParams->len1); |
1552 | 0 | } |
1553 | |
|
1554 | 0 | pNode = SymCryptHbsIncrementalTreehashAllocNode(pIncHash, i); |
1555 | |
|
1556 | 0 | SymCryptXmssSetAdrsType(adrs, XMSS_ADRS_TYPE_OTS); |
1557 | 0 | SYMCRYPT_STORE_MSBFIRST32(adrs->u.ots.en32Leaf, idx); |
1558 | 0 | SYMCRYPT_STORE_MSBFIRST32(adrs->u.ots.en32Chain, i); |
1559 | |
|
1560 | 0 | SymCryptXmssChain( |
1561 | 0 | pParams, |
1562 | 0 | &pbSignature[pParams->cbHashOutput * i], |
1563 | 0 | digit, |
1564 | 0 | maxChainIndex - digit, |
1565 | 0 | pbSeed, |
1566 | 0 | adrs, |
1567 | 0 | pNode->value); |
1568 | |
|
1569 | 0 | SymCryptHbsIncrementalTreehashProcess(pIncHash); |
1570 | 0 | } |
1571 | |
|
1572 | 0 | pNode = SymCryptHbsIncrementalTreehashFinalize(pIncHash); |
1573 | |
|
1574 | 0 | memcpy(pbOutput, pNode->value, pParams->cbHashOutput); |
1575 | 0 | } |
1576 | | |
1577 | | |
1578 | | VOID |
1579 | | SYMCRYPT_CALL |
1580 | | SymCryptXmssTreeRootFromSignature( |
1581 | | _In_ PCSYMCRYPT_XMSS_PARAMS pParams, |
1582 | | _Inout_ XMSS_ADRS *adrs, |
1583 | | _In_reads_bytes_( pParams->cbHashOutput ) |
1584 | | PCBYTE pbSeed, |
1585 | | _In_reads_bytes_( pParams->cbHashOutput ) |
1586 | | PCBYTE pbHash, |
1587 | | UINT32 uLeaf, |
1588 | | _In_reads_bytes_( pParams->cbHashOutput * pParams->len ) |
1589 | | PCBYTE pbWotspSig, |
1590 | | _In_reads_bytes_( pParams->cbHashOutput* pParams->nLayerHeight ) |
1591 | | PCBYTE pbAuthNodes, |
1592 | | _Out_writes_bytes_( pParams->cbHashOutput ) |
1593 | | PBYTE pbOutput, |
1594 | | _Out_writes_bytes_opt_( cbScratch ) |
1595 | | PBYTE pbScratch, |
1596 | | SIZE_T cbScratch ) |
1597 | 0 | { |
1598 | 0 | BYTE WotspPublickey[SYMCRYPT_HASH_MAX_RESULT_SIZE]; |
1599 | |
|
1600 | 0 | SymCryptXmssWotspPublickeyFromSignature( |
1601 | 0 | pParams, |
1602 | 0 | adrs, |
1603 | 0 | uLeaf, |
1604 | 0 | pbHash, |
1605 | 0 | pbSeed, |
1606 | 0 | pbWotspSig, |
1607 | 0 | pbScratch, |
1608 | 0 | cbScratch, |
1609 | 0 | WotspPublickey); |
1610 | |
|
1611 | 0 | SymCryptXmssTreeRootFromAuthenticationPath( |
1612 | 0 | pParams, |
1613 | 0 | adrs, |
1614 | 0 | uLeaf, |
1615 | 0 | WotspPublickey, |
1616 | 0 | pbAuthNodes, |
1617 | 0 | pbSeed, |
1618 | 0 | pbOutput); |
1619 | 0 | } |
1620 | | |
1621 | | SIZE_T |
1622 | | SYMCRYPT_CALL |
1623 | | SymCryptXmssSizeofWotspSignature(_In_ PCSYMCRYPT_XMSS_PARAMS pParams) |
1624 | 0 | { |
1625 | | // WOTSP signature size is len = len1 + len2 many hash outputs |
1626 | 0 | return pParams->cbHashOutput * pParams->len; |
1627 | 0 | } |
1628 | | |
1629 | | SIZE_T |
1630 | | SYMCRYPT_CALL |
1631 | | SymCryptXmssSizeofAuthNodes( |
1632 | | _In_ PCSYMCRYPT_XMSS_PARAMS pParams) |
1633 | 0 | { |
1634 | | // size of authentication nodes for single tree |
1635 | 0 | return pParams->cbHashOutput * pParams->nLayerHeight; |
1636 | 0 | } |
1637 | | |
1638 | | UINT64 |
1639 | | SYMCRYPT_CALL |
1640 | | SymCryptXmssSignatureGetIdx( |
1641 | | _In_ PCSYMCRYPT_XMSS_PARAMS pParams, |
1642 | | _In_ PCBYTE pbSig ) |
1643 | 0 | { |
1644 | 0 | UINT64 Idx = 0; |
1645 | |
|
1646 | 0 | for (UINT8 i = 0; i < pParams->cbIdx; i++) |
1647 | 0 | { |
1648 | 0 | Idx <<= 8; |
1649 | 0 | Idx |= (UINT64)pbSig[i]; |
1650 | 0 | } |
1651 | |
|
1652 | 0 | return Idx; |
1653 | 0 | } |
1654 | | |
1655 | | PBYTE |
1656 | | SYMCRYPT_CALL |
1657 | | SymCryptXmssSignatureGetRandomness( |
1658 | | _In_ PCSYMCRYPT_XMSS_PARAMS pParams, |
1659 | | _In_ PCBYTE pbSig ) |
1660 | 0 | { |
1661 | 0 | PBYTE pb = (PBYTE)pbSig; |
1662 | | |
1663 | | // randomness comes after idx |
1664 | 0 | pb += pParams->cbIdx; |
1665 | |
|
1666 | 0 | return pb; |
1667 | 0 | } |
1668 | | |
1669 | | PBYTE |
1670 | | SYMCRYPT_CALL |
1671 | | SymCryptXmssSignatureGetWotspSig( |
1672 | | _In_ PCSYMCRYPT_XMSS_PARAMS pParams, |
1673 | | _In_ PCBYTE pbSig, |
1674 | | UINT32 uLayer ) |
1675 | 0 | { |
1676 | 0 | PBYTE pb = SymCryptXmssSignatureGetRandomness(pParams, pbSig); |
1677 | | |
1678 | | // skip randomness |
1679 | 0 | pb += pParams->cbHashOutput; |
1680 | | |
1681 | | // each layer contains WOTSP signature and AuthNodes |
1682 | 0 | pb += uLayer * (SymCryptXmssSizeofWotspSignature(pParams) + SymCryptXmssSizeofAuthNodes(pParams)); |
1683 | |
|
1684 | 0 | return pb; |
1685 | 0 | } |
1686 | | |
1687 | | PBYTE |
1688 | | SYMCRYPT_CALL |
1689 | | SymCryptXmssSignatureGetAuthNodes( |
1690 | | _In_ PCSYMCRYPT_XMSS_PARAMS pParams, |
1691 | | _In_ PCBYTE pbSig, |
1692 | | UINT32 uLayer ) |
1693 | 0 | { |
1694 | 0 | PBYTE pb = SymCryptXmssSignatureGetWotspSig(pParams, pbSig, uLayer); |
1695 | | |
1696 | | // AuthNodes follow WOTSP signature |
1697 | 0 | pb += SymCryptXmssSizeofWotspSignature(pParams); |
1698 | |
|
1699 | 0 | return pb; |
1700 | 0 | } |
1701 | | |
1702 | | SYMCRYPT_ERROR |
1703 | | SYMCRYPT_CALL |
1704 | | SymCryptXmssVerify( |
1705 | | _Inout_ PSYMCRYPT_XMSS_KEY pKey, |
1706 | | _In_reads_bytes_( cbMessage ) PCBYTE pbMessage, |
1707 | | SIZE_T cbMessage, |
1708 | | UINT32 flags, |
1709 | | _In_reads_bytes_( cbSignature ) PCBYTE pbSignature, |
1710 | | SIZE_T cbSignature ) |
1711 | 0 | { |
1712 | 0 | SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; |
1713 | 0 | PBYTE pbScratch = NULL; |
1714 | 0 | SIZE_T cbScratch = 0; |
1715 | 0 | PCSYMCRYPT_XMSS_PARAMS pParams = &pKey->params; |
1716 | 0 | BYTE RandomizedHash[SYMCRYPT_HASH_MAX_RESULT_SIZE]; |
1717 | 0 | BYTE ComputedRoot[SYMCRYPT_HASH_MAX_RESULT_SIZE]; |
1718 | 0 | XMSS_ADRS adrs; |
1719 | 0 | UINT32 uLayer; |
1720 | 0 | UINT64 uTree; |
1721 | 0 | UINT32 uLeaf; |
1722 | 0 | const UINT64 LeafMask = (1ULL << pParams->nLayerHeight) - 1; |
1723 | |
|
1724 | 0 | SYMCRYPT_CHECK_MAGIC(pKey); |
1725 | |
|
1726 | 0 | if (flags != 0 || |
1727 | 0 | pbSignature == NULL || |
1728 | 0 | cbSignature != SymCryptXmssSizeofSignatureFromParams(pParams) || |
1729 | 0 | pKey->keyType == SYMCRYPT_XMSSKEY_TYPE_NONE ) |
1730 | 0 | { |
1731 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
1732 | 0 | goto cleanup; |
1733 | 0 | } |
1734 | | |
1735 | 0 | cbScratch += SymCryptHbsSizeofScratchBytesForIncrementalTreehash(pParams->cbHashOutput, pParams->len); |
1736 | 0 | cbScratch += SymCryptHbsSizeofScratchBytesForIncrementalTreehash(pParams->cbHashOutput, 1ULL << (pParams->nTotalTreeHeight / pParams->nLayers)); |
1737 | |
|
1738 | 0 | pbScratch = (PBYTE)SymCryptCallbackAlloc(cbScratch); |
1739 | |
|
1740 | 0 | if (pbScratch == NULL) |
1741 | 0 | { |
1742 | 0 | scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE; |
1743 | 0 | goto cleanup; |
1744 | 0 | } |
1745 | | |
1746 | 0 | PBYTE pbRandomness = SymCryptXmssSignatureGetRandomness(pParams, pbSignature); |
1747 | 0 | UINT64 Idx = SymCryptXmssSignatureGetIdx(pParams, pbSignature); |
1748 | |
|
1749 | 0 | SymCryptXmssRandomizedHash( |
1750 | 0 | pParams, |
1751 | 0 | Idx, |
1752 | 0 | pbRandomness, |
1753 | 0 | pKey->Root, |
1754 | 0 | pbMessage, |
1755 | 0 | cbMessage, |
1756 | 0 | RandomizedHash); |
1757 | |
|
1758 | 0 | uLayer = 0; |
1759 | 0 | uTree = Idx >> pParams->nLayerHeight; |
1760 | 0 | uLeaf = (UINT32)(Idx & LeafMask); |
1761 | 0 | SymCryptWipeKnownSize(&adrs, sizeof(XMSS_ADRS)); |
1762 | 0 | SYMCRYPT_STORE_MSBFIRST32(adrs.en32Layer, uLayer); |
1763 | 0 | SYMCRYPT_STORE_MSBFIRST64(adrs.en64Tree, uTree); |
1764 | 0 | SymCryptXmssTreeRootFromSignature( |
1765 | 0 | pParams, |
1766 | 0 | &adrs, |
1767 | 0 | pKey->Seed, |
1768 | 0 | RandomizedHash, |
1769 | 0 | uLeaf, |
1770 | 0 | SymCryptXmssSignatureGetWotspSig(pParams, pbSignature, uLayer), |
1771 | 0 | SymCryptXmssSignatureGetAuthNodes(pParams, pbSignature, uLayer), |
1772 | 0 | ComputedRoot, |
1773 | 0 | pbScratch, |
1774 | 0 | cbScratch); |
1775 | |
|
1776 | 0 | for (uLayer = 1; uLayer < pParams->nLayers; uLayer++) |
1777 | 0 | { |
1778 | 0 | Idx >>= pParams->nLayerHeight; |
1779 | 0 | uTree = Idx >> pParams->nLayerHeight; |
1780 | 0 | uLeaf = (UINT32)(Idx & LeafMask); |
1781 | |
|
1782 | 0 | SYMCRYPT_STORE_MSBFIRST32(adrs.en32Layer, uLayer); |
1783 | 0 | SYMCRYPT_STORE_MSBFIRST64(adrs.en64Tree, uTree); |
1784 | 0 | SymCryptXmssTreeRootFromSignature( |
1785 | 0 | pParams, |
1786 | 0 | &adrs, |
1787 | 0 | pKey->Seed, |
1788 | 0 | ComputedRoot, |
1789 | 0 | uLeaf, |
1790 | 0 | SymCryptXmssSignatureGetWotspSig(pParams, pbSignature, uLayer), |
1791 | 0 | SymCryptXmssSignatureGetAuthNodes(pParams, pbSignature, uLayer), |
1792 | 0 | ComputedRoot, |
1793 | 0 | pbScratch, |
1794 | 0 | cbScratch); |
1795 | 0 | } |
1796 | |
|
1797 | 0 | if (!SymCryptEqual(ComputedRoot, pKey->Root, pParams->cbHashOutput)) |
1798 | 0 | { |
1799 | 0 | scError = SYMCRYPT_SIGNATURE_VERIFICATION_FAILURE; |
1800 | 0 | goto cleanup; |
1801 | 0 | } |
1802 | | |
1803 | 0 | cleanup: |
1804 | |
|
1805 | 0 | if (pbScratch) |
1806 | 0 | { |
1807 | 0 | SymCryptWipe(pbScratch, cbScratch); |
1808 | 0 | SymCryptCallbackFree(pbScratch); |
1809 | 0 | } |
1810 | |
|
1811 | 0 | return scError; |
1812 | 0 | } |
1813 | | |
1814 | | VOID |
1815 | | SYMCRYPT_CALL |
1816 | | SymCryptXmssWotspSign( |
1817 | | _In_ PCSYMCRYPT_XMSS_PARAMS pParams, |
1818 | | _Inout_ XMSS_ADRS* adrs, |
1819 | | _In_reads_bytes_( pParams->cbHashOutput ) PCBYTE pbInput, |
1820 | | UINT32 uLeaf, |
1821 | | _In_reads_bytes_( pParams->cbHashOutput ) PCBYTE pbSeed, |
1822 | | _In_reads_bytes_( pParams->cbHashOutput ) PCBYTE pbSkXmss, |
1823 | | _Out_writes_bytes_( pParams->cbHashOutput * pParams->len ) PBYTE pbOutput ) |
1824 | 0 | { |
1825 | 0 | BYTE node[SYMCRYPT_HASH_MAX_RESULT_SIZE]; |
1826 | 0 | UINT32 nChecksum = 0; |
1827 | 0 | BYTE en32Checksum[sizeof(UINT32)]; |
1828 | 0 | UINT32 digit; |
1829 | 0 | const UINT32 maxChainIndex = (1UL << pParams->nWinternitzWidth) - 1; |
1830 | | |
1831 | |
|
1832 | 0 | SymCryptXmssSetAdrsType(adrs, XMSS_ADRS_TYPE_OTS); |
1833 | 0 | SYMCRYPT_STORE_MSBFIRST32(adrs->u.ots.en32Leaf, uLeaf); |
1834 | |
|
1835 | 0 | for (UINT32 i = 0; i < pParams->len; i++) |
1836 | 0 | { |
1837 | 0 | SYMCRYPT_STORE_MSBFIRST32(adrs->u.ots.en32Chain, i); |
1838 | 0 | SymCryptXmssCreateWotspSecret( |
1839 | 0 | pParams, |
1840 | 0 | pbSkXmss, |
1841 | 0 | pbSeed, |
1842 | 0 | adrs, |
1843 | 0 | node); |
1844 | |
|
1845 | 0 | if (i < pParams->len1) |
1846 | 0 | { |
1847 | 0 | digit = SymCryptHbsGetDigit(pParams->nWinternitzWidth, pbInput, pParams->cbHashOutput, i); |
1848 | |
|
1849 | 0 | nChecksum += maxChainIndex - digit; |
1850 | 0 | } |
1851 | 0 | else |
1852 | 0 | { |
1853 | 0 | if (i == pParams->len1) |
1854 | 0 | { |
1855 | 0 | nChecksum <<= pParams->nLeftShift32; |
1856 | 0 | SYMCRYPT_STORE_MSBFIRST32(en32Checksum, nChecksum); |
1857 | 0 | } |
1858 | |
|
1859 | 0 | digit = SymCryptHbsGetDigit(pParams->nWinternitzWidth, en32Checksum, sizeof(en32Checksum), i - pParams->len1); |
1860 | 0 | } |
1861 | |
|
1862 | 0 | SymCryptXmssChain( |
1863 | 0 | pParams, |
1864 | 0 | node, |
1865 | 0 | 0, |
1866 | 0 | digit, |
1867 | 0 | pbSeed, |
1868 | 0 | adrs, |
1869 | 0 | &pbOutput[i * pParams->cbHashOutput]); |
1870 | 0 | } |
1871 | 0 | } |
1872 | | |
1873 | | |
1874 | | VOID |
1875 | | SYMCRYPT_CALL |
1876 | | SymCryptXmssTreeSignHash( |
1877 | | _In_ PCSYMCRYPT_XMSS_PARAMS pParams, |
1878 | | _Inout_ XMSS_ADRS *adrs, |
1879 | | _In_reads_bytes_( pParams->cbHashOutput ) |
1880 | | PCBYTE pbSkXmss, |
1881 | | _In_reads_bytes_( pParams->cbHashOutput ) |
1882 | | PCBYTE pbSeed, |
1883 | | _In_reads_bytes_( pParams->cbHashOutput ) |
1884 | | PCBYTE pbHash, |
1885 | | UINT32 Idx, |
1886 | | _Out_writes_bytes_( pParams->cbHashOutput * pParams->len ) |
1887 | | PBYTE pbWotspSig, |
1888 | | _Out_writes_bytes_( pParams->cbHashOutput * pParams->nLayerHeight ) |
1889 | | PBYTE pbAuthNodes, |
1890 | | _Out_writes_bytes_opt_( pParams->cbHashOutput ) |
1891 | | PBYTE pbRoot, |
1892 | | _Out_writes_bytes_opt_( cbScratch ) |
1893 | | PBYTE pbScratch, |
1894 | | SIZE_T cbScratch ) |
1895 | 0 | { |
1896 | 0 | BYTE WotspPublicKey[SYMCRYPT_HASH_MAX_RESULT_SIZE]; |
1897 | |
|
1898 | 0 | SymCryptXmssWotspSign( |
1899 | 0 | pParams, |
1900 | 0 | adrs, |
1901 | 0 | pbHash, |
1902 | 0 | Idx, |
1903 | 0 | pbSeed, |
1904 | 0 | pbSkXmss, |
1905 | 0 | pbWotspSig ); |
1906 | | |
1907 | | // Generate authentication path |
1908 | 0 | for (UINT32 h = 0; h < pParams->nLayerHeight; h++) |
1909 | 0 | { |
1910 | 0 | UINT32 uLeaf = ((Idx >> h) ^ 1UL) << h; |
1911 | 0 | SymCryptXmssComputeSubtreeRoot( |
1912 | 0 | pParams, |
1913 | 0 | adrs, |
1914 | 0 | pbSkXmss, |
1915 | 0 | pbSeed, |
1916 | 0 | uLeaf, |
1917 | 0 | h, |
1918 | 0 | pbScratch, |
1919 | 0 | cbScratch, |
1920 | 0 | &pbAuthNodes[h * pParams->cbHashOutput]); |
1921 | 0 | } |
1922 | | |
1923 | | // |
1924 | | // Calculate tree root if requested by the caller |
1925 | | // |
1926 | | // This is used to return the tree root to be signed with the upper |
1927 | | // layer in XMSS^MT. |
1928 | 0 | if (pbRoot) |
1929 | 0 | { |
1930 | 0 | SymCryptXmssCreateWotspPublickey( |
1931 | 0 | pParams, |
1932 | 0 | adrs, |
1933 | 0 | Idx, |
1934 | 0 | pbSkXmss, |
1935 | 0 | pbSeed, |
1936 | 0 | pbScratch, |
1937 | 0 | cbScratch, |
1938 | 0 | WotspPublicKey); |
1939 | |
|
1940 | 0 | SymCryptXmssTreeRootFromAuthenticationPath( |
1941 | 0 | pParams, |
1942 | 0 | adrs, |
1943 | 0 | Idx, |
1944 | 0 | WotspPublicKey, |
1945 | 0 | pbAuthNodes, |
1946 | 0 | pbSeed, |
1947 | 0 | pbRoot); |
1948 | 0 | } |
1949 | 0 | } |
1950 | | |
1951 | | // |
1952 | | // Compute randomness for randomized hashing |
1953 | | // |
1954 | | VOID |
1955 | | SYMCRYPT_CALL |
1956 | | SymCryptXmssComputeRandomness( |
1957 | | _In_ PCSYMCRYPT_XMSS_KEY pKey, |
1958 | | UINT64 Idx, |
1959 | | _Out_writes_bytes_( pKey->params.cbHashOutput ) PBYTE pbRandomness ) |
1960 | 0 | { |
1961 | 0 | BYTE IdxBuffer[32]; |
1962 | |
|
1963 | 0 | SymCryptWipeKnownSize(IdxBuffer, sizeof(IdxBuffer)); |
1964 | 0 | SYMCRYPT_STORE_MSBFIRST64(IdxBuffer + sizeof(IdxBuffer) - sizeof(Idx), Idx); |
1965 | |
|
1966 | 0 | SymCryptXmssPrf( |
1967 | 0 | &pKey->params, |
1968 | 0 | SYMCRYPT_XMSS_PRF, |
1969 | 0 | pKey->SkPrf, |
1970 | 0 | pKey->params.cbHashOutput, |
1971 | 0 | IdxBuffer, |
1972 | 0 | sizeof(IdxBuffer), |
1973 | 0 | pbRandomness); |
1974 | 0 | } |
1975 | | |
1976 | | |
1977 | | SYMCRYPT_ERROR |
1978 | | SYMCRYPT_CALL |
1979 | | SymCryptXmssSign( |
1980 | | _Inout_ PSYMCRYPT_XMSS_KEY pKey, |
1981 | | _In_reads_bytes_( cbMessage ) PCBYTE pbMessage, |
1982 | | SIZE_T cbMessage, |
1983 | | UINT32 flags, |
1984 | | _Out_writes_bytes_( cbSignature ) PBYTE pbSignature, |
1985 | | SIZE_T cbSignature ) |
1986 | 0 | { |
1987 | 0 | SYMCRYPT_ERROR scError = SYMCRYPT_NO_ERROR; |
1988 | 0 | PBYTE pbScratch = NULL; |
1989 | 0 | SIZE_T cbScratch = 0; |
1990 | 0 | PSYMCRYPT_XMSS_PARAMS pParams = &pKey->params; |
1991 | 0 | UINT64 Idx; |
1992 | 0 | BYTE en64Idx[sizeof(UINT64)]; |
1993 | 0 | BYTE Randomness[SYMCRYPT_HASH_MAX_RESULT_SIZE]; |
1994 | 0 | BYTE RandomizedHash[SYMCRYPT_HASH_MAX_RESULT_SIZE]; |
1995 | 0 | BYTE TreeRoot[SYMCRYPT_HASH_MAX_RESULT_SIZE]; |
1996 | 0 | XMSS_ADRS adrs; |
1997 | 0 | const UINT64 LeafMask = (1ULL << pParams->nLayerHeight) - 1; |
1998 | | |
1999 | |
|
2000 | 0 | SYMCRYPT_CHECK_MAGIC(pKey); |
2001 | |
|
2002 | 0 | if (flags != 0 || |
2003 | 0 | pbSignature == NULL || |
2004 | 0 | cbSignature != SymCryptXmssSizeofSignatureFromParams(pParams) || |
2005 | 0 | pKey->keyType != SYMCRYPT_XMSSKEY_TYPE_PRIVATE ) |
2006 | 0 | { |
2007 | 0 | scError = SYMCRYPT_INVALID_ARGUMENT; |
2008 | 0 | goto cleanup; |
2009 | 0 | } |
2010 | | |
2011 | 0 | Idx = SYMCRYPT_ATOMIC_ADD64_POST_RELAXED(&pKey->Idx, 1) - 1; |
2012 | 0 | if (Idx >= (1ULL << pParams->nTotalTreeHeight)) |
2013 | 0 | { |
2014 | | // Set Idx to first unusable value |
2015 | 0 | pKey->Idx = (1ULL << pParams->nTotalTreeHeight); |
2016 | |
|
2017 | 0 | scError = SYMCRYPT_HBS_NO_OTS_KEYS_LEFT; |
2018 | 0 | goto cleanup; |
2019 | 0 | } |
2020 | | |
2021 | 0 | cbScratch += SymCryptHbsSizeofScratchBytesForIncrementalTreehash(pParams->cbHashOutput, pParams->len); // Ltree hashing |
2022 | 0 | cbScratch += SymCryptHbsSizeofScratchBytesForIncrementalTreehash(pParams->cbHashOutput, 1ULL << pParams->nTotalTreeHeight); // Merkle-tree hashing |
2023 | |
|
2024 | 0 | pbScratch = (PBYTE)SymCryptCallbackAlloc(cbScratch); |
2025 | |
|
2026 | 0 | if (pbScratch == NULL) |
2027 | 0 | { |
2028 | 0 | scError = SYMCRYPT_MEMORY_ALLOCATION_FAILURE; |
2029 | 0 | goto cleanup; |
2030 | 0 | } |
2031 | | |
2032 | 0 | SYMCRYPT_STORE_MSBFIRST64(en64Idx, Idx); |
2033 | 0 | memcpy(pbSignature, &en64Idx[sizeof(en64Idx) - pParams->cbIdx], pParams->cbIdx); |
2034 | |
|
2035 | 0 | SymCryptXmssComputeRandomness(pKey, Idx, Randomness); |
2036 | 0 | memcpy(SymCryptXmssSignatureGetRandomness(pParams, pbSignature), Randomness, pKey->params.cbHashOutput); |
2037 | |
|
2038 | 0 | SymCryptXmssRandomizedHash(&pKey->params, Idx, Randomness, pKey->Root, pbMessage, cbMessage, RandomizedHash); |
2039 | |
|
2040 | 0 | UINT32 uLayer = 0; |
2041 | 0 | UINT64 uTree = Idx >> pParams->nLayerHeight; |
2042 | 0 | UINT32 uLeaf = (UINT32)(Idx & LeafMask); |
2043 | 0 | SymCryptWipeKnownSize(&adrs, sizeof(XMSS_ADRS)); |
2044 | 0 | SYMCRYPT_STORE_MSBFIRST32(adrs.en32Layer, uLayer); |
2045 | 0 | SYMCRYPT_STORE_MSBFIRST64(adrs.en64Tree, uTree); |
2046 | 0 | SymCryptXmssTreeSignHash( |
2047 | 0 | &pKey->params, |
2048 | 0 | &adrs, |
2049 | 0 | pKey->SkXmss, |
2050 | 0 | pKey->Seed, |
2051 | 0 | RandomizedHash, |
2052 | 0 | uLeaf, |
2053 | 0 | SymCryptXmssSignatureGetWotspSig(pParams, pbSignature, uLayer), |
2054 | 0 | SymCryptXmssSignatureGetAuthNodes(pParams, pbSignature, uLayer), |
2055 | 0 | pParams->nLayers == 1 ? NULL : TreeRoot, // Compute tree root if signing for multi-tree |
2056 | 0 | pbScratch, |
2057 | 0 | cbScratch ); |
2058 | |
|
2059 | 0 | for (uLayer = 1; uLayer < pParams->nLayers; uLayer++) |
2060 | 0 | { |
2061 | 0 | Idx >>= pParams->nLayerHeight; |
2062 | 0 | uTree = Idx >> pParams->nLayerHeight; |
2063 | 0 | uLeaf = (UINT32)(Idx & LeafMask); |
2064 | |
|
2065 | 0 | SYMCRYPT_STORE_MSBFIRST32(adrs.en32Layer, uLayer); |
2066 | 0 | SYMCRYPT_STORE_MSBFIRST64(adrs.en64Tree, uTree); |
2067 | |
|
2068 | 0 | SymCryptXmssTreeSignHash( |
2069 | 0 | &pKey->params, |
2070 | 0 | &adrs, |
2071 | 0 | pKey->SkXmss, |
2072 | 0 | pKey->Seed, |
2073 | 0 | TreeRoot, |
2074 | 0 | uLeaf, |
2075 | 0 | SymCryptXmssSignatureGetWotspSig(pParams, pbSignature, uLayer), |
2076 | 0 | SymCryptXmssSignatureGetAuthNodes(pParams, pbSignature, uLayer), |
2077 | 0 | uLayer == (UINT32)(pParams->nLayers - 1) ? NULL : TreeRoot, // No need to compute the root for the top layer tree |
2078 | 0 | pbScratch, |
2079 | 0 | cbScratch); |
2080 | 0 | } |
2081 | |
|
2082 | 0 | if (scError != SYMCRYPT_NO_ERROR) |
2083 | 0 | { |
2084 | 0 | SymCryptWipe(pbSignature, cbSignature); |
2085 | 0 | goto cleanup; |
2086 | 0 | } |
2087 | | |
2088 | 0 | cleanup: |
2089 | |
|
2090 | 0 | if (pbScratch) |
2091 | 0 | { |
2092 | 0 | SymCryptWipe(pbScratch, cbScratch); |
2093 | 0 | SymCryptCallbackFree(pbScratch); |
2094 | 0 | } |
2095 | |
|
2096 | 0 | return scError; |
2097 | 0 | } |