1 /*
2 * Copyright (c) 2001-2019, Arm Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7
8 /************* Include Files ****************/
9 #include <stdint.h>
10 #include <string.h>
11 #include "cc_pal_log.h"
12 #include "cc_prod_error.h"
13 #include "prod_hw_defs.h"
14 #include "prod_crypto_driver.h"
15 #include "cmpu_derivation.h"
16 #include "cc_pal_mem.h"
17 #include "llf_rnd.h"
18 #include "driver_defs.h"
19
20
21 /* Description: Implementation of CTR_DRBG_Generate_algorithm, Taken from NIST SP800-90A, section 10.4.2
22 Parameters:
23 pInputBuff[IN] - the seed_material with some additional bytes to avoid copy of large buffers
24 actualInputDataSize[IN] - the actual size of teh seed without teh additions
25 pOutputBuff[OUT] - the generated buffer - 32 bytes
26 */
Derivation_Block_Cipher_df(uint32_t * pInputBuff,uint32_t actualInputDataSize,uint32_t * pOutput)27 static uint32_t Derivation_Block_Cipher_df(uint32_t *pInputBuff,
28 uint32_t actualInputDataSize,
29 uint32_t *pOutput)
30 {
31 uint32_t error = CC_OK;
32 uint8_t *initMac_ptr;
33 uint32_t i;
34 uint32_t additionalBytesSize = 0;
35 uint8_t *inputPtr = (uint8_t*)pInputBuff;
36 uint8_t keyBuff[CC_PROD_AES_Key256Bits_SIZE_IN_BYTES];
37 uint8_t ivBuff[CC_PROD_AES_IV_COUNTER_SIZE_IN_BYTES];
38 uint32_t outDataSizeBytes = CC_PROD_AES_Key256Bits_SIZE_IN_BYTES+CC_PROD_AES_IV_COUNTER_SIZE_IN_BYTES;
39 uint32_t inputDataSize = actualInputDataSize;
40 uint8_t Key[CC_PROD_AES_Key256Bits_SIZE_IN_BYTES] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
41 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F};
42 uint8_t InitialMac256[3][16] = {{0xF2,0x90,0x00,0xB6,0x2A,0x49,0x9F,0xD0,0xA9,0xF3,0x9A,0x6A,0xDD,0x2E,0x77,0x80},
43 {0x9D,0xBA,0x41,0xA7,0x77,0xF3,0xB4,0x6A,0x37,0xB7,0xAA,0xAE,0x49,0xD6,0xDF,0x8D},
44 {0x2F,0x7A,0x3C,0x60,0x07,0x08,0xD1,0x24,0xAC,0xD3,0xC5,0xDE,0x3B,0x65,0x84,0x47}};
45
46 if ((NULL == pInputBuff) || (actualInputDataSize == 0) || (NULL == pOutput)) {
47 CC_PAL_LOG_ERR("invalid parameters\n");
48 return CC_PROD_INVALID_PARAM_ERR;
49 }
50 /* Steps from NIST - ignored
51 1. If (number_of_bits_to_return > max_number_of_bits), then return an ERROR_FLAG. */
52
53 /* Steps from NIST
54 2. L = len (input_string)/8. Comment: L is the bitstring represention of the integer resulting from len (input_string)/8. L shall be represented as a 32-bit integer.
55 3. N = number_of_bits_to_return/8. Comment : N is the bitstring represention of the integer resulting from number_of_bits_to_return/8 .
56 N shall be represented as a 32-bit integer.
57 4. S = L || N || input_string || 0x80.
58 Comment : Pad S with zeros, if necessary.
59 5. While (len (S) mod outlen) 0, S = S || 0x00. */
60 /* convert L,N to little endian */
61 pInputBuff[0] = CC_PROD_SET_WORD_AS_BE(actualInputDataSize); /* L */
62 pInputBuff[1] = CC_PROD_SET_WORD_AS_BE(outDataSizeBytes); /* N */
63
64 inputPtr[8+actualInputDataSize] = 0x80;
65 // pad with 0's the remaining bytes until we reach size which is outlenSize multiply
66 additionalBytesSize = CC_PROD_AES_BLOCK_SIZE_IN_BYTES - ((8+1+actualInputDataSize)&(CC_PROD_AES_BLOCK_SIZE_IN_BYTES-1));
67 CC_PalMemSetZero(&inputPtr[8+1+actualInputDataSize], additionalBytesSize);
68
69 /* size of input to AES-MAC, rounded up to AES block */
70 inputDataSize += (8/*2w*/ + 1/*0x80*/ + additionalBytesSize);
71
72
73 /* Steps from NIST
74 Comment : Compute the starting value.
75 6. temp = the Null string.
76 7. i = 0. Comment : i shall be represented as a 32-bit integer, i.e., len (i) = 32.
77 8. K = Leftmost keylen bits of 0x00010203...1D1E1F.
78 9. While len (temp) < keylen + outlen, do
79 9.1 IV = i || 0outlen - len (i). Comment: The 32-bit integer represenation of i is padded with zeros to outlen bits.
80 9.2 temp = temp || BCC (K, (IV || S)).
81 9.3 i = i + 1. */
82 for (i = 0; i < (outDataSizeBytes >> 4); i++) {
83 /* set pointer to initial precomputed IV value */
84 initMac_ptr = (uint8_t*)&InitialMac256[i][0];
85
86 /* AES MAC */
87 error = CC_PROD_Aes(CIPHER_CBC_MAC, CRYPTO_DIRECTION_ENCRYPT,
88 USER_KEY,
89 Key,sizeof(Key),
90 initMac_ptr,CC_PROD_AES_IV_COUNTER_SIZE_IN_BYTES,
91 pInputBuff,
92 inputDataSize,
93 pOutput + i*CC_PROD_AES_BLOCK_SIZE_IN_WORDS);
94 if (error != CC_OK) {
95 CC_PAL_LOG_ERR("Failed to CC_PROD_Aes, error 0x%x\n", error);
96 return error;
97 }
98
99 }
100
101 /* Steps from NIST
102 Comment: Compute the requested number of bits.
103 10. K = Leftmost keylen bits of temp.
104 11. X = Next outlen bits of temp. */
105 CC_PalMemCopy(keyBuff, (uint8_t*)pOutput, sizeof(keyBuff));
106 CC_PalMemCopy(ivBuff, (uint8_t*)(pOutput + CC_PROD_AES_Key256Bits_SIZE_IN_WORDS), sizeof(ivBuff));
107
108
109 /* Steps from NIST
110 12. temp = the Null string.
111 13. While len (temp) < number_of_bits_to_return, do
112 13.1 X = Block_Encrypt (K, X).
113 13.2 temp = temp || X.
114 14. requested_bits = Leftmost number_of_bits_to_return of temp. */
115 /* Encrypt (K,IV) by AES-CBC using output buff */
116 CC_PalMemSetZero((uint8_t*)pOutput, outDataSizeBytes);
117 error = CC_PROD_Aes(CIPHER_CBC, CRYPTO_DIRECTION_ENCRYPT,
118 USER_KEY,
119 keyBuff, sizeof(keyBuff),
120 ivBuff, CC_PROD_AES_IV_COUNTER_SIZE_IN_BYTES,
121 pOutput,
122 outDataSizeBytes,
123 pOutput);
124 if (error != CC_OK) {
125 CC_PAL_LOG_ERR("Failed to CC_PROD_Aes, error 0x%x\n", error);
126 return error;
127 }
128
129 /* Steps from NIST
130 15. Return SUCCESS and requested_bits.*/
131 return CC_OK;
132 } /* END of Derivation_Block_Cipher_df */
133
134
135
136
137 /* increment vector by value of 1 */
Derivation_incrementVector(uint8_t * iv_ptr,uint32_t vecSizeInwords)138 static void Derivation_incrementVector(uint8_t *iv_ptr, uint32_t vecSizeInwords)
139 {
140 int32_t i;
141 uint32_t tmp, curr, tmp1;
142
143 for (i = vecSizeInwords-1; i >= 0; i--) {
144 CC_PalMemCopy((uint8_t *)&tmp1, &iv_ptr[i*sizeof(uint32_t)], sizeof(tmp1));
145 tmp = CC_PROD_SET_WORD_AS_BE(tmp1);
146 curr = tmp;
147 tmp = ((tmp+1) & 0xFFFFFFFF);
148
149 /* inverse the bytes order in a word */
150 tmp1 = CC_PROD_SET_WORD_AS_BE(tmp);
151 CC_PalMemCopy(&iv_ptr[i*sizeof(uint32_t)], (uint8_t *)&tmp1, sizeof(tmp));
152 if (tmp > curr) {
153 break;
154 }
155 }
156 }
157
158
159
160 /* Description: Implementation of CTR_DRBG_Update, Taken from NIST SP800-90A, section 10.2.1.2
161 Parameters:
162 provided_data[IN]: The data to be used. This must be exactly seedlen bits in length;
163 this length is guaranteed by the construction of the provided_data in the instantiate, reseed and generate functions.
164 Key[IN/OUT]: The current value of Key.
165 V[IN/OUT]: The current value of V.
166 */
Derivation_DRBG_Update(uint32_t * providedData_ptr,uint8_t * pKey,uint8_t * pIv)167 static uint32_t Derivation_DRBG_Update(uint32_t *providedData_ptr,
168 uint8_t *pKey,
169 uint8_t *pIv)
170 {
171
172 uint32_t error = CC_OK;
173 uint32_t outDataSize = (CC_PROD_AES_Key256Bits_SIZE_IN_BYTES+CC_PROD_AES_IV_COUNTER_SIZE_IN_BYTES);
174 uint32_t pOutput[CC_PROD_AES_Key256Bits_SIZE_IN_WORDS+CC_PROD_AES_IV_COUNTER_SIZE_IN_WORDS];
175 uint32_t i = 0;
176 AesContext_t aesCtx;
177
178 /* Steps taken from NIST
179 1. temp = Null.
180 2. While (len (temp) < seedlen) do
181 2.1 V = (V + 1) mod 2outlen.
182 2.2 output_block = Block_Encrypt (Key, V).
183 2.3 temp = temp || ouput_block.
184 3. temp = Leftmost seedlen bits of temp.
185 4 temp = temp XOR provided_data. */
186 error = CC_PROD_AesInit(&aesCtx, CIPHER_CTR, CRYPTO_DIRECTION_ENCRYPT,
187 USER_KEY,
188 pKey,CC_PROD_AES_Key256Bits_SIZE_IN_BYTES,
189 pIv,CC_PROD_AES_IV_COUNTER_SIZE_IN_BYTES);
190 if (error != CC_OK) {
191 return error;
192 }
193 // dummy block to increment IV
194 error = CC_PROD_AesProcess(&aesCtx,
195 providedData_ptr, CC_PROD_AES_BLOCK_SIZE_IN_BYTES,
196 pOutput);
197 if (error != CC_OK) {
198 return error;
199 }
200 for (i = 0; i < (outDataSize >> 4); i++) {
201 error = CC_PROD_AesProcess(&aesCtx,
202 providedData_ptr + i*CC_PROD_AES_BLOCK_SIZE_IN_WORDS, CC_PROD_AES_BLOCK_SIZE_IN_BYTES,
203 pOutput + i*CC_PROD_AES_BLOCK_SIZE_IN_WORDS);
204 if (error != CC_OK) {
205 return error;
206 }
207 }
208
209 /* Steps taken from NIST
210 5. Key = Leftmost keylen bits of temp.
211 6. V = Rightmost outlen bits of temp. */
212 CC_PalMemCopy(pKey, (uint8_t*)pOutput, CC_PROD_AES_Key256Bits_SIZE_IN_BYTES);
213 CC_PalMemCopy(pIv, (uint8_t*)(pOutput+CC_PROD_AES_Key256Bits_SIZE_IN_WORDS), CC_PROD_AES_IV_COUNTER_SIZE_IN_BYTES);
214
215 /*Steps taken from NIST
216 7. Return the new values of Key and V. */
217 return CC_OK;
218 }
219
220
221
222 /* Description: Implementation of CTR_DRBG_Instantiate_algorithm, Taken from NIST SP800-90A, section 10.2.1.3.2
223 Parameters:
224 pKey[OUT] - the generated key
225 pIv[OUT] - the generated Iv
226 */
CC_PROD_Derivation_Instantiate(uint32_t * pEntrSrc,uint32_t sourceSize,uint8_t * pKey,uint8_t * pIv)227 uint32_t CC_PROD_Derivation_Instantiate (uint32_t *pEntrSrc,
228 uint32_t sourceSize,
229 uint8_t *pKey,
230 uint8_t *pIv)
231 {
232 uint32_t error = CC_OK;
233 uint32_t pDfOutput[CC_PROD_AES_Key256Bits_SIZE_IN_WORDS+CC_PROD_AES_IV_COUNTER_SIZE_IN_WORDS] = {0};
234
235 if ((NULL == pKey) || (NULL == pIv) || (NULL == pEntrSrc) || (0 == sourceSize) || (!IS_ALIGNED(sourceSize, sizeof(uint32_t)))) {
236 CC_PAL_LOG_ERR("invalid key parameters\n");
237 return CC_PROD_INVALID_PARAM_ERR;
238 }
239 /* Steps taken from NIST - already done before calling CC_PROD_Derivation_Instantiate
240 1. seed_material = entropy_input || nonce || personalization_string.
241 (Comment: Ensure that the length of the seed_material is exactly seedlen bits.) */
242 /* Steps taken from NIST
243 2. seed_material = Derivation_Block_Cipher_df (seed_material, seedlen). */
244 error = Derivation_Block_Cipher_df(pEntrSrc, sourceSize, pDfOutput);
245 if (error != CC_OK) {
246 CC_PAL_LOG_ERR("failed Derivation_Block_Cipher_df, error is 0x%X\n", error);
247 return error;
248 }
249
250 /* Steps taken from NIST
251 3. Key = 0keylen. Comment: keylen bits of zeros.
252 4. V = 0outlen. Comment: outlen bits of zeros. */
253 CC_PalMemSetZero(pKey, CC_PROD_AES_Key256Bits_SIZE_IN_BYTES);
254 CC_PalMemSetZero(pIv, CC_PROD_AES_IV_COUNTER_SIZE_IN_BYTES);
255 /* Steps taken from NIST
256 5. (Key, V) = Derivation_DRBG_Update (seed_material, Key, V). */
257 error = Derivation_DRBG_Update(pDfOutput, pKey, pIv);
258 if (error != CC_OK) {
259 CC_PAL_LOG_ERR("failed Derivation_DRBG_Update, error is 0x%X\n", error);
260 return error;
261 }
262
263 /* Steps taken from NIST
264 6. reseed_counter = 1. -- ignored here
265 7. Return V, Key, and reseed_counter as the initial_working_state. */
266 return CC_OK;
267
268 }
269
270
271 /* Description: Implementation of CTR_DRBG_Generate_algorithm, Taken from NIST SP800-90A, section 10.2.1.5.2
272 Parameters:
273 pKey[IN] - the generated key
274 pIv[IN] - the generated Iv
275 pOutputBuff[OUT] - the generated buffer - 32 bytes
276 */
CC_PROD_Derivation_Generate(uint8_t * pKey,uint8_t * pIv,uint32_t * pOutputBuff,uint32_t outDataSize)277 uint32_t CC_PROD_Derivation_Generate(uint8_t *pKey,
278 uint8_t *pIv,
279 uint32_t *pOutputBuff,
280 uint32_t outDataSize)
281 {
282 uint32_t error = CC_OK;
283 uint32_t i = 0;
284 uint32_t numBlocks = (outDataSize >> 4);
285 uint32_t temp[CC_PROD_AES_BLOCK_SIZE_IN_WORDS] = {0};
286 #ifndef CMPU_KAT
287 uint32_t firstDummyBytes[CC_PROD_AES_BLOCK_SIZE_IN_WORDS] = {0};
288 #endif
289 AesContext_t aesCtx;
290
291 if ((pKey == NULL) || (pIv == NULL) || (pOutputBuff == NULL)) {
292 CC_PAL_LOG_ERR("Invalid input Param\n");
293 return CC_PROD_INVALID_PARAM_ERR;
294 }
295
296 /* Steps taken from NIST - all following are ignored, since th eworking state is one time
297 1. If reseed_counter > reseed_interval, then return an indication that a reseed is required.
298 2. If (additional_input Null), then
299 2.1 additional_input = Derivation_Block_Cipher_df (additional_input, seedlen).
300 2.2 (Key, V) = Derivation_DRBG_Update (additional_input, Key, V).
301 Else additional_input = 0seedlen. */
302
303
304
305 /* Steps taken from NIST
306 3. temp = Null.
307 4. While (len (temp) < requested_number_of_bits) do:
308 4.1 V = (V + 1) mod 2outlen.
309 4.2 output_block = Block_Encrypt (Key, V).
310 4.3 temp = temp || output_block.
311 5. returned_bits = Leftmost requested_number_of_bits of temp. */
312 /* Increment counter V = V+1 */
313 Derivation_incrementVector(pIv, CC_PROD_AES_IV_COUNTER_SIZE_IN_WORDS);
314 /* Init AES operation on CTR mode */
315 error = CC_PROD_AesInit(&aesCtx, CIPHER_CTR, CRYPTO_DIRECTION_ENCRYPT,
316 USER_KEY,
317 pKey, CC_PROD_AES_Key256Bits_SIZE_IN_BYTES,
318 pIv, CC_PROD_AES_IV_COUNTER_SIZE_IN_BYTES);
319 if (error != CC_OK) {
320 CC_PAL_LOG_ERR("Faild to CC_PROD_AesInit, error 0x%x\n", error);
321 return error;
322 }
323 #ifndef CMPU_KAT
324 error = CC_PROD_AesProcess(&aesCtx,
325 temp, sizeof(temp),
326 firstDummyBytes);
327 if (error != CC_OK) {
328 CC_PAL_LOG_ERR("Faild to CC_PROD_AesProcess, error 0x%x\n", error);
329 return error;
330 }
331 #endif
332
333 /* generate full blocks of input data */
334 for (i = 0; i < numBlocks; i++) {
335 error = CC_PROD_AesProcess(&aesCtx,
336 temp, CC_PROD_AES_BLOCK_SIZE_IN_BYTES,
337 pOutputBuff + i*CC_PROD_AES_BLOCK_SIZE_IN_WORDS);
338 if (error != CC_OK) {
339 CC_PAL_LOG_ERR("Faild to CC_PROD_AesProcess, error 0x%x\n", error);
340 return error;
341 }
342 }
343
344 /* Steps taken from NIST - all following are ignored, since th eworking state is one time
345 6. (Key, V) = Derivation_DRBG_Update (additional_input, Key, V).
346 7. reseed_counter = reseed_counter + 1. */
347
348 /* Steps taken from NIST
349 8. Return SUCCESS and returned_bits; also return Key, V, and reseed_counter as the new_working_state. */
350 return CC_OK;
351 }
352
353