1 /*
2  * Copyright (c) 2019-2021, Texas Instruments Incorporated
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * *  Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  *
12  * *  Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * *  Neither the name of Texas Instruments Incorporated nor the names of
17  *    its contributors may be used to endorse or promote products derived
18  *    from this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <stdint.h>
34 #include <stdbool.h>
35 #include <string.h>
36 
37 #include <ti/drivers/dpl/DebugP.h>
38 
39 #include <ti/drivers/cryptoutils/utils/CryptoUtils.h>
40 
41 #if defined(__GNUC__) || defined(__clang__)
42     #define CRYPTOUTILS_NOINLINE __attribute__((noinline))
43 #else
44     #define CRYPTOUTILS_NOINLINE
45 #endif
46 
47 #define CryptoUtils_LIMIT_MASK (0xFFFFFFFEu)
48 
49 /*
50  * These constants take values at the very top of the memory map where it is unreasonable
51  * for an application to have stored a different number value.
52  */
53 #define CryptoUtils_LIMIT_ZERO 0xFFFFFFFEu
54 #define CryptoUtils_LIMIT_ONE  0xFFFFFFFFu
55 
56 const uint8_t *CryptoUtils_limitZero = (uint8_t *)CryptoUtils_LIMIT_ZERO;
57 const uint8_t *CryptoUtils_limitOne  = (uint8_t *)CryptoUtils_LIMIT_ONE;
58 
59 /*
60  *  ======== CryptoUtils_buffersMatch ========
61  */
62 #if defined(__IAR_SYSTEMS_ICC__)
63     #pragma inline = never
64 #elif defined(__TI_COMPILER_VERSION__) && !defined(__cplusplus)
65     #pragma FUNC_CANNOT_INLINE(CryptoUtils_buffersMatch)
66 #elif defined(__TI_COMPILER_VERSION__)
67     #pragma FUNC_CANNOT_INLINE
68 #endif
CryptoUtils_buffersMatch(const volatile void * volatile buffer0,const volatile void * volatile buffer1,size_t bufferByteLength)69 CRYPTOUTILS_NOINLINE bool CryptoUtils_buffersMatch(const volatile void *volatile buffer0,
70                                                    const volatile void *volatile buffer1,
71                                                    size_t bufferByteLength)
72 {
73     volatile uint8_t tempResult = 0;
74     uint8_t byte0;
75     uint8_t byte1;
76     size_t i;
77 
78     /* XOR each byte of the buffer together and OR the results.
79      * If the OR'd result is non-zero, the buffers do not match.
80      * There is no branch based on the content of the buffers here to avoid
81      * timing attacks.
82      */
83     for (i = 0; i < bufferByteLength; i++)
84     {
85         byte0 = ((uint8_t *)buffer0)[i];
86         byte1 = ((uint8_t *)buffer1)[i];
87 
88         tempResult |= byte0 ^ byte1;
89     }
90 
91     return tempResult == 0;
92 }
93 
94 /*
95  *  ======== CryptoUtils_buffersMatchWordAligned ========
96  */
97 #if defined(__IAR_SYSTEMS_ICC__)
98     #pragma inline = never
99 #elif defined(__TI_COMPILER_VERSION__) && !defined(__cplusplus)
100     #pragma FUNC_CANNOT_INLINE(CryptoUtils_buffersMatchWordAligned)
101 #elif defined(__TI_COMPILER_VERSION__)
102     #pragma FUNC_CANNOT_INLINE
103 #endif
CryptoUtils_buffersMatchWordAligned(const volatile uint32_t * volatile buffer0,const volatile uint32_t * volatile buffer1,size_t bufferByteLength)104 CRYPTOUTILS_NOINLINE bool CryptoUtils_buffersMatchWordAligned(const volatile uint32_t *volatile buffer0,
105                                                               const volatile uint32_t *volatile buffer1,
106                                                               size_t bufferByteLength)
107 {
108     volatile uint32_t tempResult = 0;
109     uint32_t word0;
110     uint32_t word1;
111     size_t i;
112 
113     /* We could skip the branch and just set tempResult equal to the
114      * statement below for the same effect but this is more explicit.
115      */
116     if (bufferByteLength % sizeof(uint32_t) != 0)
117     {
118         return false;
119     }
120 
121     /* XOR each 32-bit word of the buffer together and OR the results.
122      * If the OR'd result is non-zero, the buffers do not match.
123      * There is no branch based on the content of the buffers here to avoid
124      * timing attacks.
125      */
126     for (i = 0; i < bufferByteLength / sizeof(uint32_t); i++)
127     {
128         word0 = buffer0[i];
129         word1 = buffer1[i];
130 
131         tempResult |= word0 ^ word1;
132     }
133 
134     return tempResult == 0;
135 }
136 
137 /*
138  *  ======== CryptoUtils_reverseBufferBytewise ========
139  */
CryptoUtils_reverseBufferBytewise(void * buffer,size_t bufferByteLength)140 void CryptoUtils_reverseBufferBytewise(void *buffer, size_t bufferByteLength)
141 {
142     uint8_t *bufferLow  = buffer;
143     uint8_t *bufferHigh = bufferLow + bufferByteLength - 1;
144     uint8_t tmp;
145 
146     while (bufferLow < bufferHigh)
147     {
148         tmp         = *bufferLow;
149         *bufferLow  = *bufferHigh;
150         *bufferHigh = tmp;
151         bufferLow++;
152         bufferHigh--;
153     }
154 }
155 
156 /*
157  *  ======== CryptoUtils_isBufferAllZeros ========
158  */
CryptoUtils_isBufferAllZeros(const void * buffer,size_t bufferByteLength)159 bool CryptoUtils_isBufferAllZeros(const void *buffer, size_t bufferByteLength)
160 {
161     uint32_t i;
162     uint8_t bufferBits = 0;
163 
164     for (i = 0; i < bufferByteLength; i++)
165     {
166         bufferBits |= ((uint8_t *)buffer)[i];
167     }
168 
169     return bufferBits == 0;
170 }
171 
172 /*
173  *  ======== CryptoUtils_memset ========
174  */
CryptoUtils_memset(void * dest,size_t destSize,uint8_t val,size_t count)175 void CryptoUtils_memset(void *dest, size_t destSize, uint8_t val, size_t count)
176 {
177     DebugP_assert(dest);
178     DebugP_assert(count <= destSize);
179 
180     volatile uint8_t *volatile p = (volatile uint8_t *)dest;
181 
182     while (destSize-- && count--)
183     {
184         *p++ = val;
185     }
186 }
187 
188 /*
189  *  ======== CryptoUtils_copyPad ========
190  */
CryptoUtils_copyPad(const void * source,uint32_t * destination,size_t sourceLength)191 void CryptoUtils_copyPad(const void *source, uint32_t *destination, size_t sourceLength)
192 {
193     uint32_t i;
194     uint8_t remainder;
195     uint32_t temp;
196     uint8_t *tempBytePointer;
197     const uint8_t *sourceBytePointer;
198 
199     remainder         = sourceLength % sizeof(uint32_t);
200     temp              = 0;
201     tempBytePointer   = (uint8_t *)&temp;
202     sourceBytePointer = (uint8_t *)source;
203 
204     /* Copy source to destination starting at the end of source and the
205      * beginning of destination.
206      * We assemble each word in normal order and write one word at a
207      * time since the PKA_RAM requires word-aligned reads and writes.
208      */
209 
210     for (i = 0; i < sourceLength / sizeof(uint32_t); i++)
211     {
212         uint32_t sourceOffset = sizeof(uint32_t) * i;
213 
214         tempBytePointer[0] = sourceBytePointer[sourceOffset + 0];
215         tempBytePointer[1] = sourceBytePointer[sourceOffset + 1];
216         tempBytePointer[2] = sourceBytePointer[sourceOffset + 2];
217         tempBytePointer[3] = sourceBytePointer[sourceOffset + 3];
218 
219         *(destination + i) = temp;
220     }
221 
222     /* Reset to 0 so we do not have to zero-out individual bytes */
223     temp = 0;
224 
225     /* If sourceLength is not a word-multiple, we need to copy over the
226      * remaining bytes and zero pad the word we are writing to PKA_RAM.
227      */
228     if (remainder == 1)
229     {
230 
231         tempBytePointer[0] = sourceBytePointer[0];
232 
233         /* i is reused from the loop above. This write zero-pads the
234          * destination buffer to word-length.
235          */
236         *(destination + i) = temp;
237     }
238     else if (remainder == 2)
239     {
240 
241         tempBytePointer[0] = sourceBytePointer[0];
242         tempBytePointer[1] = sourceBytePointer[1];
243 
244         *(destination + i) = temp;
245     }
246     else if (remainder == 3)
247     {
248 
249         tempBytePointer[0] = sourceBytePointer[0];
250         tempBytePointer[1] = sourceBytePointer[1];
251         tempBytePointer[2] = sourceBytePointer[2];
252 
253         *(destination + i) = temp;
254     }
255 }
256 
257 /*
258  *  ======== CryptoUtils_reverseCopyPad ========
259  */
CryptoUtils_reverseCopyPad(const void * source,uint32_t * destination,size_t sourceLength)260 void CryptoUtils_reverseCopyPad(const void *source, uint32_t *destination, size_t sourceLength)
261 {
262     uint32_t i;
263     uint8_t remainder;
264     uint32_t temp;
265     uint8_t *tempBytePointer;
266     const uint8_t *sourceBytePointer;
267 
268     remainder         = sourceLength % sizeof(uint32_t);
269     temp              = 0;
270     tempBytePointer   = (uint8_t *)&temp;
271     sourceBytePointer = (uint8_t *)source;
272 
273     /* Copy source to destination starting at the end of source and the
274      * beginning of destination.
275      * We assemble each word in byte-reversed order and write one word at a
276      * time since the PKA_RAM requires word-aligned reads and writes.
277      */
278 
279     for (i = 0; i < sourceLength / sizeof(uint32_t); i++)
280     {
281         uint32_t sourceOffset = sourceLength - 1 - sizeof(uint32_t) * i;
282 
283         tempBytePointer[3] = sourceBytePointer[sourceOffset - 3];
284         tempBytePointer[2] = sourceBytePointer[sourceOffset - 2];
285         tempBytePointer[1] = sourceBytePointer[sourceOffset - 1];
286         tempBytePointer[0] = sourceBytePointer[sourceOffset - 0];
287 
288         *(destination + i) = temp;
289     }
290 
291     /* Reset to 0 so we do not have to zero-out individual bytes */
292     temp = 0;
293 
294     /* If sourceLength is not a word-multiple, we need to copy over the
295      * remaining bytes and zero pad the word we are writing to PKA_RAM.
296      */
297     if (remainder == 1)
298     {
299 
300         tempBytePointer[0] = sourceBytePointer[0];
301 
302         /* i is reused from the loop above. This write  zero-pads the
303          * destination buffer to word-length.
304          */
305         *(destination + i) = temp;
306     }
307     else if (remainder == 2)
308     {
309 
310         tempBytePointer[0] = sourceBytePointer[1];
311         tempBytePointer[1] = sourceBytePointer[0];
312 
313         *(destination + i) = temp;
314     }
315     else if (remainder == 3)
316     {
317 
318         tempBytePointer[0] = sourceBytePointer[2];
319         tempBytePointer[1] = sourceBytePointer[1];
320         tempBytePointer[2] = sourceBytePointer[0];
321 
322         *(destination + i) = temp;
323     }
324 }
325 
326 /*
327  *  ======== CryptoUtils_reverseCopy ========
328  */
CryptoUtils_reverseCopy(const void * source,void * destination,size_t sourceLength)329 void CryptoUtils_reverseCopy(const void *source, void *destination, size_t sourceLength)
330 {
331     /*
332      * If destination address is word-aligned and source length is a word-multiple,
333      * use CryptoUtils_reverseCopyPad() for better efficiency.
334      */
335     if ((((uint32_t)destination | sourceLength) & 0x3) == 0)
336     {
337         CryptoUtils_reverseCopyPad(source, (uint32_t *)destination, sourceLength);
338     }
339     else
340     {
341         const uint8_t *sourceBytePtr = (const uint8_t *)source;
342         uint8_t *dstBytePtr          = (uint8_t *)destination + sourceLength - 1;
343 
344         /*
345          * Copy source to destination starting at the end of source and the
346          * beginning of destination.
347          */
348         while (sourceLength--)
349         {
350             *dstBytePtr-- = *sourceBytePtr++;
351         }
352     }
353 }
354 
355 /* limitValue must be either CryptoUtils_LIMIT_ZERO or CryptoUtils_LIMIT_ONE */
CryptoUtils_convertLimitValueToInt(const void * limitValue)356 static int16_t CryptoUtils_convertLimitValueToInt(const void *limitValue)
357 {
358     int16_t value = 0;
359 
360     if (limitValue == CryptoUtils_limitOne)
361     {
362         value = 1;
363     }
364 
365     return value;
366 }
367 
368 /*
369  * Returns number1[offset] - number2[offset].
370  *
371  * Can handle one of number1 or number2 (but not both) being one of the special limit values of
372  * CryptoUtils_LIMIT_ZERO or CryptoUtils_LIMIT_ONE.
373  *
374  * All pointer parameters must be non-NULL.
375  */
CryptoUtils_diffAtOffset(const uint8_t number1[],const uint8_t number2[],size_t offset,size_t lsbOffset)376 static int16_t CryptoUtils_diffAtOffset(const uint8_t number1[],
377                                         const uint8_t number2[],
378                                         size_t offset,
379                                         size_t lsbOffset)
380 {
381 
382     int16_t diff;
383 
384     /* Look at number2 first, as it will be more common for number2 to be one of the limit values. */
385     if (number2 == CryptoUtils_limitZero)
386     {
387         diff = (int16_t)number1[offset];
388     }
389     else if (number2 == CryptoUtils_limitOne)
390     {
391         if (offset == lsbOffset)
392         {
393             diff = (int16_t)number1[offset] - 1;
394         }
395         else
396         {
397             diff = (int16_t)number1[offset];
398         }
399     }
400     else if (number1 == CryptoUtils_limitZero)
401     {
402         diff = 0 - (int16_t)number1[offset];
403     }
404     else if (number1 == CryptoUtils_limitOne)
405     {
406         if (offset == lsbOffset)
407         {
408             diff = 1 - (int16_t)number1[offset];
409         }
410         else
411         {
412             diff = 0 - (int16_t)number1[offset];
413         }
414     }
415     else
416     {
417         diff = (int16_t)number1[offset] - (int16_t)number2[offset];
418     }
419 
420     return diff;
421 }
422 
423 /* Uses a timing constant algorithm to return 0 if value is 0 and return 1 otherwise. */
CryptoUtils_valueNonZeroTimingConstantCheck(int16_t value)424 static uint16_t CryptoUtils_valueNonZeroTimingConstantCheck(int16_t value)
425 {
426     uint16_t valueNonZero;
427 
428     /* Mask and shift bits such that if any bit in value is '1' then the
429        lsb of valueNonZero is 1 and otherwise valueNonZero is 0. */
430     valueNonZero = (((uint16_t)value & 0xFF00u) >> 8u) | ((uint8_t)value & 0xFFu);
431     valueNonZero = ((valueNonZero & 0xF0u) >> 4u) | (valueNonZero & 0x0Fu);
432     valueNonZero = ((valueNonZero & 0x0Cu) >> 2u) | (valueNonZero & 0x03u);
433     valueNonZero = ((valueNonZero & 0x02u) >> 1u) | (valueNonZero & 0x01u);
434 
435     return valueNonZero;
436 }
437 
438 /*
439  * Returns sign of number1 - number2:
440  * negative value if number2 is larger, positive value if number1 is larger and zero if numbers are equal.
441  *
442  * Note that the magnitude of the return value has no meaning.
443  *
444  * The comparison is performed with a time-constant algorithm with respect to either of the number
445  * arguments (number1, number2) when those inputs are not CryptoUtils_limitZero or CryptoUtils_limitOne.
446  *
447  * All pointer parameters must be non-NULL.
448  */
CryptoUtils_compareNumbers(const uint8_t number1[],const uint8_t number2[],size_t byteLength,CryptoUtils_Endianess endianess)449 static int16_t CryptoUtils_compareNumbers(const uint8_t number1[],
450                                           const uint8_t number2[],
451                                           size_t byteLength,
452                                           CryptoUtils_Endianess endianess)
453 {
454     int16_t result = 0x0;
455     int16_t diff;
456     uint16_t diffNonZero;
457     uint16_t diffResultMask;
458     uint16_t resultUnknown = 0xFFFFu;
459     uintptr_t number1Address;
460     uintptr_t number2Address;
461     size_t i;
462 
463     number1Address = (uintptr_t)number1;
464     number2Address = (uintptr_t)number2;
465 
466     /*
467      * Check if special RNG_limit values are being used for both values.
468      * This is not expected, but is handled for completeness.
469      */
470     if (((number1Address & CryptoUtils_LIMIT_MASK) == CryptoUtils_LIMIT_MASK) &&
471         ((number2Address & CryptoUtils_LIMIT_MASK) == CryptoUtils_LIMIT_MASK))
472     {
473 
474         result = CryptoUtils_convertLimitValueToInt(number1) - CryptoUtils_convertLimitValueToInt(number2);
475     }
476     else if (number1 != number2)
477     {
478         if (endianess == CryptoUtils_ENDIANESS_BIG)
479         {
480             i = 0u;
481             while (i < byteLength)
482             {
483                 diff = CryptoUtils_diffAtOffset(number1, number2, i, byteLength - 1);
484 
485                 /* Update result only if result was not known and is thus currently set to 0. */
486                 result = (int16_t)((uint16_t)result | (resultUnknown & (uint16_t)diff));
487 
488                 /*
489                  * Determine if result is now known and update resultUnknown
490                  */
491 
492                 diffNonZero = CryptoUtils_valueNonZeroTimingConstantCheck(diff);
493 
494                 /* Create mask where mask value is 0 if bytes were equal, otherwise mask is all 1s. */
495                 diffResultMask = diffNonZero - 1u;
496 
497                 /* Set resultUnknown to 0 (indicating result is known) if bytes were not equal. */
498                 resultUnknown &= diffResultMask;
499 
500                 i++;
501             }
502         }
503         else
504         {
505             i = byteLength;
506             while (i > 0u)
507             {
508                 i--;
509 
510                 diff = CryptoUtils_diffAtOffset(number1, number2, i, 0);
511 
512                 /* Update result only if result was not known and is thus currently set to 0. */
513                 result = (int16_t)((uint16_t)result | (resultUnknown & (uint16_t)diff));
514 
515                 /*
516                  * Determine if result is now known and update resultUnknown
517                  */
518                 diffNonZero = CryptoUtils_valueNonZeroTimingConstantCheck(diff);
519 
520                 /* Create mask where mask value is 0 if bytes were equal, otherwise mask is all 1s. */
521                 diffResultMask = diffNonZero - 1u;
522 
523                 /* Set resultUnknown to 0 (indicating result is known) if bytes were not equal. */
524                 resultUnknown &= diffResultMask;
525             }
526         }
527     }
528     else
529     {
530         result = 0;
531     }
532 
533     return result;
534 }
535 
536 /*
537  *  ======== CryptoUtils_isNumberInRange ========
538  */
CryptoUtils_isNumberInRange(const void * number,size_t bitLength,CryptoUtils_Endianess endianess,const void * lowerLimit,const void * upperLimit)539 bool CryptoUtils_isNumberInRange(const void *number,
540                                  size_t bitLength,
541                                  CryptoUtils_Endianess endianess,
542                                  const void *lowerLimit,
543                                  const void *upperLimit)
544 {
545     int16_t upperResult;
546     int16_t lowerResult;
547     bool inUpperLimit = true;
548     bool inLowerLimit = true;
549     size_t byteLength;
550 
551     byteLength = (bitLength + 7u) >> 3u;
552 
553     if (upperLimit != NULL)
554     {
555         upperResult = CryptoUtils_compareNumbers(number, upperLimit, byteLength, endianess);
556         if (upperResult >= 0)
557         {
558             inUpperLimit = false;
559         }
560     }
561 
562     if (lowerLimit != NULL)
563     {
564         lowerResult = CryptoUtils_compareNumbers(number, lowerLimit, byteLength, endianess);
565         if (lowerResult < 0)
566         {
567             inLowerLimit = false;
568         }
569     }
570 
571     return (inUpperLimit && inLowerLimit);
572 }
573