Software APIs
rsa_3072_encryption_functest.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 
6 #include "sw/device/lib/crypto/drivers/entropy.h"
7 #include "sw/device/lib/crypto/impl/integrity.h"
11 #include "sw/device/lib/testing/profile.h"
12 #include "sw/device/lib/testing/test_framework/check.h"
14 
15 // Module for status messages.
16 #define MODULE_ID MAKE_MODULE_ID('t', 's', 't')
17 
18 enum {
19  kRsa3072NumBytes = 3072 / 8,
20  kRsa3072NumWords = kRsa3072NumBytes / sizeof(uint32_t),
21 };
22 
23 // Note: The private key and valid signatures for this test were generated
24 // out-of-band using the PyCryptodome Python library.
25 
26 // Test RSA-3072 key pair:
27 // e = 65537
28 // n =
29 // 0xa60f30a231261907afe74287a90cc23b24ec935f7520180f833bf3261c9f5a53c6057b0be827fc8c8adb26e8a4b442f1075a427b065433ac5b973b2ccc4ee3b8e82d5c810922ea4653cdc14e46dcfa85141f23d07fdec0a90b53c50ad1a7e9984bed7f9edcbafdb26398c69c6b8cfc8e2cd843c33fc8e54284807eb9abca302946b16dd82f8c428bd446f2cbf9d614e637c377b39d0a8e494b2dab398094aee11cf0109bb82214b11988b5df0943554126d660d3ac776aa1ea044e20f7e63fafddecb80bde3a683d64a074ff3e1dfa99ab5c16575dfe37bc5bb1b180434ccc4853b671a05c36a62b22df77e1482def92e576ea64ebf8d88d91fcadfeabc571ebedd8bc920d15ec18e300d4747b8bc3e8e04eb5afd95d6ff662ec62aa54ce8e23dd1beacfdde93cc03d9bdfffd2412d3255bed6946258c90c5fcfd55f1e9c1ce3bcd26c2b1299c298f941f8992318ca24154da24dee956a867b1f16bd0241a25db9c19f8630ca11035b29ea9cddf894ca239b6fe8c2242ceb61422b395248e8eb
30 // d =
31 // 0x2e1fdefed60f0279cfa2b9288c4ca6709e277621d81b2383bf8c79d3b6b48e76e17469429be7eb6eb02d022831837e6a8b83c71e7bda0c864de47a43cdb605ebb8d5ccb16cb3bd85ee4622f0d69f0f98c24789ffa25ce17fb2cd40586a76acdc280ede59666f2c038e4583b933e873c81bedb018be115398bfcc1f26fc700b2393e6b99f884979bc742886cd206695e4824db1647af4d123cb95724f6507277210c31fa1d929e23c74deb3c1b1457a1b4029e0b83ad9ea8cf1bee362a5e8d6fc546a4e705e73b4c9f8f5486c3c4dcc1e3e812025483a0ef65efe857ea81331256f43345142b3cba4cdb00270c27647b3b8d1185826066b83374bb038098a4e152a95830d621c40e752fc2a22a7bd0a88f7a1e86ae8f2bd3bde3d37027fc735a1f8a09cd55ce7738204a3767a15ce0940fe49e5b63c7a23fa15dae580446884981753730bc0944ac3421f557a1f44a1927863c8051c7f4bd88a71c55225b096ecc52df173bf748b23b332bc608702a398f1624a49919be3408341fecaf3cc45d9
32 
33 // Modulus (n) in little-endian form.
34 static uint32_t kTestModulus[kRsa3072NumWords] = {
35  0x5248e8eb, 0x61422b39, 0xc2242ceb, 0x239b6fe8, 0xddf894ca, 0x5b29ea9c,
36  0x30ca1103, 0xb9c19f86, 0x0241a25d, 0x7b1f16bd, 0xee956a86, 0x154da24d,
37  0x2318ca24, 0xf941f899, 0x1299c298, 0xbcd26c2b, 0x1e9c1ce3, 0x5fcfd55f,
38  0x6258c90c, 0x55bed694, 0xd2412d32, 0x3d9bdfff, 0xdde93cc0, 0xdd1beacf,
39  0x54ce8e23, 0x62ec62aa, 0xd95d6ff6, 0xe04eb5af, 0x7b8bc3e8, 0xe300d474,
40  0x0d15ec18, 0xedd8bc92, 0xabc571eb, 0x91fcadfe, 0xebf8d88d, 0xe576ea64,
41  0x482def92, 0x22df77e1, 0x5c36a62b, 0x53b671a0, 0x434ccc48, 0x5bb1b180,
42  0x5dfe37bc, 0xab5c1657, 0x3e1dfa99, 0x64a074ff, 0xde3a683d, 0xddecb80b,
43  0xf7e63faf, 0xea044e20, 0xac776aa1, 0x26d660d3, 0x09435541, 0x1988b5df,
44  0xb82214b1, 0x1cf0109b, 0x8094aee1, 0x4b2dab39, 0x9d0a8e49, 0x37c377b3,
45  0xf9d614e6, 0xd446f2cb, 0x2f8c428b, 0x46b16dd8, 0xabca3029, 0x84807eb9,
46  0x3fc8e542, 0x2cd843c3, 0x6b8cfc8e, 0x6398c69c, 0xdcbafdb2, 0x4bed7f9e,
47  0xd1a7e998, 0x0b53c50a, 0x7fdec0a9, 0x141f23d0, 0x46dcfa85, 0x53cdc14e,
48  0x0922ea46, 0xe82d5c81, 0xcc4ee3b8, 0x5b973b2c, 0x065433ac, 0x075a427b,
49  0xa4b442f1, 0x8adb26e8, 0xe827fc8c, 0xc6057b0b, 0x1c9f5a53, 0x833bf326,
50  0x7520180f, 0x24ec935f, 0xa90cc23b, 0xafe74287, 0x31261907, 0xa60f30a2,
51 };
52 static uint32_t kTestPrivateExponent[kRsa3072NumWords] = {
53  0xf3cc45d9, 0x8341feca, 0x919be340, 0xf1624a49, 0x8702a398, 0xb332bc60,
54  0xbf748b23, 0xc52df173, 0x25b096ec, 0x8a71c552, 0x1c7f4bd8, 0x7863c805,
55  0x1f44a192, 0x421f557a, 0xc0944ac3, 0x1753730b, 0x44688498, 0x15dae580,
56  0x3c7a23fa, 0xfe49e5b6, 0x15ce0940, 0x04a3767a, 0x5ce77382, 0xf8a09cd5,
57  0x7fc735a1, 0xde3d3702, 0xe8f2bd3b, 0xf7a1e86a, 0xa7bd0a88, 0x52fc2a22,
58  0x621c40e7, 0x2a95830d, 0x098a4e15, 0x374bb038, 0x26066b83, 0xb8d11858,
59  0xc27647b3, 0xcdb00270, 0x42b3cba4, 0x6f433451, 0xa8133125, 0x5efe857e,
60  0x483a0ef6, 0x3e812025, 0x3c4dcc1e, 0xf8f5486c, 0x5e73b4c9, 0x546a4e70,
61  0xa5e8d6fc, 0xf1bee362, 0x3ad9ea8c, 0x4029e0b8, 0xb1457a1b, 0x74deb3c1,
62  0xd929e23c, 0x10c31fa1, 0x65072772, 0xcb95724f, 0x7af4d123, 0x824db164,
63  0x206695e4, 0x742886cd, 0x884979bc, 0x93e6b99f, 0xfc700b23, 0xbfcc1f26,
64  0xbe115398, 0x1bedb018, 0x33e873c8, 0x8e4583b9, 0x666f2c03, 0x280ede59,
65  0x6a76acdc, 0xb2cd4058, 0xa25ce17f, 0xc24789ff, 0xd69f0f98, 0xee4622f0,
66  0x6cb3bd85, 0xb8d5ccb1, 0xcdb605eb, 0x4de47a43, 0x7bda0c86, 0x8b83c71e,
67  0x31837e6a, 0xb02d0228, 0x9be7eb6e, 0xe1746942, 0xb6b48e76, 0xbf8c79d3,
68  0xd81b2383, 0x9e277621, 0x8c4ca670, 0xcfa2b928, 0xd60f0279, 0x2e1fdefe,
69 };
70 static uint32_t kTestPublicExponent = 65537;
71 
72 // Message data for testing.
73 static const unsigned char kTestMessage[] = "Test message.";
74 static const size_t kTestMessageLen = sizeof(kTestMessage) - 1;
75 
76 // OAEP label for testing.
77 static const unsigned char kTestLabel[] = "Test label.";
78 static const size_t kTestLabelLen = sizeof(kTestLabel) - 1;
79 
80 // Hash mode for testing (and digest length in bytes).
81 static const otcrypto_hash_mode_t kTestHashMode = kOtcryptoHashModeSha512;
82 static const size_t kTestHashModeDigestBytes = 512 / 8;
83 
84 // Maximum plaintext length for OAEP (see IETF RFC 8017).
85 static const size_t kMaxPlaintextBytes =
86  kRsa3072NumBytes - 2 * kTestHashModeDigestBytes - 2;
87 
88 // Valid ciphertext for `kTestMessage` with the test private key, using OAEP
89 // encoding with `kTestLabel` and `kTestHashMode`.
90 static const uint32_t kValidCiphertext[kRsa3072NumWords] = {
91  0x2b57a10f, 0x26bbfdb9, 0x22f881b6, 0x3ea3735c, 0xb97896d8, 0x5ca9f2b9,
92  0xd70a4c1a, 0xaf1ead0d, 0xc4b0ae6d, 0x76ae6d9b, 0xcacf7b07, 0xb63f651f,
93  0x9fc70de5, 0x5f85a0c0, 0xda3b7882, 0x6c539d54, 0xe5566273, 0xeb461031,
94  0xb20242d6, 0x0cfcb276, 0x01b4e765, 0xe6ac1931, 0x82bf7c08, 0xb3aebe9c,
95  0x37d2f9cd, 0x0fe684a5, 0x9db2afd2, 0xa99b45e5, 0x17a8aff7, 0x22c56bae,
96  0x911f3c58, 0x645e7a67, 0x8833eaa5, 0x11e5d4f0, 0xafff8172, 0x40fc3c4c,
97  0x0a261c85, 0x6d623878, 0x30115176, 0x2853df91, 0x2bd02f85, 0xb1958b8e,
98  0x9288b3f9, 0x430f8ab2, 0x2556cf3a, 0xe485dbfb, 0xa644d055, 0xe0707828,
99  0xbd2aef6b, 0xfeb784a2, 0xe5ebbf8b, 0xa5f8b0fa, 0xb24c0f7b, 0xbfad7a83,
100  0x54903942, 0x56a20d38, 0xef1ad9a2, 0xbae1bc9b, 0x235c90c3, 0x3a9bd4ef,
101  0x2606ef34, 0x643add05, 0x57bc256c, 0xa45749dd, 0x1784134c, 0x3f553100,
102  0x46e3ae90, 0x44552576, 0x4feb281d, 0x4f83b747, 0xa890f513, 0x979afc28,
103  0x2addc3f2, 0x45a1064e, 0x9e1ade54, 0x551bf540, 0x4337b81c, 0x24259077,
104  0x6ba0c23c, 0xd6d81aab, 0xdf94cc28, 0x679ca168, 0xfc2b4700, 0x5018295b,
105  0xb8bf3cce, 0x3afdd992, 0x478989db, 0xfd095c8b, 0xd75b556b, 0x4672dd8c,
106  0x7b9dfe21, 0xb615edad, 0xf001b4d9, 0x9e6f9920, 0x58a92869, 0x15125194,
107 };
108 
109 /**
110  * Helper function to run the RSA-3072 encryption routine.
111  *
112  * Packages input into cryptolib-style structs and calls `otcrypto_rsa_encrypt`
113  * using the constant test private key.
114  *
115  * @param msg Message to encrypt.
116  * @param msg_len Message length in bytes.
117  * @param label Label for OAEP padding.
118  * @param label_len Label length in bytes.
119  * @param[out] ciphertext Buffer for the generated ciphertext (3072 bits).
120  * @return OK or error.
121  */
122 static status_t run_rsa_3072_encrypt(const uint8_t *msg, size_t msg_len,
123  const uint8_t *label, size_t label_len,
124  uint32_t *ciphertext) {
125  // Construct the public key.
126  otcrypto_const_word32_buf_t modulus = {
127  .data = kTestModulus,
128  .len = ARRAYSIZE(kTestModulus),
129  };
130  uint32_t public_key_data[ceil_div(kOtcryptoRsa3072PublicKeyBytes,
131  sizeof(uint32_t))];
132  otcrypto_unblinded_key_t public_key = {
133  .key_mode = kOtcryptoKeyModeRsaEncryptOaep,
134  .key_length = kOtcryptoRsa3072PublicKeyBytes,
135  .key = public_key_data,
136  };
137  TRY(otcrypto_rsa_public_key_construct(kOtcryptoRsaSize3072, modulus,
138  kTestPublicExponent, &public_key));
139 
140  otcrypto_const_byte_buf_t msg_buf = {.data = msg, .len = msg_len};
141  otcrypto_const_byte_buf_t label_buf = {.data = label, .len = label_len};
142  otcrypto_word32_buf_t ciphertext_buf = {
143  .data = ciphertext,
144  .len = kRsa3072NumWords,
145  };
146  uint64_t t_start = profile_start();
147  TRY(otcrypto_rsa_encrypt(&public_key, kTestHashMode, msg_buf, label_buf,
148  ciphertext_buf));
149  profile_end_and_print(t_start, "RSA-3072 encryption");
150 
151  return OK_STATUS();
152 }
153 
154 /**
155  * Helper function to run the RSA-3072 decryption routine.
156  *
157  * Packages input into cryptolib-style structs and calls `otcrypto_rsa_encrypt`
158  * using the constant test private key.
159  *
160  * The caller must allocate enough space at `msg` for the maximum message
161  * length, `kMaxPlaintextBytes`. The actual message length is returned in
162  * `msg_len`.
163  *
164  * @param label Label for OAEP padding.
165  * @param label_len Label length in bytes.
166  * @param ciphertext Ciphertext to decrypt (3072 bits).
167  * @param[out] msg Decrypted message.
168  * @param[out] msg_len Message length in bytes.
169  * @return OK or error.
170  */
171 static status_t run_rsa_3072_decrypt(const uint8_t *label, size_t label_len,
172  const uint32_t *ciphertext, uint8_t *msg,
173  size_t *msg_len) {
174  // Create two shares for the private exponent (second share is all-zero).
175  otcrypto_const_word32_buf_t d_share0 = {
176  .data = kTestPrivateExponent,
177  .len = ARRAYSIZE(kTestPrivateExponent),
178  };
179  uint32_t share1[ARRAYSIZE(kTestPrivateExponent)] = {0};
180  otcrypto_const_word32_buf_t d_share1 = {
181  .data = share1,
182  .len = ARRAYSIZE(share1),
183  };
184 
185  // Construct the private key.
186  otcrypto_key_config_t private_key_config = {
187  .version = kOtcryptoLibVersion1,
188  .key_mode = kOtcryptoKeyModeRsaEncryptOaep,
189  .key_length = kOtcryptoRsa3072PrivateKeyBytes,
190  .hw_backed = kHardenedBoolFalse,
191  .security_level = kOtcryptoKeySecurityLevelLow,
192  };
193  size_t keyblob_words =
194  ceil_div(kOtcryptoRsa3072PrivateKeyblobBytes, sizeof(uint32_t));
195  uint32_t keyblob[keyblob_words];
196  otcrypto_blinded_key_t private_key = {
197  .config = private_key_config,
198  .keyblob = keyblob,
199  .keyblob_length = kOtcryptoRsa3072PrivateKeyblobBytes,
200  };
201  otcrypto_const_word32_buf_t modulus = {
202  .data = kTestModulus,
203  .len = ARRAYSIZE(kTestModulus),
204  };
205  TRY(otcrypto_rsa_private_key_from_exponents(kOtcryptoRsaSize3072, modulus,
206  kTestPublicExponent, d_share0,
207  d_share1, &private_key));
208 
209  otcrypto_byte_buf_t plaintext_buf = {.data = msg, .len = kMaxPlaintextBytes};
210  otcrypto_const_byte_buf_t label_buf = {.data = label, .len = label_len};
211  otcrypto_const_word32_buf_t ciphertext_buf = {
212  .data = ciphertext,
213  .len = kRsa3072NumWords,
214  };
215  uint64_t t_start = profile_start();
216  TRY(otcrypto_rsa_decrypt(&private_key, kTestHashMode, ciphertext_buf,
217  label_buf, plaintext_buf, msg_len));
218  profile_end_and_print(t_start, "RSA-3072 decryption");
219 
220  return OK_STATUS();
221 }
222 
223 status_t oaep_decrypt_valid_test(void) {
224  // Decrypt the valid ciphertext.
225  uint8_t actual_msg[kMaxPlaintextBytes];
226  size_t actual_msg_len;
227  TRY(run_rsa_3072_decrypt(kTestLabel, kTestLabelLen, kValidCiphertext,
228  actual_msg, &actual_msg_len));
229 
230  // Compare to the expected plaintext.
231  TRY_CHECK(actual_msg_len == kTestMessageLen);
232  TRY_CHECK_ARRAYS_EQ(actual_msg, kTestMessage, actual_msg_len);
233  return OK_STATUS();
234 }
235 
236 status_t oaep_encrypt_decrypt_test(void) {
237  // Encrypt the message. Because OAEP is not deterministic, we cannot compare
238  // to an exact expected value, but we can check that it successfully
239  // decrypts.
240  uint32_t ciphertext[kRsa3072NumWords];
241  TRY(run_rsa_3072_encrypt(kTestMessage, kTestMessageLen, kTestLabel,
242  kTestLabelLen, ciphertext));
243 
244  // Decrypt the message.
245  uint8_t actual_msg[kMaxPlaintextBytes];
246  size_t actual_msg_len;
247  TRY(run_rsa_3072_decrypt(kTestLabel, kTestLabelLen, ciphertext, actual_msg,
248  &actual_msg_len));
249 
250  // Compare to the original message.
251  TRY_CHECK(actual_msg_len == kTestMessageLen);
252  TRY_CHECK_ARRAYS_EQ(actual_msg, kTestMessage, actual_msg_len);
253  return OK_STATUS();
254 }
255 
256 OTTF_DEFINE_TEST_CONFIG();
257 
258 bool test_main(void) {
259  status_t test_result = OK_STATUS();
260  CHECK_STATUS_OK(entropy_complex_init());
261  EXECUTE_TEST(test_result, oaep_decrypt_valid_test);
262  EXECUTE_TEST(test_result, oaep_encrypt_decrypt_test);
263  return status_ok(test_result);
264 }