Coverage Report

Created: 2024-11-21 07:03

/src/SymCrypt/lib/hash.c
Line
Count
Source (jump to first uncovered line)
1
//
2
// hash.c generic code used in many hash implementations.
3
// Copyright (c) Microsoft Corporation. Licensed under the MIT license.
4
//
5
6
#include "precomp.h"
7
8
VOID
9
SYMCRYPT_CALL
10
SymCryptHashAppendInternal( 
11
    _In_                        PCSYMCRYPT_HASH             pHash,
12
    _Inout_                     PSYMCRYPT_COMMON_HASH_STATE pState,
13
    _In_reads_bytes_( cbData )  PCBYTE                      pbData,
14
                                SIZE_T                      cbData )
15
156k
{
16
156k
    UINT32  bytesInBuffer;
17
156k
    UINT32  freeInBuffer;
18
156k
    SIZE_T  tmp;
19
20
156k
    SYMCRYPT_CHECK_MAGIC( pState );
21
22
156k
    pState->dataLengthL += cbData;
23
156k
    if( pState->dataLengthL < cbData ) {
24
0
        pState->dataLengthH ++;                         // This is almost-unreachable code as it requires 2^64 bytes to be hashed.
25
0
    }
26
27
156k
    bytesInBuffer = pState->bytesInBuffer;
28
29
    //
30
    // If previous data in buffer, buffer new input and transform if possible.
31
    //
32
156k
    if( bytesInBuffer > 0 )
33
131k
    {
34
131k
        SYMCRYPT_ASSERT( pHash->inputBlockSize > bytesInBuffer );
35
36
131k
        freeInBuffer = pHash->inputBlockSize - bytesInBuffer;
37
131k
        if( cbData < freeInBuffer )
38
111k
        {
39
            //
40
            // All the data will fit in the buffer.
41
            // We don't do anything here. 
42
            // As cbData < inputBlockSize the bulk data processing is skipped,
43
            // and the data will be copied to the buffer at the end
44
            // of this code.
45
111k
        } else {
46
            //
47
            // Enough data to fill the whole buffer & process it
48
            //
49
19.7k
            memcpy(&pState->buffer[bytesInBuffer], pbData, freeInBuffer);
50
19.7k
            pbData += freeInBuffer;
51
19.7k
            cbData -= freeInBuffer;
52
19.7k
            (*pHash->appendBlockFunc)( (PBYTE)pState + pHash->chainOffset, &pState->buffer[0], pHash->inputBlockSize, &tmp );
53
            
54
19.7k
            bytesInBuffer = 0;
55
19.7k
        }
56
131k
    }
57
58
    //
59
    // Internal buffer is empty; process all remaining whole blocks in the input
60
    //
61
156k
    if( cbData >= pHash->inputBlockSize )
62
21.6k
    {
63
21.6k
        (*pHash->appendBlockFunc)( (PBYTE)pState + pHash->chainOffset, pbData, cbData, &tmp );
64
21.6k
        SYMCRYPT_ASSERT( tmp < pHash->inputBlockSize );
65
21.6k
        pbData += cbData - tmp;
66
21.6k
        cbData = tmp;
67
21.6k
    }
68
69
156k
    SYMCRYPT_ASSERT( cbData < pHash->inputBlockSize );
70
71
    //
72
    // buffer remaining input if necessary.
73
    //
74
156k
    if( cbData > 0 )
75
69.1k
    {
76
69.1k
        memcpy( &pState->buffer[bytesInBuffer], pbData, cbData );
77
69.1k
        bytesInBuffer += (UINT32) cbData;
78
69.1k
    }
79
80
156k
    pState->bytesInBuffer = bytesInBuffer;
81
156k
}
82
83
VOID
84
SYMCRYPT_CALL
85
SymCryptHashCommonPaddingMd4Style(
86
    _In_                        PCSYMCRYPT_HASH             pHash,
87
    _Inout_                     PSYMCRYPT_COMMON_HASH_STATE pState )
88
23.0k
{
89
23.0k
    SIZE_T tmp;
90
23.0k
    SIZE_T bytesInBuffer = pState->bytesInBuffer;
91
92
23.0k
    SYMCRYPT_CHECK_MAGIC( pState );
93
23.0k
    SYMCRYPT_ASSERT( pHash->inputBlockSize == 64 );
94
23.0k
    SYMCRYPT_ASSERT( bytesInBuffer == (pState->dataLengthL & 0x3f) );
95
96
    //
97
    // The buffer is never completely full, so we can always put the first
98
    // padding byte in.
99
    //
100
23.0k
    pState->buffer[bytesInBuffer++] = 0x80;
101
102
23.0k
    if( bytesInBuffer > 64-8 ) {
103
        //
104
        // No room for the rest of the padding. Pad with zeroes & process block
105
        // bytesInBuffer is at most 64, so we do not have an integer underflow
106
        //
107
1.76k
        SymCryptWipe( &pState->buffer[bytesInBuffer], 64-bytesInBuffer );
108
1.76k
        (*pHash->appendBlockFunc)( (PBYTE)pState + pHash->chainOffset, pState->buffer, 64, &tmp );
109
1.76k
        SYMCRYPT_ASSERT( tmp == 0 );
110
1.76k
        bytesInBuffer = 0;
111
1.76k
    }
112
113
    //
114
    // Set rest of padding
115
    // At this point bytesInBuffer <= 64-8, so we don't have an underflow
116
    // We wipe to the end of the buffer as it is 16-aligned,
117
    // and it is faster to wipe to an aligned point
118
    //
119
23.0k
    SymCryptWipe( &pState->buffer[bytesInBuffer], 64-bytesInBuffer );
120
23.0k
    SYMCRYPT_STORE_LSBFIRST64( &pState->buffer[64-8], pState->dataLengthL * 8 );
121
122
    //
123
    // Process the final block
124
    //
125
23.0k
    (*pHash->appendBlockFunc)( (PBYTE)pState + pHash->chainOffset, pState->buffer, 64, &tmp );
126
23.0k
}
127
128
129
130
SIZE_T
131
SYMCRYPT_CALL
132
SymCryptHashResultSize( _In_ PCSYMCRYPT_HASH pHash )
133
0
{
134
0
    return pHash->resultSize;
135
0
}
136
137
138
SIZE_T
139
SYMCRYPT_CALL
140
SymCryptHashInputBlockSize( _In_ PCSYMCRYPT_HASH pHash )
141
0
{
142
0
    return pHash->inputBlockSize;
143
0
}
144
145
SIZE_T
146
SYMCRYPT_CALL
147
SymCryptHashStateSize( _In_ PCSYMCRYPT_HASH pHash )
148
0
{
149
0
    return pHash->stateSize;
150
0
}
151
152
153
VOID
154
SYMCRYPT_CALL
155
SymCryptHash( 
156
    _In_                                                         PCSYMCRYPT_HASH pHash,
157
    _In_reads_( cbData )                                         PCBYTE          pbData, 
158
                                                                 SIZE_T          cbData,
159
    _Out_writes_( SYMCRYPT_MIN( cbResult, pHash->resultSize ) )  PBYTE           pbResult,
160
                                                                 SIZE_T          cbResult )
161
0
{
162
0
    SYMCRYPT_HASH_STATE hash;
163
164
0
    _Analysis_assume_( pHash->stateSize <= sizeof( hash ) );
165
0
    SymCryptHashInit( pHash, &hash );
166
0
    SymCryptHashAppend( pHash, &hash, pbData, cbData );
167
0
    SymCryptHashResult( pHash, &hash, pbResult, cbResult );
168
0
    SymCryptWipe( &hash, pHash->stateSize );
169
0
}
170
171
VOID
172
SYMCRYPT_CALL
173
SymCryptHashInit(
174
    _In_                                        PCSYMCRYPT_HASH pHash,
175
    _Out_writes_bytes_( pHash->stateSize )      PVOID           pState )
176
0
{
177
0
    (*pHash->initFunc)( pState );
178
0
}
179
180
VOID
181
SYMCRYPT_CALL
182
SymCryptHashAppend(
183
    _In_                                        PCSYMCRYPT_HASH pHash,
184
    _Inout_updates_bytes_( pHash->stateSize )   PVOID           pState,
185
    _In_reads_( cbData )                        PCBYTE          pbData,
186
                                                SIZE_T          cbData )
187
0
{
188
0
    (*pHash->appendFunc)( pState, pbData, cbData );
189
0
}
190
191
VOID
192
SYMCRYPT_CALL
193
SymCryptHashResult( 
194
    _In_                                                         PCSYMCRYPT_HASH pHash,
195
    _Inout_updates_bytes_( pHash->stateSize )                    PVOID           pState,
196
    _Out_writes_( SYMCRYPT_MIN( cbResult, pHash->resultSize ) )  PBYTE           pbResult,
197
                                                                 SIZE_T          cbResult )
198
0
{
199
0
    BYTE    buf[SYMCRYPT_HASH_MAX_RESULT_SIZE];
200
201
0
    _Analysis_assume_( pHash->resultSize <= SYMCRYPT_HASH_MAX_RESULT_SIZE );
202
203
0
    (*pHash->resultFunc)( pState, buf );
204
0
    memcpy( pbResult, buf, SYMCRYPT_MIN( cbResult, pHash->resultSize ));
205
0
    SymCryptWipe( buf, pHash->resultSize );
206
0
}
207
208
VOID
209
SYMCRYPT_CALL
210
SymCryptHashStateCopy(
211
    _In_                                PCSYMCRYPT_HASH pHash,
212
    _In_reads_( pHash->stateSize )      PCVOID          pSrc,
213
    _Out_writes_( pHash->stateSize )    PVOID           pDst)
214
0
{
215
0
    (*pHash->stateCopyFunc)( pSrc, pDst );
216
0
}
217