/src/ms-tpm-20-ref/TPMCmd/tpm/src/crypt/CryptRand.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Microsoft Reference Implementation for TPM 2.0 |
2 | | * |
3 | | * The copyright in this software is being made available under the BSD License, |
4 | | * included below. This software may be subject to other third party and |
5 | | * contributor rights, including patent rights, and no such rights are granted |
6 | | * under this license. |
7 | | * |
8 | | * Copyright (c) Microsoft Corporation |
9 | | * |
10 | | * All rights reserved. |
11 | | * |
12 | | * BSD License |
13 | | * |
14 | | * Redistribution and use in source and binary forms, with or without modification, |
15 | | * are permitted provided that the following conditions are met: |
16 | | * |
17 | | * Redistributions of source code must retain the above copyright notice, this list |
18 | | * of conditions and the following disclaimer. |
19 | | * |
20 | | * Redistributions in binary form must reproduce the above copyright notice, this |
21 | | * list of conditions and the following disclaimer in the documentation and/or |
22 | | * other materials provided with the distribution. |
23 | | * |
24 | | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ""AS IS"" |
25 | | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
26 | | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
27 | | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR |
28 | | * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
29 | | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
30 | | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON |
31 | | * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
32 | | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
33 | | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
34 | | */ |
35 | | //** Introduction |
36 | | // This file implements a DRBG with a behavior according to SP800-90A using |
37 | | // a block cypher. This is also compliant to ISO/IEC 18031:2011(E) C.3.2. |
38 | | // |
39 | | // A state structure is created for use by TPM.lib and functions |
40 | | // within the CryptoEngine my use their own state structures when they need to have |
41 | | // deterministic values. |
42 | | // |
43 | | // A debug mode is available that allows the random numbers generated for TPM.lib |
44 | | // to be repeated during runs of the simulator. The switch for it is in |
45 | | // TpmBuildSwitches.h. It is USE_DEBUG_RNG. |
46 | | // |
47 | | // |
48 | | // This is the implementation layer of CTR DRGB mechanism as defined in SP800-90A |
49 | | // and the functions are organized as closely as practical to the organization in |
50 | | // SP800-90A. It is intended to be compiled as a separate module that is linked |
51 | | // with a secure application so that both reside inside the same boundary |
52 | | // [SP 800-90A 8.5]. The secure application in particular manages the accesses |
53 | | // protected storage for the state of the DRBG instantiations, and supplies the |
54 | | // implementation functions here with a valid pointer to the working state of the |
55 | | // given instantiations (as a DRBG_STATE structure). |
56 | | // |
57 | | // This DRBG mechanism implementation does not support prediction resistance. Thus |
58 | | // 'prediction_resistance_flag' is omitted from Instantiate_function(), |
59 | | // Reseed_function(), Generate_function() argument lists [SP 800-90A 9.1, 9.2, |
60 | | // 9.3], as well as from the working state data structure DRBG_STATE [SP 800-90A |
61 | | // 9.1]. |
62 | | // |
63 | | // This DRBG mechanism implementation always uses the highest security strength of |
64 | | // available in the block ciphers. Thus 'requested_security_strength' parameter is |
65 | | // omitted from Instantiate_function() and Generate_function() argument lists |
66 | | // [SP 800-90A 9.1, 9.2, 9.3], as well as from the working state data structure |
67 | | // DRBG_STATE [SP 800-90A 9.1]. |
68 | | // |
69 | | // Internal functions (ones without Crypt prefix) expect validated arguments and |
70 | | // therefore use assertions instead of runtime parameter checks and mostly return |
71 | | // void instead of a status value. |
72 | | |
73 | | #include "Tpm.h" |
74 | | |
75 | | // Pull in the test vector definitions and define the space |
76 | | #include "PRNG_TestVectors.h" |
77 | | |
78 | | const BYTE DRBG_NistTestVector_Entropy[] = {DRBG_TEST_INITIATE_ENTROPY}; |
79 | | const BYTE DRBG_NistTestVector_GeneratedInterm[] = {DRBG_TEST_GENERATED_INTERM}; |
80 | | |
81 | | const BYTE DRBG_NistTestVector_EntropyReseed[] = {DRBG_TEST_RESEED_ENTROPY}; |
82 | | const BYTE DRBG_NistTestVector_Generated[] = {DRBG_TEST_GENERATED}; |
83 | | |
84 | | //** Derivation Functions |
85 | | //*** Description |
86 | | // The functions in this section are used to reduce the personalization input values |
87 | | // to make them usable as input for reseeding and instantiation. The overall |
88 | | // behavior is intended to produce the same results as described in SP800-90A, |
89 | | // section 10.4.2 "Derivation Function Using a Block Cipher Algorithm |
90 | | // (Block_Cipher_df)." The code is broken into several subroutines to deal with the |
91 | | // fact that the data used for personalization may come in several separate blocks |
92 | | // such as a Template hash and a proof value and a primary seed. |
93 | | |
94 | | //*** Derivation Function Defines and Structures |
95 | | |
96 | 32.6k | #define DF_COUNT (DRBG_KEY_SIZE_WORDS / DRBG_IV_SIZE_WORDS + 1) |
97 | | #if DRBG_KEY_SIZE_BITS != 128 && DRBG_KEY_SIZE_BITS != 256 |
98 | | # error "CryptRand.c only written for AES with 128- or 256-bit keys." |
99 | | #endif |
100 | | |
101 | | typedef struct |
102 | | { |
103 | | DRBG_KEY_SCHEDULE keySchedule; |
104 | | DRBG_IV iv[DF_COUNT]; |
105 | | DRBG_IV out1; |
106 | | DRBG_IV buf; |
107 | | int contents; |
108 | | } DF_STATE, *PDF_STATE; |
109 | | |
110 | | //*** DfCompute() |
111 | | // This function does the incremental update of the derivation function state. It |
112 | | // encrypts the 'iv' value and XOR's the results into each of the blocks of the |
113 | | // output. This is equivalent to processing all of input data for each output block. |
114 | | static void DfCompute(PDF_STATE dfState) |
115 | 7.31k | { |
116 | 7.31k | int i; |
117 | 7.31k | int iv; |
118 | 7.31k | crypt_uword_t* pIv; |
119 | 7.31k | crypt_uword_t temp[DRBG_IV_SIZE_WORDS] = {0}; |
120 | | // |
121 | 29.2k | for(iv = 0; iv < DF_COUNT; iv++) |
122 | 21.9k | { |
123 | 21.9k | pIv = (crypt_uword_t*)&dfState->iv[iv].words[0]; |
124 | 65.8k | for(i = 0; i < DRBG_IV_SIZE_WORDS; i++) |
125 | 43.8k | { |
126 | 43.8k | temp[i] ^= pIv[i] ^ dfState->buf.words[i]; |
127 | 43.8k | } |
128 | 21.9k | DRBG_ENCRYPT(&dfState->keySchedule, &temp, pIv); |
129 | 21.9k | } |
130 | 21.9k | for(i = 0; i < DRBG_IV_SIZE_WORDS; i++) |
131 | 14.6k | dfState->buf.words[i] = 0; |
132 | 7.31k | dfState->contents = 0; |
133 | 7.31k | } |
134 | | |
135 | | //*** DfStart() |
136 | | // This initializes the output blocks with an encrypted counter value and |
137 | | // initializes the key schedule. |
138 | | static void DfStart(PDF_STATE dfState, uint32_t inputLength) |
139 | 842 | { |
140 | 842 | BYTE init[8]; |
141 | 842 | int i; |
142 | 842 | UINT32 drbgSeedSize = sizeof(DRBG_SEED); |
143 | | |
144 | 842 | const BYTE dfKey[DRBG_KEY_SIZE_BYTES] = |
145 | 842 | { 0x00, |
146 | 842 | 0x01, |
147 | 842 | 0x02, |
148 | 842 | 0x03, |
149 | 842 | 0x04, |
150 | 842 | 0x05, |
151 | 842 | 0x06, |
152 | 842 | 0x07, |
153 | 842 | 0x08, |
154 | 842 | 0x09, |
155 | 842 | 0x0a, |
156 | 842 | 0x0b, |
157 | 842 | 0x0c, |
158 | 842 | 0x0d, |
159 | 842 | 0x0e, |
160 | 842 | 0x0f |
161 | 842 | #if DRBG_KEY_SIZE_BYTES > 16 |
162 | 842 | , |
163 | 842 | 0x10, |
164 | 842 | 0x11, |
165 | 842 | 0x12, |
166 | 842 | 0x13, |
167 | 842 | 0x14, |
168 | 842 | 0x15, |
169 | 842 | 0x16, |
170 | 842 | 0x17, |
171 | 842 | 0x18, |
172 | 842 | 0x19, |
173 | 842 | 0x1a, |
174 | 842 | 0x1b, |
175 | 842 | 0x1c, |
176 | 842 | 0x1d, |
177 | 842 | 0x1e, |
178 | 842 | 0x1f |
179 | 842 | #endif |
180 | 842 | }; |
181 | 842 | memset(dfState, 0, sizeof(DF_STATE)); |
182 | 842 | DRBG_ENCRYPT_SETUP(&dfKey[0], DRBG_KEY_SIZE_BITS, &dfState->keySchedule); |
183 | | // Create the first chaining values |
184 | 3.36k | for(i = 0; i < DF_COUNT; i++) |
185 | 2.52k | ((BYTE*)&dfState->iv[i])[3] = (BYTE)i; |
186 | 842 | DfCompute(dfState); |
187 | | // initialize the first 64 bits of the IV in a way that doesn't depend |
188 | | // on the size of the words used. |
189 | 842 | UINT32_TO_BYTE_ARRAY(inputLength, init); |
190 | 842 | UINT32_TO_BYTE_ARRAY(drbgSeedSize, &init[4]); |
191 | 842 | memcpy(&dfState->iv[0], init, 8); |
192 | 842 | dfState->contents = 4; |
193 | 842 | } |
194 | | |
195 | | //*** DfUpdate() |
196 | | // This updates the state with the input data. A byte at a time is moved into the |
197 | | // state buffer until it is full and then that block is encrypted by DfCompute(). |
198 | | static void DfUpdate(PDF_STATE dfState, int size, const BYTE* data) |
199 | 3.05k | { |
200 | 11.0k | while(size > 0) |
201 | 8.00k | { |
202 | 8.00k | int toFill = DRBG_IV_SIZE_BYTES - dfState->contents; |
203 | 8.00k | if(size < toFill) |
204 | 2.37k | toFill = size; |
205 | | // Copy as many bytes as there are or until the state buffer is full |
206 | 8.00k | memcpy(&dfState->buf.bytes[dfState->contents], data, toFill); |
207 | | // Reduce the size left by the amount copied |
208 | 8.00k | size -= toFill; |
209 | | // Advance the data pointer by the amount copied |
210 | 8.00k | data += toFill; |
211 | | // increase the buffer contents count by the amount copied |
212 | 8.00k | dfState->contents += toFill; |
213 | 8.00k | pAssert(dfState->contents <= DRBG_IV_SIZE_BYTES); |
214 | | // If we have a full buffer, do a computation pass. |
215 | 8.00k | if(dfState->contents == DRBG_IV_SIZE_BYTES) |
216 | 5.63k | DfCompute(dfState); |
217 | 8.00k | } |
218 | 3.05k | } |
219 | | |
220 | | //*** DfEnd() |
221 | | // This function is called to get the result of the derivation function computation. |
222 | | // If the buffer is not full, it is padded with zeros. The output buffer is |
223 | | // structured to be the same as a DRBG_SEED value so that the function can return |
224 | | // a pointer to the DRBG_SEED value in the DF_STATE structure. |
225 | | static DRBG_SEED* DfEnd(PDF_STATE dfState) |
226 | 842 | { |
227 | | // Since DfCompute is always called when a buffer is full, there is always |
228 | | // space in the buffer for the terminator |
229 | 842 | dfState->buf.bytes[dfState->contents++] = 0x80; |
230 | | // If the buffer is not full, pad with zeros |
231 | 5.31k | while(dfState->contents < DRBG_IV_SIZE_BYTES) |
232 | 4.46k | dfState->buf.bytes[dfState->contents++] = 0; |
233 | | // Do a final state update |
234 | 842 | DfCompute(dfState); |
235 | 842 | return (DRBG_SEED*)&dfState->iv; |
236 | 842 | } |
237 | | |
238 | | //*** DfBuffer() |
239 | | // Function to take an input buffer and do the derivation function to produce a |
240 | | // DRBG_SEED value that can be used in DRBG_Reseed(); |
241 | | static DRBG_SEED* DfBuffer(DRBG_SEED* output, // OUT: receives the result |
242 | | int size, // IN: size of the buffer to add |
243 | | BYTE* buf // IN: address of the buffer |
244 | | ) |
245 | 8.41k | { |
246 | 8.41k | DF_STATE dfState; |
247 | 8.41k | if(size == 0 || buf == NULL) |
248 | 8.30k | return NULL; |
249 | | // Initialize the derivation function |
250 | 104 | DfStart(&dfState, size); |
251 | 104 | DfUpdate(&dfState, size, buf); |
252 | 104 | DfEnd(&dfState); |
253 | 104 | memcpy(output, &dfState.iv[0], sizeof(DRBG_SEED)); |
254 | 104 | return output; |
255 | 8.41k | } |
256 | | |
257 | | //*** DRBG_GetEntropy() |
258 | | // Even though this implementation never fails, it may get blocked |
259 | | // indefinitely long in the call to get entropy from the platform |
260 | | // (DRBG_GetEntropy32()). |
261 | | // This function is only used during instantiation of the DRBG for |
262 | | // manufacturing and on each start-up after an non-orderly shutdown. |
263 | | // |
264 | | // Return Type: BOOL |
265 | | // TRUE(1) requested entropy returned |
266 | | // FALSE(0) entropy Failure |
267 | | BOOL DRBG_GetEntropy(UINT32 requiredEntropy, // IN: requested number of bytes of full |
268 | | // entropy |
269 | | BYTE* entropy // OUT: buffer to return collected entropy |
270 | | ) |
271 | 24.9k | { |
272 | 24.9k | #if !USE_DEBUG_RNG |
273 | | |
274 | 24.9k | UINT32 obtainedEntropy; |
275 | 24.9k | INT32 returnedEntropy; |
276 | | |
277 | | // If in debug mode, always use the self-test values for initialization |
278 | 24.9k | if(IsSelfTest()) |
279 | 8.29k | { |
280 | 8.29k | #endif |
281 | | // If doing simulated DRBG, then check to see if the |
282 | | // entropyFailure condition is being tested |
283 | 8.29k | if(!IsEntropyBad()) |
284 | 8.29k | { |
285 | | // In self-test, the caller should be asking for exactly the seed |
286 | | // size of entropy. |
287 | 8.29k | pAssert(requiredEntropy == sizeof(DRBG_NistTestVector_Entropy)); |
288 | 8.29k | memcpy(entropy, |
289 | 8.29k | DRBG_NistTestVector_Entropy, |
290 | 8.29k | sizeof(DRBG_NistTestVector_Entropy)); |
291 | 8.29k | } |
292 | 8.29k | #if !USE_DEBUG_RNG |
293 | 8.29k | } |
294 | 16.6k | else if(!IsEntropyBad()) |
295 | 8.37k | { |
296 | | // Collect entropy |
297 | | // Note: In debug mode, the only "entropy" value ever returned |
298 | | // is the value of the self-test vector. |
299 | 8.37k | for(returnedEntropy = 1, obtainedEntropy = 0; |
300 | 108k | obtainedEntropy < requiredEntropy && !IsEntropyBad(); |
301 | 100k | obtainedEntropy += returnedEntropy) |
302 | 100k | { |
303 | 100k | returnedEntropy = _plat__GetEntropy(&entropy[obtainedEntropy], |
304 | 100k | requiredEntropy - obtainedEntropy); |
305 | 100k | if(returnedEntropy <= 0) |
306 | 100k | SetEntropyBad(); |
307 | 100k | } |
308 | 8.37k | } |
309 | 24.9k | #endif |
310 | 24.9k | return !IsEntropyBad(); |
311 | 24.9k | } |
312 | | |
313 | | //*** IncrementIv() |
314 | | // This function increments the IV value by 1. It is used by EncryptDRBG(). |
315 | | void IncrementIv(DRBG_IV* iv) |
316 | 657k | { |
317 | 657k | BYTE* ivP = ((BYTE*)iv) + DRBG_IV_SIZE_BYTES; |
318 | 659k | while((--ivP >= (BYTE*)iv) && ((*ivP = ((*ivP + 1) & 0xFF)) == 0)) |
319 | 2.13k | ; |
320 | 657k | } |
321 | | |
322 | | //*** EncryptDRBG() |
323 | | // This does the encryption operation for the DRBG. It will encrypt |
324 | | // the input state counter (IV) using the state key. Into the output |
325 | | // buffer for as many times as it takes to generate the required |
326 | | // number of bytes. |
327 | | static BOOL EncryptDRBG(BYTE* dOut, |
328 | | UINT32 dOutBytes, |
329 | | DRBG_KEY_SCHEDULE* keySchedule, |
330 | | DRBG_IV* iv, |
331 | | UINT32* lastValue // Points to the last output value |
332 | | ) |
333 | 177k | { |
334 | 177k | #if FIPS_COMPLIANT |
335 | | // For FIPS compliance, the DRBG has to do a continuous self-test to make sure that |
336 | | // no two consecutive values are the same. This overhead is not incurred if the TPM |
337 | | // is not required to be FIPS compliant |
338 | | // |
339 | 177k | UINT32 temp[DRBG_IV_SIZE_BYTES / sizeof(UINT32)]; |
340 | 177k | int i; |
341 | 177k | BYTE* p; |
342 | | |
343 | 834k | for(; dOutBytes > 0;) |
344 | 657k | { |
345 | | // Increment the IV before each encryption (this is what makes this |
346 | | // different from normal counter-mode encryption |
347 | 657k | IncrementIv(iv); |
348 | 657k | DRBG_ENCRYPT(keySchedule, iv, temp); |
349 | | // Expect a 16 byte block |
350 | | # if DRBG_IV_SIZE_BITS != 128 |
351 | | # error "Unsuppored IV size in DRBG" |
352 | | # endif |
353 | 657k | if((lastValue[0] == temp[0]) && (lastValue[1] == temp[1]) |
354 | 657k | && (lastValue[2] == temp[2]) && (lastValue[3] == temp[3])) |
355 | 0 | { |
356 | 0 | LOG_FAILURE(FATAL_ERROR_ENTROPY); |
357 | 0 | return FALSE; |
358 | 0 | } |
359 | 657k | lastValue[0] = temp[0]; |
360 | 657k | lastValue[1] = temp[1]; |
361 | 657k | lastValue[2] = temp[2]; |
362 | 657k | lastValue[3] = temp[3]; |
363 | 657k | i = MIN(dOutBytes, DRBG_IV_SIZE_BYTES); |
364 | 657k | dOutBytes -= i; |
365 | 11.1M | for(p = (BYTE*)temp; i > 0; i--) |
366 | 10.5M | *dOut++ = *p++; |
367 | 657k | } |
368 | | #else // version without continuous self-test |
369 | | NOT_REFERENCED(lastValue); |
370 | | for(; dOutBytes >= DRBG_IV_SIZE_BYTES; |
371 | | dOut = &dOut[DRBG_IV_SIZE_BYTES], dOutBytes -= DRBG_IV_SIZE_BYTES) |
372 | | { |
373 | | // Increment the IV |
374 | | IncrementIv(iv); |
375 | | DRBG_ENCRYPT(keySchedule, iv, dOut); |
376 | | } |
377 | | // If there is a partial, generate into a block-sized |
378 | | // temp buffer and copy to the output. |
379 | | if(dOutBytes != 0) |
380 | | { |
381 | | BYTE temp[DRBG_IV_SIZE_BYTES]; |
382 | | // Increment the IV |
383 | | IncrementIv(iv); |
384 | | DRBG_ENCRYPT(keySchedule, iv, temp); |
385 | | memcpy(dOut, temp, dOutBytes); |
386 | | } |
387 | | #endif |
388 | 177k | return TRUE; |
389 | 177k | } |
390 | | |
391 | | //*** DRBG_Update() |
392 | | // This function performs the state update function. |
393 | | // According to SP800-90A, a temp value is created by doing CTR mode |
394 | | // encryption of 'providedData' and replacing the key and IV with |
395 | | // these values. The one difference is that, with counter mode, the |
396 | | // IV is incremented after each block is encrypted and in this |
397 | | // operation, the counter is incremented before each block is |
398 | | // encrypted. This function implements an 'optimized' version |
399 | | // of the algorithm in that it does the update of the drbgState->seed |
400 | | // in place and then 'providedData' is XORed into drbgState->seed |
401 | | // to complete the encryption of 'providedData'. This works because |
402 | | // the IV is the last thing that gets encrypted. |
403 | | // |
404 | | static BOOL DRBG_Update( |
405 | | DRBG_STATE* drbgState, // IN:OUT state to update |
406 | | DRBG_KEY_SCHEDULE* keySchedule, // IN: the key schedule (optional) |
407 | | DRBG_SEED* providedData // IN: additional data |
408 | | ) |
409 | 101k | { |
410 | 101k | UINT32 i; |
411 | 101k | BYTE* temp = (BYTE*)&drbgState->seed; |
412 | 101k | DRBG_KEY* key = pDRBG_KEY(&drbgState->seed); |
413 | 101k | DRBG_IV* iv = pDRBG_IV(&drbgState->seed); |
414 | 101k | DRBG_KEY_SCHEDULE localKeySchedule; |
415 | | // |
416 | 101k | pAssert(drbgState->magic == DRBG_MAGIC); |
417 | | |
418 | | // If an key schedule was not provided, make one |
419 | 101k | if(keySchedule == NULL) |
420 | 25.7k | { |
421 | 25.7k | if(DRBG_ENCRYPT_SETUP((BYTE*)key, DRBG_KEY_SIZE_BITS, &localKeySchedule) != 0) |
422 | 0 | { |
423 | 0 | LOG_FAILURE(FATAL_ERROR_INTERNAL); |
424 | 0 | return FALSE; |
425 | 0 | } |
426 | 25.7k | keySchedule = &localKeySchedule; |
427 | 25.7k | } |
428 | | // Encrypt the temp value |
429 | | |
430 | 101k | EncryptDRBG(temp, sizeof(DRBG_SEED), keySchedule, iv, drbgState->lastValue); |
431 | 101k | if(providedData != NULL) |
432 | 25.7k | { |
433 | 25.7k | BYTE* pP = (BYTE*)providedData; |
434 | 1.26M | for(i = DRBG_SEED_SIZE_BYTES; i != 0; i--) |
435 | 1.23M | *temp++ ^= *pP++; |
436 | 25.7k | } |
437 | | // Since temp points to the input key and IV, we are done and |
438 | | // don't need to copy the resulting 'temp' to drbgState->seed |
439 | 101k | return TRUE; |
440 | 101k | } |
441 | | |
442 | | //*** DRBG_Reseed() |
443 | | // This function is used when reseeding of the DRBG is required. If |
444 | | // entropy is provided, it is used in lieu of using hardware entropy. |
445 | | // Note: the provided entropy must be the required size. |
446 | | // |
447 | | // Return Type: BOOL |
448 | | // TRUE(1) reseed succeeded |
449 | | // FALSE(0) reseed failed, probably due to the entropy generation |
450 | | BOOL DRBG_Reseed(DRBG_STATE* drbgState, // IN: the state to update |
451 | | DRBG_SEED* providedEntropy, // IN: entropy |
452 | | DRBG_SEED* additionalData // IN: |
453 | | ) |
454 | 25.7k | { |
455 | 25.7k | DRBG_SEED seed; |
456 | | |
457 | 25.7k | pAssert((drbgState != NULL) && (drbgState->magic == DRBG_MAGIC)); |
458 | | |
459 | 25.7k | if(providedEntropy == NULL) |
460 | 8.29k | { |
461 | 8.29k | providedEntropy = &seed; |
462 | 8.29k | if(!DRBG_GetEntropy(sizeof(DRBG_SEED), (BYTE*)providedEntropy)) |
463 | 0 | return FALSE; |
464 | 8.29k | } |
465 | 25.7k | if(additionalData != NULL) |
466 | 66 | { |
467 | 66 | unsigned int i; |
468 | | |
469 | | // XOR the provided data into the provided entropy |
470 | 3.23k | for(i = 0; i < sizeof(DRBG_SEED); i++) |
471 | 3.16k | ((BYTE*)providedEntropy)[i] ^= ((BYTE*)additionalData)[i]; |
472 | 66 | } |
473 | 25.7k | DRBG_Update(drbgState, NULL, providedEntropy); |
474 | | |
475 | 25.7k | drbgState->reseedCounter = 1; |
476 | | |
477 | 25.7k | return TRUE; |
478 | 25.7k | } |
479 | | |
480 | | //*** DRBG_SelfTest() |
481 | | // This is run when the DRBG is instantiated and at startup. |
482 | | // |
483 | | // Return Type: BOOL |
484 | | // TRUE(1) test OK |
485 | | // FALSE(0) test failed |
486 | | BOOL DRBG_SelfTest(void) |
487 | 8.29k | { |
488 | 8.29k | BYTE buf[sizeof(DRBG_NistTestVector_Generated)]; |
489 | 8.29k | DRBG_SEED seed; |
490 | 8.29k | UINT32 i; |
491 | 8.29k | BYTE* p; |
492 | 8.29k | DRBG_STATE testState; |
493 | | // |
494 | 8.29k | pAssert(!IsSelfTest()); |
495 | | |
496 | 8.29k | SetSelfTest(); |
497 | 8.29k | SetDrbgTested(); |
498 | | // Do an instantiate |
499 | 8.29k | if(!DRBG_Instantiate(&testState, 0, NULL)) |
500 | 0 | return FALSE; |
501 | | #if DRBG_DEBUG_PRINT |
502 | | dbgDumpMemBlock( |
503 | | pDRBG_KEY(&testState), DRBG_KEY_SIZE_BYTES, "Key after Instantiate"); |
504 | | dbgDumpMemBlock( |
505 | | pDRBG_IV(&testState), DRBG_IV_SIZE_BYTES, "Value after Instantiate"); |
506 | | #endif |
507 | 8.29k | if(DRBG_Generate((RAND_STATE*)&testState, buf, sizeof(buf)) == 0) |
508 | 0 | return FALSE; |
509 | | #if DRBG_DEBUG_PRINT |
510 | | dbgDumpMemBlock( |
511 | | pDRBG_KEY(&testState.seed), DRBG_KEY_SIZE_BYTES, "Key after 1st Generate"); |
512 | | dbgDumpMemBlock( |
513 | | pDRBG_IV(&testState.seed), DRBG_IV_SIZE_BYTES, "Value after 1st Generate"); |
514 | | #endif |
515 | 8.29k | if(memcmp(buf, DRBG_NistTestVector_GeneratedInterm, sizeof(buf)) != 0) |
516 | 0 | return FALSE; |
517 | 8.29k | memcpy(seed.bytes, DRBG_NistTestVector_EntropyReseed, sizeof(seed)); |
518 | 8.29k | DRBG_Reseed(&testState, &seed, NULL); |
519 | | #if DRBG_DEBUG_PRINT |
520 | | dbgDumpMemBlock((BYTE*)pDRBG_KEY(&testState.seed), |
521 | | DRBG_KEY_SIZE_BYTES, |
522 | | "Key after 2nd Generate"); |
523 | | dbgDumpMemBlock((BYTE*)pDRBG_IV(&testState.seed), |
524 | | DRBG_IV_SIZE_BYTES, |
525 | | "Value after 2nd Generate"); |
526 | | dbgDumpMemBlock(buf, sizeof(buf), "2nd Generated"); |
527 | | #endif |
528 | 8.29k | if(DRBG_Generate((RAND_STATE*)&testState, buf, sizeof(buf)) == 0) |
529 | 0 | return FALSE; |
530 | 8.29k | if(memcmp(buf, DRBG_NistTestVector_Generated, sizeof(buf)) != 0) |
531 | 0 | return FALSE; |
532 | 8.29k | ClearSelfTest(); |
533 | | |
534 | 8.29k | DRBG_Uninstantiate(&testState); |
535 | 672k | for(p = (BYTE*)&testState, i = 0; i < sizeof(DRBG_STATE); i++) |
536 | 663k | { |
537 | 663k | if(*p++) |
538 | 0 | return FALSE; |
539 | 663k | } |
540 | | // Simulate hardware failure to make sure that we get an error when |
541 | | // trying to instantiate |
542 | 8.29k | SetEntropyBad(); |
543 | 8.29k | if(DRBG_Instantiate(&testState, 0, NULL)) |
544 | 0 | return FALSE; |
545 | 8.29k | ClearEntropyBad(); |
546 | | |
547 | 8.29k | return TRUE; |
548 | 8.29k | } |
549 | | |
550 | | //** Public Interface |
551 | | //*** Description |
552 | | // The functions in this section are the interface to the RNG. These |
553 | | // are the functions that are used by TPM.lib. |
554 | | |
555 | | //*** CryptRandomStir() |
556 | | // This function is used to cause a reseed. A DRBG_SEED amount of entropy is |
557 | | // collected from the hardware and then additional data is added. |
558 | | // |
559 | | // Return Type: TPM_RC |
560 | | // TPM_RC_NO_RESULT failure of the entropy generator |
561 | | LIB_EXPORT TPM_RC CryptRandomStir(UINT16 additionalDataSize, BYTE* additionalData) |
562 | 72 | { |
563 | 72 | #if !USE_DEBUG_RNG |
564 | 72 | DRBG_SEED tmpBuf; |
565 | 72 | DRBG_SEED dfResult; |
566 | | // |
567 | | // All reseed with outside data starts with a buffer full of entropy |
568 | 72 | if(!DRBG_GetEntropy(sizeof(tmpBuf), (BYTE*)&tmpBuf)) |
569 | 0 | return TPM_RC_NO_RESULT; |
570 | | |
571 | 72 | DRBG_Reseed(&drbgDefault, |
572 | 72 | &tmpBuf, |
573 | 72 | DfBuffer(&dfResult, additionalDataSize, additionalData)); |
574 | 72 | drbgDefault.reseedCounter = 1; |
575 | | |
576 | 72 | return TPM_RC_SUCCESS; |
577 | | |
578 | | #else |
579 | | // If doing debug, use the input data as the initial setting for the RNG state |
580 | | // so that the test can be reset at any time. |
581 | | // Note: If this is called with a data size of 0 or less, nothing happens. The |
582 | | // presumption is that, in a debug environment, the caller will have specific |
583 | | // values for initialization, so this check is just a simple way to prevent |
584 | | // inadvertent programming errors from screwing things up. This doesn't use an |
585 | | // pAssert() because the non-debug version of this function will accept these |
586 | | // parameters as meaning that there is no additionalData and only hardware |
587 | | // entropy is used. |
588 | | if((additionalDataSize > 0) && (additionalData != NULL)) |
589 | | { |
590 | | memset(drbgDefault.seed.bytes, 0, sizeof(drbgDefault.seed.bytes)); |
591 | | memcpy(drbgDefault.seed.bytes, |
592 | | additionalData, |
593 | | MIN(additionalDataSize, sizeof(drbgDefault.seed.bytes))); |
594 | | } |
595 | | drbgDefault.reseedCounter = 1; |
596 | | |
597 | | return TPM_RC_SUCCESS; |
598 | | #endif |
599 | 72 | } |
600 | | |
601 | | //*** CryptRandomGenerate() |
602 | | // Generate a 'randomSize' number or random bytes. |
603 | | LIB_EXPORT UINT16 CryptRandomGenerate(UINT16 randomSize, BYTE* buffer) |
604 | 25.6k | { |
605 | 25.6k | return DRBG_Generate((RAND_STATE*)&drbgDefault, buffer, randomSize); |
606 | 25.6k | } |
607 | | |
608 | | //*** DRBG_InstantiateSeededKdf() |
609 | | // This function is used to instantiate a KDF-based RNG. This is used for derivations. |
610 | | // This function always returns TRUE. |
611 | | LIB_EXPORT BOOL DRBG_InstantiateSeededKdf( |
612 | | KDF_STATE* state, // OUT: buffer to hold the state |
613 | | TPM_ALG_ID hashAlg, // IN: hash algorithm |
614 | | TPM_ALG_ID kdf, // IN: the KDF to use |
615 | | TPM2B* seed, // IN: the seed to use |
616 | | const TPM2B* label, // IN: a label for the generation process. |
617 | | TPM2B* context, // IN: the context value |
618 | | UINT32 limit // IN: Maximum number of bits from the KDF |
619 | | ) |
620 | 0 | { |
621 | 0 | state->magic = KDF_MAGIC; |
622 | 0 | state->limit = limit; |
623 | 0 | state->seed = seed; |
624 | 0 | state->hash = hashAlg; |
625 | 0 | state->kdf = kdf; |
626 | 0 | state->label = label; |
627 | 0 | state->context = context; |
628 | 0 | state->digestSize = CryptHashGetDigestSize(hashAlg); |
629 | 0 | state->counter = 0; |
630 | 0 | state->residual.t.size = 0; |
631 | 0 | return TRUE; |
632 | 0 | } |
633 | | |
634 | | //*** DRBG_AdditionalData() |
635 | | // Function to reseed the DRBG with additional entropy. This is normally called |
636 | | // before computing the protection value of a primary key in the Endorsement |
637 | | // hierarchy. |
638 | | LIB_EXPORT void DRBG_AdditionalData(DRBG_STATE* drbgState, // IN:OUT state to update |
639 | | TPM2B* additionalData // IN: value to incorporate |
640 | | ) |
641 | 38 | { |
642 | 38 | DRBG_SEED dfResult; |
643 | 38 | if(drbgState->magic == DRBG_MAGIC) |
644 | 38 | { |
645 | 38 | DfBuffer(&dfResult, additionalData->size, additionalData->buffer); |
646 | 38 | DRBG_Reseed(drbgState, &dfResult, NULL); |
647 | 38 | } |
648 | 38 | } |
649 | | |
650 | | //*** DRBG_InstantiateSeeded() |
651 | | // This function is used to instantiate a random number generator from seed values. |
652 | | // The nominal use of this generator is to create sequences of pseudo-random |
653 | | // numbers from a seed value. |
654 | | // |
655 | | // Return Type: TPM_RC |
656 | | // TPM_RC_FAILURE DRBG self-test failure |
657 | | LIB_EXPORT TPM_RC DRBG_InstantiateSeeded( |
658 | | DRBG_STATE* drbgState, // IN/OUT: buffer to hold the state |
659 | | const TPM2B* seed, // IN: the seed to use |
660 | | const TPM2B* purpose, // IN: a label for the generation process. |
661 | | const TPM2B* name, // IN: name of the object |
662 | | const TPM2B* additional // IN: additional data |
663 | | ) |
664 | 738 | { |
665 | 738 | DF_STATE dfState; |
666 | 738 | int totalInputSize; |
667 | | // DRBG should have been tested, but... |
668 | 738 | if(!IsDrbgTested() && !DRBG_SelfTest()) |
669 | 0 | { |
670 | 0 | LOG_FAILURE(FATAL_ERROR_SELF_TEST); |
671 | 0 | return TPM_RC_FAILURE; |
672 | 0 | } |
673 | | // Initialize the DRBG state |
674 | 738 | memset(drbgState, 0, sizeof(DRBG_STATE)); |
675 | 738 | drbgState->magic = DRBG_MAGIC; |
676 | | |
677 | | // Size all of the values |
678 | 738 | totalInputSize = (seed != NULL) ? seed->size : 0; |
679 | 738 | totalInputSize += (purpose != NULL) ? purpose->size : 0; |
680 | 738 | totalInputSize += (name != NULL) ? name->size : 0; |
681 | 738 | totalInputSize += (additional != NULL) ? additional->size : 0; |
682 | | |
683 | | // Initialize the derivation |
684 | 738 | DfStart(&dfState, totalInputSize); |
685 | | |
686 | | // Run all the input strings through the derivation function |
687 | 738 | if(seed != NULL) |
688 | 738 | DfUpdate(&dfState, seed->size, seed->buffer); |
689 | 738 | if(purpose != NULL) |
690 | 738 | DfUpdate(&dfState, purpose->size, purpose->buffer); |
691 | 738 | if(name != NULL) |
692 | 738 | DfUpdate(&dfState, name->size, name->buffer); |
693 | 738 | if(additional != NULL) |
694 | 738 | DfUpdate(&dfState, additional->size, additional->buffer); |
695 | | |
696 | | // Used the derivation function output as the "entropy" input. This is not |
697 | | // how it is described in SP800-90A but this is the equivalent function |
698 | 738 | DRBG_Reseed(((DRBG_STATE*)drbgState), DfEnd(&dfState), NULL); |
699 | | |
700 | 738 | return TPM_RC_SUCCESS; |
701 | 738 | } |
702 | | |
703 | | //*** CryptRandStartup() |
704 | | // This function is called when TPM_Startup is executed. This function always returns |
705 | | // TRUE. |
706 | | LIB_EXPORT BOOL CryptRandStartup(void) |
707 | 8.29k | { |
708 | | #if !_DRBG_STATE_SAVE |
709 | | // If not saved in NV, re-instantiate on each startup |
710 | | return DRBG_Instantiate(&drbgDefault, 0, NULL); |
711 | | #else |
712 | | // If the running state is saved in NV, NV has to be loaded before it can |
713 | | // be updated |
714 | 8.29k | if(go.drbgState.magic == DRBG_MAGIC) |
715 | 8.29k | return DRBG_Reseed(&go.drbgState, NULL, NULL); |
716 | 2 | else |
717 | 2 | return DRBG_Instantiate(&go.drbgState, 0, NULL); |
718 | 8.29k | #endif |
719 | 8.29k | } |
720 | | |
721 | | //*** CryptRandInit() |
722 | | // This function is called when _TPM_Init is being processed. |
723 | | // |
724 | | // Return Type: BOOL |
725 | | // TRUE(1) success |
726 | | // FALSE(0) failure |
727 | | LIB_EXPORT BOOL CryptRandInit(void) |
728 | 8.29k | { |
729 | 8.29k | #if !USE_DEBUG_RNG |
730 | 8.29k | _plat__GetEntropy(NULL, 0); |
731 | 8.29k | #endif |
732 | 8.29k | return DRBG_SelfTest(); |
733 | 8.29k | } |
734 | | |
735 | | //*** DRBG_Generate() |
736 | | // This function generates a random sequence according SP800-90A. |
737 | | // If 'random' is not NULL, then 'randomSize' bytes of random values are generated. |
738 | | // If 'random' is NULL or 'randomSize' is zero, then the function returns |
739 | | // zero without generating any bits or updating the reseed counter. |
740 | | // This function returns the number of bytes produced which could be less than the |
741 | | // number requested if the request is too large ("too large" is implementation |
742 | | // dependent.) |
743 | | LIB_EXPORT UINT16 DRBG_Generate( |
744 | | RAND_STATE* state, |
745 | | BYTE* random, // OUT: buffer to receive the random values |
746 | | UINT16 randomSize // IN: the number of bytes to generate |
747 | | ) |
748 | 75.8k | { |
749 | 75.8k | if(state == NULL) |
750 | 2.89k | state = (RAND_STATE*)&drbgDefault; |
751 | 75.8k | if(random == NULL) |
752 | 0 | return 0; |
753 | | |
754 | | // If the caller used a KDF state, generate a sequence from the KDF not to |
755 | | // exceed the limit. |
756 | 75.8k | if(state->kdf.magic == KDF_MAGIC) |
757 | 0 | { |
758 | 0 | KDF_STATE* kdf = (KDF_STATE*)state; |
759 | 0 | UINT32 counter = (UINT32)kdf->counter; |
760 | 0 | INT32 bytesLeft = randomSize; |
761 | | // |
762 | | // If the number of bytes to be returned would put the generator |
763 | | // over the limit, then return 0 |
764 | 0 | if((((kdf->counter * kdf->digestSize) + randomSize) * 8) > kdf->limit) |
765 | 0 | return 0; |
766 | | // Process partial and full blocks until all requested bytes provided |
767 | 0 | while(bytesLeft > 0) |
768 | 0 | { |
769 | | // If there is any residual data in the buffer, copy it to the output |
770 | | // buffer |
771 | 0 | if(kdf->residual.t.size > 0) |
772 | 0 | { |
773 | 0 | INT32 size; |
774 | | // |
775 | | // Don't use more of the residual than will fit or more than are |
776 | | // available |
777 | 0 | size = MIN(kdf->residual.t.size, bytesLeft); |
778 | | |
779 | | // Copy some or all of the residual to the output. The residual is |
780 | | // at the end of the buffer. The residual might be a full buffer. |
781 | 0 | MemoryCopy( |
782 | 0 | random, |
783 | 0 | &kdf->residual.t.buffer[kdf->digestSize - kdf->residual.t.size], |
784 | 0 | size); |
785 | | |
786 | | // Advance the buffer pointer |
787 | 0 | random += size; |
788 | | |
789 | | // Reduce the number of bytes left to get |
790 | 0 | bytesLeft -= size; |
791 | | |
792 | | // And reduce the residual size appropriately |
793 | 0 | kdf->residual.t.size -= (UINT16)size; |
794 | 0 | } |
795 | 0 | else |
796 | 0 | { |
797 | 0 | UINT16 blocks = (UINT16)(bytesLeft / kdf->digestSize); |
798 | | // |
799 | | // Get the number of required full blocks |
800 | 0 | if(blocks > 0) |
801 | 0 | { |
802 | 0 | UINT16 size = blocks * kdf->digestSize; |
803 | | // Get some number of full blocks and put them in the return buffer |
804 | 0 | CryptKDFa(kdf->hash, |
805 | 0 | kdf->seed, |
806 | 0 | kdf->label, |
807 | 0 | kdf->context, |
808 | 0 | NULL, |
809 | 0 | kdf->limit, |
810 | 0 | random, |
811 | 0 | &counter, |
812 | 0 | blocks); |
813 | | |
814 | | // reduce the size remaining to be moved and advance the pointer |
815 | 0 | bytesLeft -= size; |
816 | 0 | random += size; |
817 | 0 | } |
818 | 0 | else |
819 | 0 | { |
820 | | // Fill the residual buffer with a full block and then loop to |
821 | | // top to get part of it copied to the output. |
822 | 0 | kdf->residual.t.size = CryptKDFa(kdf->hash, |
823 | 0 | kdf->seed, |
824 | 0 | kdf->label, |
825 | 0 | kdf->context, |
826 | 0 | NULL, |
827 | 0 | kdf->limit, |
828 | 0 | kdf->residual.t.buffer, |
829 | 0 | &counter, |
830 | 0 | 1); |
831 | 0 | } |
832 | 0 | } |
833 | 0 | } |
834 | 0 | kdf->counter = counter; |
835 | 0 | return randomSize; |
836 | 0 | } |
837 | 75.8k | else if(state->drbg.magic == DRBG_MAGIC) |
838 | 75.8k | { |
839 | 75.8k | DRBG_STATE* drbgState = (DRBG_STATE*)state; |
840 | 75.8k | DRBG_KEY_SCHEDULE keySchedule; |
841 | 75.8k | DRBG_SEED* seed = &drbgState->seed; |
842 | | |
843 | 75.8k | if(drbgState->reseedCounter >= CTR_DRBG_MAX_REQUESTS_PER_RESEED) |
844 | 0 | { |
845 | 0 | if(drbgState == &drbgDefault) |
846 | 0 | { |
847 | 0 | DRBG_Reseed(drbgState, NULL, NULL); |
848 | 0 | if(IsEntropyBad() && !IsSelfTest()) |
849 | 0 | return 0; |
850 | 0 | } |
851 | 0 | else |
852 | 0 | { |
853 | | // If this is a PRNG then the only way to get |
854 | | // here is if the SW has run away. |
855 | 0 | LOG_FAILURE(FATAL_ERROR_INTERNAL); |
856 | 0 | return 0; |
857 | 0 | } |
858 | 0 | } |
859 | | // if the allowed number of bytes in a request is larger than the |
860 | | // less than the number of bytes that can be requested, then check |
861 | | #if UINT16_MAX >= CTR_DRBG_MAX_BYTES_PER_REQUEST |
862 | | if(randomSize > CTR_DRBG_MAX_BYTES_PER_REQUEST) |
863 | | randomSize = CTR_DRBG_MAX_BYTES_PER_REQUEST; |
864 | | #endif |
865 | | // Create encryption schedule |
866 | 75.8k | if(DRBG_ENCRYPT_SETUP( |
867 | 75.8k | (BYTE*)pDRBG_KEY(seed), DRBG_KEY_SIZE_BITS, &keySchedule) |
868 | 75.8k | != 0) |
869 | 0 | { |
870 | 0 | LOG_FAILURE(FATAL_ERROR_INTERNAL); |
871 | 0 | return 0; |
872 | 0 | } |
873 | | // Generate the random data |
874 | 75.8k | EncryptDRBG( |
875 | 75.8k | random, randomSize, &keySchedule, pDRBG_IV(seed), drbgState->lastValue); |
876 | | // Do a key update |
877 | 75.8k | DRBG_Update(drbgState, &keySchedule, NULL); |
878 | | |
879 | | // Increment the reseed counter |
880 | 75.8k | drbgState->reseedCounter += 1; |
881 | 75.8k | } |
882 | 0 | else |
883 | 0 | { |
884 | 0 | LOG_FAILURE(FATAL_ERROR_INTERNAL); |
885 | 0 | return FALSE; |
886 | 0 | } |
887 | 75.8k | return randomSize; |
888 | 75.8k | } |
889 | | |
890 | | //*** DRBG_Instantiate() |
891 | | // This is CTR_DRBG_Instantiate_algorithm() from [SP 800-90A 10.2.1.3.1]. |
892 | | // This is called when a the TPM DRBG is to be instantiated. This is |
893 | | // called to instantiate a DRBG used by the TPM for normal |
894 | | // operations. |
895 | | // |
896 | | // Return Type: BOOL |
897 | | // TRUE(1) instantiation succeeded |
898 | | // FALSE(0) instantiation failed |
899 | | LIB_EXPORT BOOL DRBG_Instantiate( |
900 | | DRBG_STATE* drbgState, // OUT: the instantiated value |
901 | | UINT16 pSize, // IN: Size of personalization string |
902 | | BYTE* personalization // IN: The personalization string |
903 | | ) |
904 | 16.6k | { |
905 | 16.6k | DRBG_SEED seed; |
906 | 16.6k | DRBG_SEED dfResult; |
907 | | // |
908 | 16.6k | pAssert((pSize == 0) || (pSize <= sizeof(seed)) || (personalization != NULL)); |
909 | | // If the DRBG has not been tested, test when doing an instantiation. Since |
910 | | // Instantiation is called during self test, make sure we don't get stuck in a |
911 | | // loop. |
912 | 16.6k | if(!IsDrbgTested() && !IsSelfTest() && !DRBG_SelfTest()) |
913 | 0 | return FALSE; |
914 | | // If doing a self test, DRBG_GetEntropy will return the NIST |
915 | | // test vector value. |
916 | 16.6k | if(!DRBG_GetEntropy(sizeof(seed), (BYTE*)&seed)) |
917 | 8.29k | return FALSE; |
918 | | // set everything to zero |
919 | 8.30k | memset(drbgState, 0, sizeof(DRBG_STATE)); |
920 | 8.30k | drbgState->magic = DRBG_MAGIC; |
921 | | |
922 | | // Steps 1, 2, 3, 6, 7 of SP 800-90A 10.2.1.3.1 are exactly what |
923 | | // reseeding does. So, do a reduction on the personalization value (if any) |
924 | | // and do a reseed. |
925 | 8.30k | DRBG_Reseed(drbgState, &seed, DfBuffer(&dfResult, pSize, personalization)); |
926 | | |
927 | 8.30k | return TRUE; |
928 | 16.6k | } |
929 | | |
930 | | //*** DRBG_Uninstantiate() |
931 | | // This is Uninstantiate_function() from [SP 800-90A 9.4]. |
932 | | // |
933 | | // Return Type: TPM_RC |
934 | | // TPM_RC_VALUE not a valid state |
935 | | LIB_EXPORT TPM_RC DRBG_Uninstantiate( |
936 | | DRBG_STATE* drbgState // IN/OUT: working state to erase |
937 | | ) |
938 | 8.29k | { |
939 | 8.29k | if((drbgState == NULL) || (drbgState->magic != DRBG_MAGIC)) |
940 | 0 | return TPM_RC_VALUE; |
941 | 8.29k | memset(drbgState, 0, sizeof(DRBG_STATE)); |
942 | 8.29k | return TPM_RC_SUCCESS; |
943 | 8.29k | } |