Software APIs
rsa_modexp.c
1 // Copyright lowRISC contributors (OpenTitan project).
2 // Licensed under the Apache License, Version 2.0, see LICENSE for details.
3 // SPDX-License-Identifier: Apache-2.0
4 
5 #include "sw/device/lib/crypto/impl/rsa/rsa_modexp.h"
6 
7 #include "sw/device/lib/crypto/drivers/otbn.h"
8 
9 // Module ID for status codes.
10 #define MODULE_ID MAKE_MODULE_ID('r', 'm', 'e')
11 
12 // Declare the OTBN app.
13 OTBN_DECLARE_APP_SYMBOLS(run_rsa_modexp);
14 static const otbn_app_t kOtbnAppRsaModexp = OTBN_APP_T_INIT(run_rsa_modexp);
15 
16 // Declare offsets for input and output buffers.
17 OTBN_DECLARE_SYMBOL_ADDR(run_rsa_modexp, mode); // Application mode.
18 OTBN_DECLARE_SYMBOL_ADDR(run_rsa_modexp, n); // Public modulus n.
19 OTBN_DECLARE_SYMBOL_ADDR(run_rsa_modexp, d); // Private exponent d.
20 OTBN_DECLARE_SYMBOL_ADDR(run_rsa_modexp, inout); // Input/output buffer.
21 
22 static const otbn_addr_t kOtbnVarRsaMode =
23  OTBN_ADDR_T_INIT(run_rsa_modexp, mode);
24 static const otbn_addr_t kOtbnVarRsaN = OTBN_ADDR_T_INIT(run_rsa_modexp, n);
25 static const otbn_addr_t kOtbnVarRsaD = OTBN_ADDR_T_INIT(run_rsa_modexp, d);
26 static const otbn_addr_t kOtbnVarRsaInOut =
27  OTBN_ADDR_T_INIT(run_rsa_modexp, inout);
28 
29 // Declare mode constants.
30 OTBN_DECLARE_SYMBOL_ADDR(run_rsa_modexp, MODE_RSA_2048_MODEXP);
31 OTBN_DECLARE_SYMBOL_ADDR(run_rsa_modexp, MODE_RSA_2048_MODEXP_F4);
32 OTBN_DECLARE_SYMBOL_ADDR(run_rsa_modexp, MODE_RSA_3072_MODEXP);
33 OTBN_DECLARE_SYMBOL_ADDR(run_rsa_modexp, MODE_RSA_3072_MODEXP_F4);
34 OTBN_DECLARE_SYMBOL_ADDR(run_rsa_modexp, MODE_RSA_4096_MODEXP);
35 OTBN_DECLARE_SYMBOL_ADDR(run_rsa_modexp, MODE_RSA_4096_MODEXP_F4);
36 static const uint32_t kMode2048Modexp =
37  OTBN_ADDR_T_INIT(run_rsa_modexp, MODE_RSA_2048_MODEXP);
38 static const uint32_t kMode2048ModexpF4 =
39  OTBN_ADDR_T_INIT(run_rsa_modexp, MODE_RSA_2048_MODEXP_F4);
40 static const uint32_t kMode3072Modexp =
41  OTBN_ADDR_T_INIT(run_rsa_modexp, MODE_RSA_3072_MODEXP);
42 static const uint32_t kMode3072ModexpF4 =
43  OTBN_ADDR_T_INIT(run_rsa_modexp, MODE_RSA_3072_MODEXP_F4);
44 static const uint32_t kMode4096Modexp =
45  OTBN_ADDR_T_INIT(run_rsa_modexp, MODE_RSA_4096_MODEXP);
46 static const uint32_t kMode4096ModexpF4 =
47  OTBN_ADDR_T_INIT(run_rsa_modexp, MODE_RSA_4096_MODEXP_F4);
48 
49 enum {
50  /**
51  * Common RSA exponent with a specialized implementation.
52  *
53  * This exponent is 2^16 + 1, and called "F4" because it's the fourth Fermat
54  * number.
55  */
56  kExponentF4 = 65537,
57 };
58 
59 status_t rsa_modexp_wait(size_t *num_words) {
60  // Spin here waiting for OTBN to complete.
61  HARDENED_TRY(otbn_busy_wait_for_done());
62 
63  // Read the application mode.
64  uint32_t mode;
65  HARDENED_TRY(otbn_dmem_read(1, kOtbnVarRsaMode, &mode));
66 
67  *num_words = 0;
68  if (mode == kMode2048Modexp || mode == kMode2048ModexpF4) {
69  *num_words = kRsa2048NumWords;
70  } else if (mode == kMode3072Modexp || mode == kMode3072ModexpF4) {
71  *num_words = kRsa3072NumWords;
72  } else if (mode == kMode4096Modexp || mode == kMode4096ModexpF4) {
73  *num_words = kRsa4096NumWords;
74  } else {
75  // Unrecognized mode.
76  return OTCRYPTO_FATAL_ERR;
77  }
78 
79  return OTCRYPTO_OK;
80 }
81 
82 /**
83  * Finalizes a modular exponentiation of variable size.
84  *
85  * Blocks until OTBN is done, checks for errors. Ensures the mode matches
86  * expectations. Reads back the result, and then performs an OTBN secure wipe.
87  *
88  * @param num_words Number of words for the modexp result.
89  * @param[out] result Result of the modexp operation.
90  * @return Status of the operation (OK or error).
91  */
92 static status_t rsa_modexp_finalize(const size_t num_words, uint32_t *result) {
93  // Wait for OTBN to complete and get the result size.
94  size_t num_words_inferred;
95  HARDENED_TRY(rsa_modexp_wait(&num_words_inferred));
96 
97  // Check that the inferred result size matches expectations.
98  if (num_words != num_words_inferred) {
99  return OTCRYPTO_FATAL_ERR;
100  }
101 
102  // Read the result.
103  HARDENED_TRY(otbn_dmem_read(num_words, kOtbnVarRsaInOut, result));
104 
105  // Wipe DMEM.
106  return otbn_dmem_sec_wipe();
107 }
108 
109 status_t rsa_modexp_consttime_2048_start(const rsa_2048_int_t *base,
110  const rsa_2048_int_t *exp,
111  const rsa_2048_int_t *modulus) {
112  // Load the OTBN app. Fails if OTBN is not idle.
113  HARDENED_TRY(otbn_load_app(kOtbnAppRsaModexp));
114 
115  // Set mode.
116  uint32_t mode = kMode2048Modexp;
117  HARDENED_TRY(otbn_dmem_write(1, &mode, kOtbnVarRsaMode));
118 
119  // Set the base, the modulus n and private exponent d.
120  HARDENED_TRY(otbn_dmem_write(kRsa2048NumWords, base->data, kOtbnVarRsaInOut));
121  HARDENED_TRY(otbn_dmem_write(kRsa2048NumWords, modulus->data, kOtbnVarRsaN));
122  HARDENED_TRY(otbn_dmem_write(kRsa2048NumWords, exp->data, kOtbnVarRsaD));
123 
124  // Start OTBN.
125  return otbn_execute();
126 }
127 
128 status_t rsa_modexp_vartime_2048_start(const rsa_2048_int_t *base,
129  const uint32_t exp,
130  const rsa_2048_int_t *modulus) {
131  if (exp != kExponentF4) {
132  // TODO for other exponents, we temporarily fall back to the constant-time
133  // implementation until a variable-time implementation is supported.
134  rsa_2048_int_t exp_rsa;
135  memset(exp_rsa.data, 0, kRsa2048NumWords * sizeof(uint32_t));
136  exp_rsa.data[0] = exp;
137  return rsa_modexp_consttime_2048_start(base, &exp_rsa, modulus);
138  }
139 
140  // Load the OTBN app. Fails if OTBN is not idle.
141  HARDENED_TRY(otbn_load_app(kOtbnAppRsaModexp));
142 
143  // Set mode.
144  uint32_t mode = kMode2048ModexpF4;
145  HARDENED_TRY(otbn_dmem_write(1, &mode, kOtbnVarRsaMode));
146 
147  // Set the base and the modulus n.
148  HARDENED_TRY(otbn_dmem_write(kRsa2048NumWords, base->data, kOtbnVarRsaInOut));
149  HARDENED_TRY(otbn_dmem_write(kRsa2048NumWords, modulus->data, kOtbnVarRsaN));
150 
151  // Start OTBN.
152  return otbn_execute();
153 }
154 
155 status_t rsa_modexp_2048_finalize(rsa_2048_int_t *result) {
156  return rsa_modexp_finalize(kRsa2048NumWords, result->data);
157 }
158 
159 status_t rsa_modexp_consttime_3072_start(const rsa_3072_int_t *base,
160  const rsa_3072_int_t *exp,
161  const rsa_3072_int_t *modulus) {
162  // Load the OTBN app. Fails if OTBN is not idle.
163  HARDENED_TRY(otbn_load_app(kOtbnAppRsaModexp));
164 
165  // Set mode.
166  uint32_t mode = kMode3072Modexp;
167  HARDENED_TRY(otbn_dmem_write(1, &mode, kOtbnVarRsaMode));
168 
169  // Set the base, the modulus n and private exponent d.
170  HARDENED_TRY(otbn_dmem_write(kRsa3072NumWords, base->data, kOtbnVarRsaInOut));
171  HARDENED_TRY(otbn_dmem_write(kRsa3072NumWords, modulus->data, kOtbnVarRsaN));
172  HARDENED_TRY(otbn_dmem_write(kRsa3072NumWords, exp->data, kOtbnVarRsaD));
173 
174  // Start OTBN.
175  return otbn_execute();
176 }
177 
178 status_t rsa_modexp_vartime_3072_start(const rsa_3072_int_t *base,
179  const uint32_t exp,
180  const rsa_3072_int_t *modulus) {
181  if (exp != kExponentF4) {
182  // TODO for other exponents, we temporarily fall back to the constant-time
183  // implementation until a variable-time implementation is supported.
184  rsa_3072_int_t exp_rsa;
185  memset(exp_rsa.data, 0, kRsa3072NumWords * sizeof(uint32_t));
186  exp_rsa.data[0] = exp;
187  return rsa_modexp_consttime_3072_start(base, &exp_rsa, modulus);
188  }
189 
190  // Load the OTBN app. Fails if OTBN is not idle.
191  HARDENED_TRY(otbn_load_app(kOtbnAppRsaModexp));
192 
193  // Set mode.
194  uint32_t mode = kMode3072ModexpF4;
195  HARDENED_TRY(otbn_dmem_write(1, &mode, kOtbnVarRsaMode));
196 
197  // Set the base and the modulus n.
198  HARDENED_TRY(otbn_dmem_write(kRsa3072NumWords, base->data, kOtbnVarRsaInOut));
199  HARDENED_TRY(otbn_dmem_write(kRsa3072NumWords, modulus->data, kOtbnVarRsaN));
200 
201  // Start OTBN.
202  return otbn_execute();
203 }
204 
205 status_t rsa_modexp_3072_finalize(rsa_3072_int_t *result) {
206  return rsa_modexp_finalize(kRsa3072NumWords, result->data);
207 }
208 
209 status_t rsa_modexp_consttime_4096_start(const rsa_4096_int_t *base,
210  const rsa_4096_int_t *exp,
211  const rsa_4096_int_t *modulus) {
212  // Load the OTBN app. Fails if OTBN is not idle.
213  HARDENED_TRY(otbn_load_app(kOtbnAppRsaModexp));
214 
215  // Set mode.
216  uint32_t mode = kMode4096Modexp;
217  HARDENED_TRY(otbn_dmem_write(1, &mode, kOtbnVarRsaMode));
218 
219  // Set the base, the modulus n and private exponent d.
220  HARDENED_TRY(otbn_dmem_write(kRsa4096NumWords, base->data, kOtbnVarRsaInOut));
221  HARDENED_TRY(otbn_dmem_write(kRsa4096NumWords, modulus->data, kOtbnVarRsaN));
222  HARDENED_TRY(otbn_dmem_write(kRsa4096NumWords, exp->data, kOtbnVarRsaD));
223 
224  // Start OTBN.
225  return otbn_execute();
226 }
227 
228 status_t rsa_modexp_vartime_4096_start(const rsa_4096_int_t *base,
229  const uint32_t exp,
230  const rsa_4096_int_t *modulus) {
231  if (exp != kExponentF4) {
232  // TODO for other exponents, we temporarily fall back to the constant-time
233  // implementation until a variable-time implementation is supported.
234  rsa_4096_int_t exp_rsa;
235  memset(exp_rsa.data, 0, kRsa4096NumWords * sizeof(uint32_t));
236  exp_rsa.data[0] = exp;
237  return rsa_modexp_consttime_4096_start(base, &exp_rsa, modulus);
238  }
239 
240  // Load the OTBN app. Fails if OTBN is not idle.
241  HARDENED_TRY(otbn_load_app(kOtbnAppRsaModexp));
242 
243  // Set mode.
244  uint32_t mode = kMode4096ModexpF4;
245  HARDENED_TRY(otbn_dmem_write(1, &mode, kOtbnVarRsaMode));
246 
247  // Set the base and the modulus n.
248  HARDENED_TRY(otbn_dmem_write(kRsa4096NumWords, base->data, kOtbnVarRsaInOut));
249  HARDENED_TRY(otbn_dmem_write(kRsa4096NumWords, modulus->data, kOtbnVarRsaN));
250 
251  // Start OTBN.
252  return otbn_execute();
253 }
254 
255 status_t rsa_modexp_4096_finalize(rsa_4096_int_t *result) {
256  return rsa_modexp_finalize(kRsa4096NumWords, result->data);
257 }