Coverage Report

Created: 2024-11-21 07:03

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