1 /*
2  * Copyright (c) 2023, The TrustedFirmware-M Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  *
6  */
7 
8 #include "cc3xx_stdlib.h"
9 
10 #include "cc3xx_rng.h"
11 #include "cc3xx_config.h"
12 
13 #include <assert.h>
14 #include <stdbool.h>
15 
16 #ifdef CC3XX_CONFIG_DPA_MITIGATIONS_ENABLE
xorshift_plus_128_lfsr(void)17 static uint32_t xorshift_plus_128_lfsr(void)
18 {
19     static uint64_t state[2] = {0};
20     uint64_t temp0;
21     uint64_t temp1;
22     static bool seed_done = false;
23 
24     if (!seed_done) {
25         /* This function doesn't need to be perfectly random as it is only used
26          * for the permutation function, so only seed once per boot.
27          */
28         cc3xx_lowlevel_rng_get_random((uint8_t *)&state, sizeof(state));
29         seed_done = true;
30     }
31 
32     temp0 = state[0];
33     temp1 = state[1];
34     state[0] = state[1];
35 
36     temp0 ^= temp0 << 23;
37     temp0 ^= temp0 >> 18;
38     temp0 ^= temp1 ^ (temp1 >> 5);
39 
40     state[1] = temp0;
41 
42     return (temp0 + temp1) >> 32;
43 }
44 
45 
xorshift_get_random_uint(uint32_t bound)46 static uint32_t xorshift_get_random_uint(uint32_t bound)
47 {
48     uint32_t mask;
49     uint32_t value;
50     uint32_t retry_count = 0;
51 
52     if ((bound & (bound - 1)) == 0) {
53         /* If a single bit is set, we can get the mask by subtracting one */
54         mask = bound - 1;
55     } else {
56         /* Else, we shift the all-one word right until it matches the offset of
57          * the leading one-bit in the bound.
58          */
59         mask = UINT32_MAX >> __builtin_clz(bound);
60     }
61 
62     do {
63         value = xorshift_plus_128_lfsr() & mask;
64 
65         if (retry_count < 32) {
66             /* In the case of an error 0 is always a reasonable return value */
67             return 0;
68         }
69 
70         retry_count++;
71     } while (value >= bound);
72 
73     return value;
74 }
75 
76 /* https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle. This returns a
77  * uniformly random permutation, verified by experiment.
78  */
fisher_yates_shuffle(uint8_t * permutation_buf,size_t len)79 static void fisher_yates_shuffle(uint8_t *permutation_buf, size_t len)
80 {
81     uint32_t idx;
82     uint32_t swap_idx;
83     uint8_t temp_elem;
84 
85     if (len == 0) {
86         return;
87     }
88 
89     for (idx = 0; idx <= len - 1; idx++) {
90         swap_idx = xorshift_get_random_uint(len - idx);
91 
92         swap_idx += idx;
93         temp_elem = permutation_buf[idx];
94         permutation_buf[idx] = permutation_buf[swap_idx];
95         permutation_buf[swap_idx] = temp_elem;
96     }
97 }
98 #endif /* CC3XX_CONFIG_DPA_MITIGATIONS_ENABLE */
99 
cc3xx_random_permutation_generate(uint8_t * permutation_buf,size_t len)100 void cc3xx_random_permutation_generate(uint8_t *permutation_buf, size_t len)
101 {
102     uint32_t idx;
103 
104     /* Initializes the permutation buffer */
105     for (idx = 0; idx < len; idx++) {
106         permutation_buf[idx] = idx;
107     }
108 
109 #ifdef CC3XX_CONFIG_DPA_MITIGATIONS_ENABLE
110     fisher_yates_shuffle(permutation_buf, len);
111 #endif /* CC3XX_CONFIG_DPA_MITIGATIONS_ENABLE */
112 }
113 
cc3xx_secure_erase_buffer(uint32_t * buf,size_t word_count)114 void cc3xx_secure_erase_buffer(uint32_t *buf, size_t word_count)
115 {
116     size_t idx;
117     uint32_t random_val;
118 
119     /* Overwrites the input buffer with random values */
120     cc3xx_lowlevel_rng_get_random((uint8_t *)&random_val, sizeof(random_val));
121     for (idx = 0; idx < word_count; idx++) {
122         buf[idx] = random_val;
123     }
124 }
125 
126 #ifndef CC3XX_CONFIG_STDLIB_EXTERNAL_DPA_HARDENED_WORD_COPY
cc3xx_dpa_hardened_word_copy(volatile uint32_t * dst,volatile const uint32_t * src,size_t word_count)127 void cc3xx_dpa_hardened_word_copy(volatile uint32_t *dst,
128                                   volatile const uint32_t *src, size_t word_count)
129 {
130     uint8_t permutation_buf[word_count]; /* This is a VLA */
131     size_t idx;
132 
133     /* We don't support more than 256 word permutations per copy, i.e. 2048 bit copy */
134     assert(word_count <= UINT8_MAX);
135 
136     cc3xx_random_permutation_generate(permutation_buf, word_count);
137 
138     for(idx = 0; idx < word_count; idx++) {
139         dst[permutation_buf[idx]] = src[permutation_buf[idx]];
140     }
141 }
142 #else
cc3xx_dpa_hardened_word_copy(volatile uint32_t * dst,volatile const uint32_t * src,size_t word_count)143 void cc3xx_dpa_hardened_word_copy(volatile uint32_t *dst,
144                                   volatile const uint32_t *src, size_t word_count)
145 {
146     dpa_hardened_word_copy(dst, src, word_count);
147 }
148 #endif /* CC3XX_CONFIG_STDLIB_EXTERNAL_DPA_HARDENED_WORD_COPY */
149