1 /*
2  * Copyright (c) 2015, Freescale Semiconductor, Inc.
3  * Copyright 2017,2021, NXP
4  * All rights reserved.
5  *
6  *
7  * SPDX-License-Identifier: BSD-3-Clause
8  */
9 
10 #include "fsl_mmcau.h"
11 #include "cau_api.h"
12 
13 #define MMCAU_AES_BLOCK_SIZE (16)
14 #define MMCAU_DES_BLOCK_SIZE (8)
15 
16 #define MMCAU_MD5_STATE_SIZE    (16)
17 #define MMCAU_SHA1_STATE_SIZE   (20)
18 #define MMCAU_SHA256_STATE_SIZE (32)
19 
20 /* these are maximum for CAU API has functions. HAST_STATE shall be set to maximum of MD5_STATE,SHA1_STATE and
21  * SHA256_STATE */
22 #define MMCAU_HASH_STATE_SIZE (32)
23 #define MMCAU_HASH_BLOCK_SIZE (64)
24 
25 /* typedef for pointer to CAU API functions */
26 typedef void (*cau_hash_api_t)(const uint8_t *msgData, const int numBlocks, uint32_t *hashState);
27 typedef void (*cau_hash_md5_api_t)(const uint8_t *msgData, const int numBlocks, uint8_t *hashState);
28 
29 /*******************************************************************************
30  * Code
31  ******************************************************************************/
mmcau_memcpy(void * dst,const void * src,size_t size)32 static void mmcau_memcpy(void *dst, const void *src, size_t size)
33 {
34     register uint8_t *to         = dst;
35     register const uint8_t *from = src;
36     while (size != 0U)
37     {
38         *to = *from;
39         size--;
40         to++;
41         from++;
42     }
43 }
44 
45 /* check if in pointer is aligned. if not, copy in to inAlign. return pointer to aligned data. */
mmcau_align_const(const void * in,void * inAlign,size_t size)46 static const void *mmcau_align_const(const void *in, void *inAlign, size_t size)
47 {
48     const void *inWork  = in;
49     const uint32_t *src = (const uint32_t *)in;
50     /* if one or two least significant bits in the address are set, the address is unaligned */
51     if (0U != ((uint32_t)src & 0x3u))
52     {
53         mmcau_memcpy(inAlign, in, size);
54         inWork = inAlign;
55     }
56 
57     return inWork;
58 }
59 
60 /* check if out pointer is aligned. if not, set bool variable to notify caller. return pointer to aligned data. */
mmcau_align(void * out,void * outAlign,bool * copyOut)61 static void *mmcau_align(void *out, void *outAlign, bool *copyOut)
62 {
63     void *outWork;
64     uint32_t *dst = (uint32_t *)out;
65     /* if one or two least significant bits in the address are set, the address is unaligned */
66     if (0U != ((uint32_t)dst & 0x3u))
67     {
68         outWork  = outAlign;
69         *copyOut = true;
70     }
71     else
72     {
73         outWork  = out;
74         *copyOut = false;
75     }
76 
77     return outWork;
78 }
79 
80 /* common function for AES process. "encrypt" argument selects between en-/de-cryption */
mmcau_AesCrypt(const uint8_t * in,const uint8_t * keySch,uint32_t aesRounds,uint8_t * out,bool encrypt)81 static status_t mmcau_AesCrypt(const uint8_t *in, const uint8_t *keySch, uint32_t aesRounds, uint8_t *out, bool encrypt)
82 {
83     status_t status;
84 
85     /* check validity of input arguments */
86     if (((aesRounds != 10u) && (aesRounds != 12u) && (aesRounds != 14u)) || (NULL == in) || (NULL == out) ||
87         (NULL == keySch))
88     {
89         status = kStatus_InvalidArgument;
90     }
91     else
92     {
93         uint8_t inAlign[MMCAU_AES_BLOCK_SIZE];  /* 16 bytes aligned input block */
94         uint8_t outAlign[MMCAU_AES_BLOCK_SIZE]; /* 16 bytes aligned output block */
95         uint32_t keySchAlign[60];               /* max 60 longwords in case of 32 bytes AES key */
96         size_t keySchSize = 0;
97         const uint8_t *keySchWork;
98         const uint8_t *inWork;
99         uint8_t *outWork;
100         bool copyOut;
101 
102         /* compute keySchSize in bytes per CAU API documentation */
103         if (aesRounds == 10u)
104         {
105             keySchSize = 44u * sizeof(uint32_t);
106         }
107         else if (aesRounds == 12u)
108         {
109             keySchSize = 52u * sizeof(uint32_t);
110         }
111         else /* aesRounds = 14u */
112         {
113             keySchSize = 60u * sizeof(uint32_t);
114         }
115 
116         /* align pointers */
117         inWork     = mmcau_align_const(in, inAlign, MMCAU_AES_BLOCK_SIZE);
118         keySchWork = mmcau_align_const(keySch, keySchAlign, keySchSize);
119         outWork    = mmcau_align(out, outAlign, &copyOut);
120 
121         /* call actual CAU API */
122         if (encrypt)
123         {
124             cau_aes_encrypt(inWork, keySchWork, (int)aesRounds, outWork);
125         }
126         else
127         {
128             cau_aes_decrypt(inWork, keySchWork, (int)aesRounds, outWork);
129         }
130         /* copy to unaligned out pointer */
131         if (copyOut)
132         {
133             mmcau_memcpy(out, outAlign, MMCAU_AES_BLOCK_SIZE);
134         }
135 
136         status = kStatus_Success;
137     }
138     return status;
139 }
140 
141 /* common function for DES process. "encrypt" argument selects between en-/de-cryption */
mmcau_DesCrypt(const uint8_t * in,const uint8_t * key,uint8_t * out,bool encrypt)142 static status_t mmcau_DesCrypt(const uint8_t *in, const uint8_t *key, uint8_t *out, bool encrypt)
143 {
144     status_t status;
145 
146     if ((in != NULL) && (key != NULL) && (out != NULL))
147     {
148         uint8_t keyAlign[MMCAU_DES_BLOCK_SIZE]; /* 8 bytes key size aligned */
149         uint8_t inAlign[MMCAU_DES_BLOCK_SIZE];  /* 8 bytes input block aligned */
150         uint8_t outAlign[MMCAU_DES_BLOCK_SIZE]; /* 8 bytes output block aligned */
151         const uint8_t *inWork;
152         const uint8_t *keyWork;
153         uint8_t *outWork;
154         bool copyOut;
155 
156         /* align pointers */
157         inWork  = mmcau_align_const(in, inAlign, MMCAU_DES_BLOCK_SIZE);
158         keyWork = mmcau_align_const(key, keyAlign, MMCAU_DES_BLOCK_SIZE);
159         outWork = mmcau_align(out, outAlign, &copyOut);
160 
161         /* call CAU API */
162         if (encrypt)
163         {
164             cau_des_encrypt(inWork, keyWork, outWork);
165         }
166         else
167         {
168             cau_des_decrypt(inWork, keyWork, outWork);
169         }
170 
171         if (copyOut)
172         {
173             mmcau_memcpy(out, outAlign, MMCAU_DES_BLOCK_SIZE);
174         }
175         status = kStatus_Success;
176     }
177     else
178     {
179         status = kStatus_InvalidArgument;
180     }
181 
182     return status;
183 }
184 
mmcau_hash_API(cau_hash_api_t cauFunc,const uint8_t * msgData,uint32_t numBlocks,void * hashState,size_t stateSize)185 static status_t mmcau_hash_API(
186     cau_hash_api_t cauFunc, const uint8_t *msgData, uint32_t numBlocks, void *hashState, size_t stateSize)
187 {
188     status_t status;
189 
190     if ((msgData != NULL) && (hashState != NULL) && (numBlocks != 0U))
191     {
192         const uint8_t *msgDataWork;
193         void *hashStateWork;
194         uint8_t msgDataAlign[MMCAU_HASH_BLOCK_SIZE];
195         uint8_t hashStateAlign[MMCAU_HASH_STATE_SIZE];
196         bool copyInOut;
197 
198         /* get aligned pointers */
199         msgDataWork   = mmcau_align_const(msgData, msgDataAlign, MMCAU_HASH_BLOCK_SIZE);
200         hashStateWork = mmcau_align(hashState, hashStateAlign, &copyInOut);
201         if (copyInOut)
202         {
203             mmcau_memcpy(hashStateAlign, hashState, stateSize);
204         }
205         /* CAU API */
206         cauFunc(msgDataWork, numBlocks, hashStateWork);
207         /* copy result to misaligned address */
208         if (copyInOut)
209         {
210             mmcau_memcpy(hashState, hashStateAlign, stateSize);
211         }
212         status = kStatus_Success;
213     }
214     else
215     {
216         status = kStatus_InvalidArgument;
217     }
218     return status;
219 }
220 
mmcau_hash_MD5API(cau_hash_md5_api_t cauFunc,const uint8_t * msgData,uint32_t numBlocks,void * hashState,size_t stateSize)221 static status_t mmcau_hash_MD5API(
222     cau_hash_md5_api_t cauFunc, const uint8_t *msgData, uint32_t numBlocks, void *hashState, size_t stateSize)
223 {
224     status_t status;
225 
226     if ((msgData != NULL) && (hashState != NULL) && (numBlocks != 0U))
227     {
228         const uint8_t *msgDataWork;
229         void *hashStateWork;
230         uint8_t msgDataAlign[MMCAU_HASH_BLOCK_SIZE];
231         uint8_t hashStateAlign[MMCAU_HASH_STATE_SIZE];
232         bool copyInOut;
233 
234         /* get aligned pointers */
235         msgDataWork   = mmcau_align_const(msgData, msgDataAlign, MMCAU_HASH_BLOCK_SIZE);
236         hashStateWork = mmcau_align(hashState, hashStateAlign, &copyInOut);
237         if (copyInOut)
238         {
239             mmcau_memcpy(hashStateAlign, hashState, stateSize);
240         }
241         /* CAU API */
242         cauFunc(msgDataWork, numBlocks, hashStateWork);
243         /* copy result to misaligned address */
244         if (copyInOut)
245         {
246             mmcau_memcpy(hashState, hashStateAlign, stateSize);
247         }
248         status = kStatus_Success;
249     }
250     else
251     {
252         status = kStatus_InvalidArgument;
253     }
254     return status;
255 }
256 
MMCAU_AES_SetKey(const uint8_t * key,const size_t keySize,uint8_t * keySch)257 status_t MMCAU_AES_SetKey(const uint8_t *key, const size_t keySize, uint8_t *keySch)
258 {
259     status_t status;
260 
261     /* check validity of input arguments */
262     if (((keySize != 16u) && (keySize != 24u) && (keySize != 32u)) || (NULL == key) || (NULL == keySch))
263     {
264         status = kStatus_InvalidArgument;
265     }
266     else
267     {
268         uint8_t keyAlign[32]     = {0}; /* max 32 bytes key supported by CAU lib */
269         uint32_t keySchAlign[60] = {0}; /* max 60 longwords in case of 32 bytes AES key */
270         const uint8_t *keyWork;         /* aligned CAU lib input address argument */
271         uint8_t *keySchWork;            /* aligned CAU lib output address argument */
272         bool copyOut;
273         size_t sizeOut = 0;
274 
275         keyWork    = mmcau_align_const(key, keyAlign, sizeof(keyAlign));
276         keySchWork = mmcau_align(keySch, keySchAlign, &copyOut);
277 
278         /* call CAU lib API with all addresses aligned */
279         cau_aes_set_key(keyWork, ((int)keySize * 8), keySchWork);
280 
281         /* in case we have aligned output to local, copy the result out */
282         if (copyOut)
283         {
284             if (keySize == 16u)
285             {
286                 sizeOut = 44u * sizeof(uint32_t);
287             }
288             else if (keySize == 24u)
289             {
290                 sizeOut = 52u * sizeof(uint32_t);
291             }
292             else /* keySize = 32u */
293             {
294                 sizeOut = 60u * sizeof(uint32_t);
295             }
296 
297             mmcau_memcpy(keySch, keySchAlign, sizeOut);
298         }
299 
300         status = kStatus_Success;
301     }
302 
303     return status;
304 }
305 
MMCAU_AES_EncryptEcb(const uint8_t * in,const uint8_t * keySch,uint32_t aesRounds,uint8_t * out)306 status_t MMCAU_AES_EncryptEcb(const uint8_t *in, const uint8_t *keySch, uint32_t aesRounds, uint8_t *out)
307 {
308     return mmcau_AesCrypt(in, keySch, aesRounds, out, true /* true for encryption */);
309 }
310 
MMCAU_AES_DecryptEcb(const uint8_t * in,const uint8_t * keySch,uint32_t aesRounds,uint8_t * out)311 status_t MMCAU_AES_DecryptEcb(const uint8_t *in, const uint8_t *keySch, uint32_t aesRounds, uint8_t *out)
312 {
313     return mmcau_AesCrypt(in, keySch, aesRounds, out, false /* false for decryption */);
314 }
315 
MMCAU_DES_ChkParity(const uint8_t * key)316 status_t MMCAU_DES_ChkParity(const uint8_t *key)
317 {
318     status_t status;
319 
320     if (key != NULL)
321     {
322         uint8_t keyAlign[8]; /* 8 bytes key size aligned */
323         const uint8_t *keyWork;
324 
325         /* align key[] */
326         keyWork = mmcau_align_const(key, keyAlign, sizeof(keyAlign));
327 
328         /* call CAU API */
329         if (0 == cau_des_chk_parity(keyWork))
330         {
331             status = kStatus_Success;
332         }
333         else
334         {
335             status = kStatus_Fail;
336         }
337     }
338     else
339     {
340         status = kStatus_InvalidArgument;
341     }
342 
343     return status;
344 }
345 
MMCAU_DES_EncryptEcb(const uint8_t * in,const uint8_t * key,uint8_t * out)346 status_t MMCAU_DES_EncryptEcb(const uint8_t *in, const uint8_t *key, uint8_t *out)
347 {
348     return mmcau_DesCrypt(in, key, out, true /* 1 for encryption */);
349 }
350 
MMCAU_DES_DecryptEcb(const uint8_t * in,const uint8_t * key,uint8_t * out)351 status_t MMCAU_DES_DecryptEcb(const uint8_t *in, const uint8_t *key, uint8_t *out)
352 {
353     return mmcau_DesCrypt(in, key, out, false /* 0 for decryption */);
354 }
355 
356 /* cau_md5_initialize_output() */
MMCAU_MD5_InitializeOutput(uint32_t * md5State)357 status_t MMCAU_MD5_InitializeOutput(uint32_t *md5State)
358 {
359     status_t status;
360 
361     if (md5State != NULL)
362     {
363         uint8_t hashStateAlign[MMCAU_HASH_STATE_SIZE];
364         void *hashStateWork;
365         bool copyInOut;
366         /* align pointer */
367         hashStateWork = mmcau_align(md5State, hashStateAlign, &copyInOut);
368         if (copyInOut)
369         {
370             mmcau_memcpy(hashStateAlign, md5State, MMCAU_MD5_STATE_SIZE);
371         }
372         /* CAU API */
373         cau_md5_initialize_output(hashStateWork);
374         /* copy result to unaligned pointer */
375         if (copyInOut)
376         {
377             mmcau_memcpy(md5State, hashStateAlign, MMCAU_MD5_STATE_SIZE);
378         }
379         status = kStatus_Success;
380     }
381     else
382     {
383         status = kStatus_InvalidArgument;
384     }
385     return status;
386 }
387 
388 /* cau_md5_hash_n */
MMCAU_MD5_HashN(const uint8_t * msgData,uint32_t numBlocks,uint32_t * md5State)389 status_t MMCAU_MD5_HashN(const uint8_t *msgData, uint32_t numBlocks, uint32_t *md5State)
390 {
391     return mmcau_hash_MD5API((cau_hash_md5_api_t)cau_md5_hash_n, msgData, numBlocks, md5State, MMCAU_MD5_STATE_SIZE);
392 }
393 
394 /* cau_md5_update */
MMCAU_MD5_Update(const uint8_t * msgData,uint32_t numBlocks,uint32_t * md5State)395 status_t MMCAU_MD5_Update(const uint8_t *msgData, uint32_t numBlocks, uint32_t *md5State)
396 {
397     return mmcau_hash_MD5API((cau_hash_md5_api_t)cau_md5_update, msgData, numBlocks, md5State, MMCAU_MD5_STATE_SIZE);
398 }
399 
400 /* cau_sha1_initialize_output */
MMCAU_SHA1_InitializeOutput(uint32_t * sha1State)401 status_t MMCAU_SHA1_InitializeOutput(uint32_t *sha1State)
402 {
403     status_t status;
404 
405     if (sha1State != NULL)
406     {
407         uint8_t hashStateAlign[MMCAU_HASH_STATE_SIZE];
408         void *hashStateWork;
409         bool copyInOut;
410         /* align pointer */
411         hashStateWork = mmcau_align(sha1State, hashStateAlign, &copyInOut);
412         if (copyInOut)
413         {
414             mmcau_memcpy(hashStateAlign, sha1State, MMCAU_SHA1_STATE_SIZE);
415         }
416         /* CAU API */
417         cau_sha1_initialize_output(hashStateWork);
418         /* copy result to unaligned pointer */
419         if (copyInOut)
420         {
421             mmcau_memcpy(sha1State, hashStateAlign, MMCAU_SHA1_STATE_SIZE);
422         }
423         status = kStatus_Success;
424     }
425     else
426     {
427         status = kStatus_InvalidArgument;
428     }
429     return status;
430 }
431 
432 /* cau_sha1_hash_n */
MMCAU_SHA1_HashN(const uint8_t * msgData,uint32_t numBlocks,uint32_t * sha1State)433 status_t MMCAU_SHA1_HashN(const uint8_t *msgData, uint32_t numBlocks, uint32_t *sha1State)
434 {
435     return mmcau_hash_API((cau_hash_api_t)cau_sha1_hash_n, msgData, numBlocks, sha1State, MMCAU_SHA1_STATE_SIZE);
436 }
437 
438 /* cau_sha1_update */
MMCAU_SHA1_Update(const uint8_t * msgData,uint32_t numBlocks,uint32_t * sha1State)439 status_t MMCAU_SHA1_Update(const uint8_t *msgData, uint32_t numBlocks, uint32_t *sha1State)
440 {
441     return mmcau_hash_API((cau_hash_api_t)cau_sha1_update, msgData, numBlocks, sha1State, MMCAU_SHA1_STATE_SIZE);
442 }
443 
444 /* cau_sha256_initialize_output(). not this function has different return value (int) that the other two (void) */
MMCAU_SHA256_InitializeOutput(uint32_t * sha256State)445 status_t MMCAU_SHA256_InitializeOutput(uint32_t *sha256State)
446 {
447     status_t status;
448     int ret;
449 
450     if (sha256State != NULL)
451     {
452         uint8_t hashStateAlign[MMCAU_HASH_STATE_SIZE];
453         void *hashStateWork;
454         bool copyInOut;
455         /* align pointer */
456         hashStateWork = mmcau_align(sha256State, hashStateAlign, &copyInOut);
457         if (copyInOut)
458         {
459             mmcau_memcpy(hashStateAlign, sha256State, MMCAU_SHA256_STATE_SIZE);
460         }
461         /* CAU API */
462         ret = cau_sha256_initialize_output(hashStateWork);
463         /* copy result to unaligned pointer */
464         if (copyInOut)
465         {
466             mmcau_memcpy(sha256State, hashStateAlign, MMCAU_SHA256_STATE_SIZE);
467         }
468         if (ret == 0)
469         {
470             status = kStatus_Success;
471         }
472         else
473         {
474             status = kStatus_Fail;
475         }
476     }
477     else
478     {
479         status = kStatus_InvalidArgument;
480     }
481     return status;
482 }
483 
484 /* cau_sha256_hash_n */
MMCAU_SHA256_HashN(const uint8_t * input,uint32_t numBlocks,uint32_t * sha256State)485 status_t MMCAU_SHA256_HashN(const uint8_t *input, uint32_t numBlocks, uint32_t *sha256State)
486 {
487     return mmcau_hash_API((cau_hash_api_t)cau_sha256_hash_n, input, numBlocks, sha256State, MMCAU_SHA256_STATE_SIZE);
488 }
489 
490 /* cau_sha256_update */
MMCAU_SHA256_Update(const uint8_t * input,uint32_t numBlocks,uint32_t * sha256State)491 status_t MMCAU_SHA256_Update(const uint8_t *input, uint32_t numBlocks, uint32_t *sha256State)
492 {
493     return mmcau_hash_API((cau_hash_api_t)cau_sha256_update, input, numBlocks, sha256State, MMCAU_SHA256_STATE_SIZE);
494 }
495