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