Software APIs
keyblob_unittest.cc
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/keyblob.h"
6 
7 #include <array>
8 
9 #include "gmock/gmock.h"
10 #include "gtest/gtest.h"
11 #include "sw/device/lib/crypto/impl/status.h"
13 
14 namespace keyblob_unittest {
15 namespace {
16 using ::testing::ElementsAreArray;
17 
18 #define EXPECT_OK(status_) EXPECT_EQ(status_.value, OTCRYPTO_OK.value)
19 #define EXPECT_NOT_OK(status_) EXPECT_NE(status_.value, OTCRYPTO_OK.value)
20 
21 // Key configuration for testing (128-bit AES-CTR software key).
22 constexpr otcrypto_key_config_t kConfigCtr128 = {
23  .version = kOtcryptoLibVersion1,
24  .key_mode = kOtcryptoKeyModeAesCtr,
25  .key_length = 16,
26  .hw_backed = kHardenedBoolFalse,
27  .security_level = kOtcryptoKeySecurityLevelLow,
28 };
29 
30 // Key configuration for testing (31-byte key; not valid but helps test for
31 // issues with keys that don't have an even word size).
32 constexpr otcrypto_key_config_t kConfigOddBytes = {
33  .version = kOtcryptoLibVersion1,
34  .key_mode = kOtcryptoKeyModeAesCtr,
35  .key_length = 31,
36  .hw_backed = kHardenedBoolFalse,
37  .security_level = kOtcryptoKeySecurityLevelLow,
38 };
39 
40 // Key configuration for testing (key with a huge number of bytes; not valid
41 // but helps test for overflow).
42 constexpr otcrypto_key_config_t kConfigHuge = {
43  .version = kOtcryptoLibVersion1,
44  .key_mode = kOtcryptoKeyModeAesCtr,
45  .key_length = SIZE_MAX,
46  .hw_backed = kHardenedBoolFalse,
47  .security_level = kOtcryptoKeySecurityLevelLow,
48 };
49 
50 // Key configuration for testing (sideloaded AES-CTR key).
51 constexpr otcrypto_key_config_t kConfigCtrSideloaded = {
52  .version = kOtcryptoLibVersion1,
53  .key_mode = kOtcryptoKeyModeAesCtr,
54  .key_length = 16,
55  .hw_backed = kHardenedBoolTrue,
56  .security_level = kOtcryptoKeySecurityLevelLow,
57 };
58 
59 // Key configuration for testing (sideloaded AES-OFB key).
60 constexpr otcrypto_key_config_t kConfigOfbSideloaded = {
61  .version = kOtcryptoLibVersion1,
62  .key_mode = kOtcryptoKeyModeAesOfb,
63  .key_length = 16,
64  .hw_backed = kHardenedBoolTrue,
65  .security_level = kOtcryptoKeySecurityLevelLow,
66 };
67 
68 TEST(Keyblob, ShareNumWordsSimpleTest) {
69  size_t share_words = keyblob_share_num_words(kConfigCtr128);
70  EXPECT_GE(share_words * sizeof(uint32_t), kConfigCtr128.key_length);
71  EXPECT_LT((share_words - 1) * sizeof(uint32_t), kConfigCtr128.key_length);
72 }
73 
74 TEST(Keyblob, ShareNumWordsOdd) {
75  size_t share_words = keyblob_share_num_words(kConfigOddBytes);
76  EXPECT_GE(share_words * sizeof(uint32_t), kConfigOddBytes.key_length);
77  EXPECT_LT((share_words - 1) * sizeof(uint32_t), kConfigOddBytes.key_length);
78 }
79 
80 TEST(Keyblob, ShareNumWordsHuge) {
81  size_t share_words = keyblob_share_num_words(kConfigHuge);
82  EXPECT_GE(share_words, kConfigHuge.key_length / sizeof(uint32_t));
83  EXPECT_LT((share_words - 1) * sizeof(uint32_t), kConfigHuge.key_length);
84 }
85 
86 TEST(Keyblob, KeyblobNumWordsSimpleTest) {
87  EXPECT_EQ(keyblob_num_words(kConfigCtr128),
88  2 * keyblob_share_num_words(kConfigCtr128));
89 }
90 
91 TEST(Keyblob, KeyblobNumWordsOdd) {
92  EXPECT_EQ(keyblob_num_words(kConfigOddBytes),
93  2 * keyblob_share_num_words(kConfigOddBytes));
94 }
95 
96 TEST(Keyblob, KeyblobNumWordsHuge) {
97  EXPECT_EQ(keyblob_num_words(kConfigHuge),
98  2 * keyblob_share_num_words(kConfigHuge));
99 }
100 
101 TEST(Keyblob, FromSharesSimpleTest) {
102  std::array<uint32_t, 4> test_share0 = {0x01234567, 0x89abcdef, 0x00010203,
103  0x04050607};
104  std::array<uint32_t, 4> test_share1 = {0x08090a0b, 0x0c0d0e0f, 0x10111213,
105  0x14151617};
106 
107  // Test assumption; shares are the correct size.
108  ASSERT_EQ(test_share0.size(), keyblob_share_num_words(kConfigCtr128));
109  ASSERT_EQ(test_share1.size(), keyblob_share_num_words(kConfigCtr128));
110 
111  // Convert shares to keyblob array.
112  size_t keyblob_words = keyblob_num_words(kConfigCtr128);
113  EXPECT_THAT(keyblob_share_num_words(kConfigCtr128), 4);
114  uint32_t keyblob[keyblob_words] = {0};
115  keyblob_from_shares(test_share0.data(), test_share1.data(), kConfigCtr128,
116  keyblob);
117 
118  // Check that keyblob is both shares concatenated.
119  for (size_t i = 0; i < test_share0.size(); i++) {
120  EXPECT_EQ(keyblob[i], test_share0[i]);
121  }
122  for (size_t i = 0; i < test_share1.size(); i++) {
123  EXPECT_EQ(keyblob[test_share0.size() + i], test_share1[i]);
124  }
125 }
126 
127 TEST(Keyblob, FromToSharesNoop) {
128  std::array<uint32_t, 4> test_share0 = {0x01234567, 0x89abcdef, 0x00010203,
129  0x04050607};
130  std::array<uint32_t, 4> test_share1 = {0x08090a0b, 0x0c0d0e0f, 0x10111213,
131  0x14151617};
132 
133  // Test assumption; shares are the correct size.
134  ASSERT_EQ(test_share0.size(), keyblob_share_num_words(kConfigCtr128));
135  ASSERT_EQ(test_share1.size(), keyblob_share_num_words(kConfigCtr128));
136 
137  // Convert shares to keyblob array.
138  size_t keyblob_words = keyblob_num_words(kConfigCtr128);
139  uint32_t keyblob[keyblob_words] = {0};
140  keyblob_from_shares(test_share0.data(), test_share1.data(), kConfigCtr128,
141  keyblob);
142 
143  // Construct blinded key.
144  otcrypto_blinded_key_t key = {
145  .config = kConfigCtr128,
146  .keyblob_length = sizeof(keyblob),
147  .keyblob = keyblob,
148  .checksum = 0,
149  };
150 
151  // Retrieve pointers to each share.
152  uint32_t *share0;
153  uint32_t *share1;
154  EXPECT_OK(keyblob_to_shares(&key, &share0, &share1));
155 
156  // Check share values match original data.
157  for (size_t i = 0; i < test_share0.size(); i++) {
158  EXPECT_EQ(share0[i], test_share0[i]);
159  }
160  for (size_t i = 0; i < test_share1.size(); i++) {
161  EXPECT_EQ(share1[i], test_share1[i]);
162  }
163 }
164 
165 TEST(Keyblob, FromKeyMaskDoesNotChangeKey) {
166  std::array<uint32_t, 4> test_key = {0x01234567, 0x89abcdef, 0x00010203,
167  0x04050607};
168  std::array<uint32_t, 4> test_mask = {0x08090a0b, 0x0c0d0e0f, 0x10111213,
169  0x14151617};
170 
171  // Test assumption; key and mask are the correct size.
172  ASSERT_EQ(test_key.size(), keyblob_share_num_words(kConfigCtr128));
173  ASSERT_EQ(test_mask.size(), keyblob_share_num_words(kConfigCtr128));
174 
175  // Convert key/mask to keyblob array.
176  size_t keyblob_words = keyblob_num_words(kConfigCtr128);
177  uint32_t keyblob[keyblob_words] = {0};
178  EXPECT_OK(keyblob_from_key_and_mask(test_key.data(), test_mask.data(),
179  kConfigCtr128, keyblob));
180 
181  // Construct blinded key.
182  otcrypto_blinded_key_t key = {
183  .config = kConfigCtr128,
184  .keyblob_length = sizeof(keyblob),
185  .keyblob = keyblob,
186  .checksum = 0,
187  };
188 
189  // Retrieve pointers to each share.
190  uint32_t *share0;
191  uint32_t *share1;
192  EXPECT_OK(keyblob_to_shares(&key, &share0, &share1));
193 
194  // Unmask the key and check that it matches the original.
195  for (size_t i = 0; i < test_key.size(); i++) {
196  uint32_t share0 = keyblob[i];
197  uint32_t share1 = keyblob[test_key.size() + i];
198  EXPECT_EQ(share1, test_mask[i]);
199  EXPECT_EQ(share0 ^ share1, test_key[i]);
200  }
201 }
202 
203 TEST(Keyblob, ToKeymgrDiversificationSimple) {
204  // Salt and version for the hardware-backed key.
205  std::array<uint32_t, 7> test_salt = {0x01234567, 0x89abcdef, 0x00010203,
206  0x04050607, 0x08090a0b, 0x0c0d0e0f,
207  0xffffffff};
208  uint32_t test_version = 0xdeadbeef;
209 
210  // Pack (version, salt) into a keyblob array.
211  uint32_t keyblob[test_salt.size() + 1];
212  keyblob[0] = test_version;
213  for (size_t i = 0; i < test_salt.size(); i++) {
214  keyblob[i + 1] = test_salt[i];
215  }
216 
217  // Construct blinded key.
218  otcrypto_blinded_key_t key = {
219  .config = kConfigCtrSideloaded,
220  .keyblob_length = sizeof(keyblob),
221  .keyblob = keyblob,
222  .checksum = 0,
223  };
224 
225  // Extract the keymgr diversification data.
226  keymgr_diversification_t diversification;
227  EXPECT_OK(keyblob_to_keymgr_diversification(&key, &diversification));
228 
229  // Check that the version and salt match expectations.
230  EXPECT_EQ(diversification.version, test_version);
231  for (size_t i = 0; i < test_salt.size(); i++) {
232  EXPECT_EQ(diversification.salt[i], test_salt[i]);
233  }
234  EXPECT_EQ(diversification.salt[test_salt.size()], key.config.key_mode);
235 }
236 
237 TEST(Keyblob, ToKeymgrDiversificationBadlength) {
238  // Salt and version for the hardware-backed keys.
239  std::array<uint32_t, 6> test_salt = {0x01234567, 0x89abcdef, 0x00010203,
240  0x04050607, 0x08090a0b, 0x0c0d0e0f};
241  uint32_t test_version = 0xdeadbeef;
242 
243  // Pack (version, salt) into a keyblob array.
244  uint32_t keyblob[test_salt.size() + 1];
245  keyblob[0] = test_version;
246  for (size_t i = 0; i < test_salt.size(); i++) {
247  keyblob[i + 1] = test_salt[i];
248  }
249 
250  // Construct blinded key.
251  otcrypto_blinded_key_t key = {
252  .config = kConfigCtrSideloaded,
253  .keyblob_length = sizeof(keyblob),
254  .keyblob = keyblob,
255  .checksum = 0,
256  };
257 
258  // Try to extract the keymgr diversification data.
259  keymgr_diversification_t diversification;
260  EXPECT_NOT_OK(keyblob_to_keymgr_diversification(&key, &diversification));
261 }
262 
263 TEST(Keyblob, ToKeymgrDiversificationDifferentModes) {
264  // Salt for the hardware-backed key (one word too short).
265  std::array<uint32_t, 7> test_salt = {0x01234567, 0x89abcdef, 0x00010203,
266  0x04050607, 0x08090a0b, 0x0c0d0e0f,
267  0xffffffff};
268  uint32_t test_version = 0xdeadbeef;
269 
270  // Pack (version, salt) into a keyblob array.
271  uint32_t keyblob[test_salt.size() + 1];
272  keyblob[0] = test_version;
273  for (size_t i = 0; i < test_salt.size(); i++) {
274  keyblob[i + 1] = test_salt[i];
275  }
276 
277  // Construct blinded key for CTR mode.
278  otcrypto_blinded_key_t key1 = {
279  .config = kConfigCtrSideloaded,
280  .keyblob_length = sizeof(keyblob),
281  .keyblob = keyblob,
282  .checksum = 0,
283  };
284 
285  // Construct blinded key for OFB mode.
286  otcrypto_blinded_key_t key2 = {
287  .config = kConfigOfbSideloaded,
288  .keyblob_length = sizeof(keyblob),
289  .keyblob = keyblob,
290  .checksum = 0,
291  };
292 
293  // Extract the keymgr diversification data for both keys.
294  keymgr_diversification_t diversification1;
295  EXPECT_OK(keyblob_to_keymgr_diversification(&key1, &diversification1));
296  keymgr_diversification_t diversification2;
297  EXPECT_OK(keyblob_to_keymgr_diversification(&key2, &diversification2));
298 
299  // Expect different salts.
300  bool salts_equal = true;
301  for (size_t i = 0; i < ARRAYSIZE(diversification1.salt); i++) {
302  if (diversification1.salt[i] != diversification2.salt[i]) {
303  salts_equal = false;
304  }
305  }
306  EXPECT_EQ(salts_equal, false);
307 }
308 
309 TEST(Keyblob, RemaskDoesNotChangeKey) {
310  std::array<uint32_t, 4> test_key = {0x01234567, 0x89abcdef, 0x00010203,
311  0x04050607};
312  std::array<uint32_t, 4> test_mask0 = {0x08090a0b, 0x0c0d0e0f, 0x10111213,
313  0x14151617};
314  std::array<uint32_t, 4> test_mask1 = {0x18191a1b, 0x1c1d1e1f, 0x20212223,
315  0x24252627};
316 
317  // Test assumption; key and masks are the correct size.
318  ASSERT_EQ(test_key.size(), keyblob_share_num_words(kConfigCtr128));
319  ASSERT_EQ(test_mask0.size(), keyblob_share_num_words(kConfigCtr128));
320  ASSERT_EQ(test_mask1.size(), keyblob_share_num_words(kConfigCtr128));
321 
322  // Convert key and first mask to keyblob array.
323  size_t keyblob_words = keyblob_num_words(kConfigCtr128);
324  uint32_t keyblob[keyblob_words] = {0};
325  EXPECT_OK(keyblob_from_key_and_mask(test_key.data(), test_mask0.data(),
326  kConfigCtr128, keyblob));
327 
328  // Construct blinded key.
329  otcrypto_blinded_key_t key = {
330  .config = kConfigCtr128,
331  .keyblob_length = sizeof(keyblob),
332  .keyblob = keyblob,
333  .checksum = 0,
334  };
335 
336  // Remask the key using the second mask.
337  EXPECT_OK(keyblob_remask(&key, test_mask1.data()));
338 
339  // Retrieve pointers to each share.
340  uint32_t *share0;
341  uint32_t *share1;
342  EXPECT_OK(keyblob_to_shares(&key, &share0, &share1));
343 
344  // Unmask the key and check that it matches the original.
345  for (size_t i = 0; i < test_key.size(); i++) {
346  uint32_t share0 = keyblob[i];
347  uint32_t share1 = keyblob[test_key.size() + i];
348  EXPECT_EQ(share1, test_mask0[i] ^ test_mask1[i]);
349  EXPECT_EQ(share0 ^ share1, test_key[i]);
350  }
351 }
352 
353 TEST(Keyblob, RemaskWithZero) {
354  std::array<uint32_t, 4> test_key = {0x01234567, 0x89abcdef, 0x00010203,
355  0x04050607};
356  std::array<uint32_t, 4> test_mask0 = {0x08090a0b, 0x0c0d0e0f, 0x10111213,
357  0x14151617};
358  std::array<uint32_t, 4> test_mask1 = {0x18191a1b, 0x1c1d1e1f, 0x20212223,
359  0x24252627};
360 
361  // Test assumption; key and masks are the correct size.
362  ASSERT_EQ(test_key.size(), keyblob_share_num_words(kConfigCtr128));
363  ASSERT_EQ(test_mask0.size(), keyblob_share_num_words(kConfigCtr128));
364  ASSERT_EQ(test_mask1.size(), keyblob_share_num_words(kConfigCtr128));
365 
366  // Convert key and first mask to keyblob array.
367  size_t keyblob_words = keyblob_num_words(kConfigCtr128);
368  uint32_t keyblob[keyblob_words] = {0};
369  EXPECT_OK(keyblob_from_key_and_mask(test_key.data(), test_mask0.data(),
370  kConfigCtr128, keyblob));
371 
372  // Construct blinded key.
373  otcrypto_blinded_key_t key = {
374  .config = kConfigCtr128,
375  .keyblob_length = sizeof(keyblob),
376  .keyblob = keyblob,
377  .checksum = 0,
378  };
379 
380  // Remask the key using the second mask.
381  EXPECT_OK(keyblob_remask(&key, test_mask1.data()));
382 
383  // Retrieve pointers to each share.
384  uint32_t *share0;
385  uint32_t *share1;
386  EXPECT_OK(keyblob_to_shares(&key, &share0, &share1));
387 
388  // Unmask the key and check that it matches the original.
389  for (size_t i = 0; i < test_key.size(); i++) {
390  uint32_t share0 = keyblob[i];
391  uint32_t share1 = keyblob[test_key.size() + i];
392  EXPECT_EQ(share1, test_mask0[i] ^ test_mask1[i]);
393  EXPECT_EQ(share0 ^ share1, test_key[i]);
394  }
395 }
396 
397 } // namespace
398 } // namespace keyblob_unittest