Coverage Report

Created: 2024-11-21 07:03

/src/SymCrypt/lib/xmss.c
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
}