pk11_chacha20poly1305_unittest.cc (26254B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include <memory> 8 #include "nss.h" 9 #include "pk11pub.h" 10 #include "pk11priv.h" 11 #include "sechash.h" 12 #include "secerr.h" 13 14 #include "cpputil.h" 15 #include "nss_scoped_ptrs.h" 16 17 #include "testvectors/chachapoly-vectors.h" 18 #include "gtest/gtest.h" 19 20 namespace nss_test { 21 22 static const CK_MECHANISM_TYPE kMech = CKM_CHACHA20_POLY1305; 23 static const CK_MECHANISM_TYPE kMechLegacy = CKM_NSS_CHACHA20_POLY1305; 24 static const CK_MECHANISM_TYPE kMechXor = CKM_CHACHA20; 25 static const CK_MECHANISM_TYPE kMechXorLegacy = CKM_NSS_CHACHA20_CTR; 26 // Some test data for simple tests. 27 static const uint8_t kKeyData[32] = {'k'}; 28 static const uint8_t kXorParamsLegacy[16] = {'c', 0, 0, 0, 'n'}; 29 static const uint8_t kCounter[4] = {'c', 0}; 30 static const uint8_t kNonce[12] = {'n', 0}; 31 static const CK_CHACHA20_PARAMS kXorParams{ 32 /* pBlockCounter */ const_cast<CK_BYTE_PTR>(kCounter), 33 /* blockCounterBits */ sizeof(kCounter) * 8, 34 /* pNonce */ const_cast<CK_BYTE_PTR>(kNonce), 35 /* ulNonceBits */ sizeof(kNonce) * 8, 36 }; 37 static const uint8_t kData[16] = {'d'}; 38 static const uint8_t kExpectedXor[sizeof(kData)] = { 39 0xd8, 0x15, 0xd3, 0xb3, 0xe9, 0x34, 0x3b, 0x7a, 40 0x24, 0xf6, 0x5f, 0xd7, 0x95, 0x3d, 0xd3, 0x51}; 41 static const size_t kTagLen = 16; 42 43 class Pkcs11ChaCha20Poly1305Test 44 : public ::testing::TestWithParam<ChaChaTestVector> { 45 public: 46 void EncryptDecrypt(const ScopedPK11SymKey& key, const bool invalid_iv, 47 const bool invalid_tag, const uint8_t* data, 48 size_t data_len, CK_MECHANISM_TYPE mech, SECItem* params, 49 std::vector<uint8_t>* nonce, std::vector<uint8_t>* aad, 50 const uint8_t* ct = nullptr, size_t ct_len = 0) { 51 std::vector<uint8_t> encrypted(data_len + kTagLen); 52 unsigned int encrypted_len = 0; 53 // Encrypt. 54 SECStatus rv = 55 PK11_Encrypt(key.get(), mech, params, encrypted.data(), &encrypted_len, 56 encrypted.size(), data, data_len); 57 58 // Return if encryption failure was expected due to invalid IV. 59 // Without valid ciphertext, all further tests can be skipped. 60 if (invalid_iv) { 61 EXPECT_EQ(rv, SECFailure); 62 EXPECT_EQ(0U, encrypted_len) 63 << "encrypted_len is unmodified after failure"; 64 return; 65 } 66 67 EXPECT_EQ(rv, SECSuccess); 68 EXPECT_EQ(encrypted.size(), static_cast<size_t>(encrypted_len)); 69 70 // Check ciphertext and tag. 71 if (ct) { 72 ASSERT_EQ(ct_len, encrypted_len); 73 EXPECT_TRUE(!memcmp(ct, encrypted.data(), encrypted.size() - 16)); 74 EXPECT_TRUE(!memcmp(ct, encrypted.data(), encrypted.size()) != 75 invalid_tag); 76 } 77 78 // Get the *estimated* plaintext length. This value should 79 // never be zero as it could lead to a NULL outPtr being 80 // passed to a subsequent decryption call (for AEAD we 81 // must authenticate even when the pt is zero-length). 82 unsigned int decrypt_bytes_needed = 0; 83 rv = PK11_Decrypt(key.get(), mech, params, nullptr, &decrypt_bytes_needed, 84 0, encrypted.data(), encrypted_len); 85 EXPECT_EQ(rv, SECSuccess); 86 EXPECT_GT(decrypt_bytes_needed, data_len); 87 88 // Now decrypt it 89 std::vector<uint8_t> decrypted(decrypt_bytes_needed); 90 unsigned int decrypted_len = 0; 91 rv = PK11_Decrypt(key.get(), mech, params, decrypted.data(), &decrypted_len, 92 decrypted.size(), encrypted.data(), encrypted.size()); 93 EXPECT_EQ(rv, SECSuccess); 94 95 // Check the plaintext. 96 ASSERT_EQ(data_len, decrypted_len); 97 EXPECT_TRUE(!memcmp(data, decrypted.data(), decrypted_len)); 98 99 // Decrypt with bogus data. 100 // Skip if there's no data to modify. 101 if (encrypted_len > 0) { 102 decrypted_len = 0; 103 std::vector<uint8_t> bogus_ciphertext(encrypted); 104 bogus_ciphertext[0] ^= 0xff; 105 rv = PK11_Decrypt(key.get(), mech, params, decrypted.data(), 106 &decrypted_len, decrypted.size(), 107 bogus_ciphertext.data(), encrypted_len); 108 EXPECT_EQ(rv, SECFailure); 109 EXPECT_EQ(0U, decrypted_len); 110 } 111 112 // Decrypt with bogus tag. 113 // Skip if there's no tag to modify. 114 if (encrypted_len > 0) { 115 decrypted_len = 0; 116 std::vector<uint8_t> bogus_tag(encrypted); 117 bogus_tag[encrypted_len - 1] ^= 0xff; 118 rv = PK11_Decrypt(key.get(), mech, params, decrypted.data(), 119 &decrypted_len, decrypted.size(), bogus_tag.data(), 120 encrypted_len); 121 EXPECT_EQ(rv, SECFailure); 122 EXPECT_EQ(0U, decrypted_len); 123 } 124 125 // Decrypt with bogus nonce. 126 // A nonce length of 0 is invalid and should be caught earlier. 127 ASSERT_NE(0U, nonce->size()); 128 decrypted_len = 0; 129 nonce->data()[0] ^= 0xff; 130 rv = PK11_Decrypt(key.get(), mech, params, decrypted.data(), &decrypted_len, 131 data_len, encrypted.data(), encrypted.size()); 132 EXPECT_EQ(rv, SECFailure); 133 EXPECT_EQ(0U, decrypted_len); 134 nonce->data()[0] ^= 0xff; // restore value 135 136 // Decrypt with bogus additional data. 137 // Skip when AAD was empty and can't be modified. 138 // Alternatively we could generate random aad. 139 if (aad->size() != 0) { 140 decrypted_len = 0; 141 aad->data()[0] ^= 0xff; 142 143 rv = PK11_Decrypt(key.get(), mech, params, decrypted.data(), 144 &decrypted_len, data_len, encrypted.data(), 145 encrypted.size()); 146 EXPECT_EQ(rv, SECFailure); 147 EXPECT_EQ(0U, decrypted_len); 148 } 149 } 150 151 void EncryptDecrypt(const ScopedPK11SymKey& key, const bool invalid_iv, 152 const bool invalid_tag, const uint8_t* data, 153 size_t data_len, const uint8_t* aad_ptr, size_t aad_len, 154 const uint8_t* iv_ptr, size_t iv_len, 155 const uint8_t* ct = nullptr, size_t ct_len = 0) { 156 std::vector<uint8_t> nonce(iv_ptr, iv_ptr + iv_len); 157 std::vector<uint8_t> aad(aad_ptr, aad_ptr + aad_len); 158 // Prepare AEAD params. 159 CK_SALSA20_CHACHA20_POLY1305_PARAMS aead_params; 160 aead_params.pNonce = toUcharPtr(nonce.data()); 161 aead_params.ulNonceLen = nonce.size(); 162 aead_params.pAAD = toUcharPtr(aad.data()); 163 aead_params.ulAADLen = aad.size(); 164 165 SECItem params = {siBuffer, reinterpret_cast<unsigned char*>(&aead_params), 166 sizeof(aead_params)}; 167 168 EncryptDecrypt(key, invalid_iv, invalid_tag, data, data_len, kMech, ¶ms, 169 &nonce, &aad, ct, ct_len); 170 } 171 172 void EncryptDecryptLegacy(const ScopedPK11SymKey& key, const bool invalid_iv, 173 const bool invalid_tag, const uint8_t* data, 174 size_t data_len, const uint8_t* aad_ptr, 175 size_t aad_len, const uint8_t* iv_ptr, 176 size_t iv_len, const uint8_t* ct = nullptr, 177 size_t ct_len = 0) { 178 std::vector<uint8_t> nonce(iv_ptr, iv_ptr + iv_len); 179 std::vector<uint8_t> aad(aad_ptr, aad_ptr + aad_len); 180 // Prepare AEAD params. 181 CK_NSS_AEAD_PARAMS aead_params; 182 aead_params.pNonce = toUcharPtr(nonce.data()); 183 aead_params.ulNonceLen = nonce.size(); 184 aead_params.pAAD = toUcharPtr(aad.data()); 185 aead_params.ulAADLen = aad.size(); 186 aead_params.ulTagLen = kTagLen; 187 188 SECItem params = {siBuffer, reinterpret_cast<unsigned char*>(&aead_params), 189 sizeof(aead_params)}; 190 191 // Encrypt with bad parameters (TagLen is too long). 192 unsigned int encrypted_len = 0; 193 std::vector<uint8_t> encrypted(data_len + aead_params.ulTagLen); 194 aead_params.ulTagLen = 158072; 195 SECStatus rv = 196 PK11_Encrypt(key.get(), kMechLegacy, ¶ms, encrypted.data(), 197 &encrypted_len, encrypted.size(), data, data_len); 198 EXPECT_EQ(SECFailure, rv); 199 EXPECT_EQ(0U, encrypted_len); 200 201 // Encrypt with bad parameters (TagLen is too short). 202 aead_params.ulTagLen = 2; 203 rv = PK11_Encrypt(key.get(), kMechLegacy, ¶ms, encrypted.data(), 204 &encrypted_len, encrypted.size(), data, data_len); 205 EXPECT_EQ(SECFailure, rv); 206 EXPECT_EQ(0U, encrypted_len); 207 208 // Encrypt. 209 aead_params.ulTagLen = kTagLen; 210 EncryptDecrypt(key, invalid_iv, invalid_tag, data, data_len, kMechLegacy, 211 ¶ms, &nonce, &aad, ct, ct_len); 212 } 213 214 void EncryptDecrypt(const ChaChaTestVector testvector) { 215 ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); 216 SECItem keyItem = {siBuffer, toUcharPtr(testvector.key.data()), 217 static_cast<unsigned int>(testvector.key.size())}; 218 219 // Import key. 220 ScopedPK11SymKey key(PK11_ImportSymKey(slot.get(), kMech, PK11_OriginUnwrap, 221 CKA_ENCRYPT, &keyItem, nullptr)); 222 EXPECT_TRUE(!!key); 223 224 // Check. 225 EncryptDecrypt(key, testvector.invalid_iv, testvector.invalid_tag, 226 testvector.plaintext.data(), testvector.plaintext.size(), 227 testvector.aad.data(), testvector.aad.size(), 228 testvector.iv.data(), testvector.iv.size(), 229 testvector.ciphertext.data(), testvector.ciphertext.size()); 230 } 231 232 void MessageInterfaceTest(CK_MECHANISM_TYPE mech, int iterations, 233 PRBool separateTag) { 234 // Generate a random key. 235 ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); 236 ASSERT_NE(nullptr, slot); 237 ScopedPK11SymKey sym_key( 238 PK11_KeyGen(slot.get(), mech, nullptr, 32, nullptr)); 239 ASSERT_NE(nullptr, sym_key); 240 241 int tagSize = kTagLen; 242 int cipher_simulated_size; 243 int output_len_message = 0; 244 int output_len_simulated = 0; 245 unsigned int output_len_v24 = 0; 246 247 std::vector<uint8_t> plainIn(17); 248 std::vector<uint8_t> plainOut_message(17); 249 std::vector<uint8_t> plainOut_simulated(17); 250 std::vector<uint8_t> plainOut_v24(17); 251 std::vector<uint8_t> nonce(12); 252 std::vector<uint8_t> cipher_message(33); 253 std::vector<uint8_t> cipher_simulated(33); 254 std::vector<uint8_t> cipher_v24(33); 255 std::vector<uint8_t> aad(16); 256 std::vector<uint8_t> tag_message(kTagLen); 257 std::vector<uint8_t> tag_simulated(kTagLen); 258 259 // Prepare AEAD v2.40 params. 260 CK_SALSA20_CHACHA20_POLY1305_PARAMS chacha_params; 261 chacha_params.pNonce = nonce.data(); 262 chacha_params.ulNonceLen = nonce.size(); 263 chacha_params.pAAD = aad.data(); 264 chacha_params.ulAADLen = aad.size(); 265 266 // Prepare AEAD MESSAGE params. 267 CK_SALSA20_CHACHA20_POLY1305_MSG_PARAMS chacha_message_params; 268 chacha_message_params.pNonce = nonce.data(); 269 chacha_message_params.ulNonceLen = nonce.size(); 270 if (separateTag) { 271 chacha_message_params.pTag = tag_message.data(); 272 } else { 273 chacha_message_params.pTag = cipher_message.data() + plainIn.size(); 274 } 275 276 // Prepare AEAD MESSAGE params for simulated case 277 CK_SALSA20_CHACHA20_POLY1305_MSG_PARAMS chacha_simulated_params; 278 chacha_simulated_params = chacha_message_params; 279 if (separateTag) { 280 // The simulated case, we have to allocate temp bufs for separate 281 // tags, make sure that works in both the encrypt and the decrypt 282 // cases. 283 chacha_simulated_params.pTag = tag_simulated.data(); 284 cipher_simulated_size = cipher_simulated.size() - tagSize; 285 } else { 286 chacha_simulated_params.pTag = cipher_simulated.data() + plainIn.size(); 287 cipher_simulated_size = cipher_simulated.size(); 288 } 289 SECItem params = {siBuffer, 290 reinterpret_cast<unsigned char*>(&chacha_params), 291 sizeof(chacha_params)}; 292 SECItem empty = {siBuffer, NULL, 0}; 293 294 // initialize our plain text, IV and aad. 295 ASSERT_EQ(PK11_GenerateRandom(plainIn.data(), plainIn.size()), SECSuccess); 296 ASSERT_EQ(PK11_GenerateRandom(aad.data(), aad.size()), SECSuccess); 297 298 // Initialize message encrypt context 299 ScopedPK11Context encrypt_message_context(PK11_CreateContextBySymKey( 300 mech, CKA_NSS_MESSAGE | CKA_ENCRYPT, sym_key.get(), &empty)); 301 ASSERT_NE(nullptr, encrypt_message_context); 302 ASSERT_FALSE(_PK11_ContextGetAEADSimulation(encrypt_message_context.get())); 303 304 // Initialize simulated encrypt context 305 ScopedPK11Context encrypt_simulated_context(PK11_CreateContextBySymKey( 306 mech, CKA_NSS_MESSAGE | CKA_ENCRYPT, sym_key.get(), &empty)); 307 ASSERT_NE(nullptr, encrypt_simulated_context); 308 ASSERT_EQ(SECSuccess, 309 _PK11_ContextSetAEADSimulation(encrypt_simulated_context.get())); 310 311 // Initialize message decrypt context 312 ScopedPK11Context decrypt_message_context(PK11_CreateContextBySymKey( 313 mech, CKA_NSS_MESSAGE | CKA_DECRYPT, sym_key.get(), &empty)); 314 ASSERT_NE(nullptr, decrypt_message_context); 315 ASSERT_FALSE(_PK11_ContextGetAEADSimulation(decrypt_message_context.get())); 316 317 // Initialize simulated decrypt context 318 ScopedPK11Context decrypt_simulated_context(PK11_CreateContextBySymKey( 319 mech, CKA_NSS_MESSAGE | CKA_DECRYPT, sym_key.get(), &empty)); 320 ASSERT_NE(nullptr, decrypt_simulated_context); 321 EXPECT_EQ(SECSuccess, 322 _PK11_ContextSetAEADSimulation(decrypt_simulated_context.get())); 323 324 // Now walk down our iterations. Each method of calculating the operation 325 // should agree at each step. 326 for (int i = 0; i < iterations; i++) { 327 // get a unique nonce for each iteration 328 EXPECT_EQ(PK11_GenerateRandom(nonce.data(), nonce.size()), SECSuccess); 329 EXPECT_EQ(SECSuccess, 330 PK11_AEADRawOp( 331 encrypt_message_context.get(), &chacha_message_params, 332 sizeof(chacha_message_params), aad.data(), aad.size(), 333 cipher_message.data(), &output_len_message, 334 cipher_message.size(), plainIn.data(), plainIn.size())); 335 EXPECT_EQ(SECSuccess, 336 PK11_AEADRawOp( 337 encrypt_simulated_context.get(), &chacha_simulated_params, 338 sizeof(chacha_simulated_params), aad.data(), aad.size(), 339 cipher_simulated.data(), &output_len_simulated, 340 cipher_simulated_size, plainIn.data(), plainIn.size())); 341 // make sure simulated and message is the same 342 EXPECT_EQ(output_len_message, output_len_simulated); 343 EXPECT_EQ(0, memcmp(cipher_message.data(), cipher_simulated.data(), 344 output_len_message)); 345 EXPECT_EQ(0, memcmp(chacha_message_params.pTag, 346 chacha_simulated_params.pTag, tagSize)); 347 // make sure v2.40 is the same. 348 EXPECT_EQ(SECSuccess, 349 PK11_Encrypt(sym_key.get(), mech, ¶ms, cipher_v24.data(), 350 &output_len_v24, cipher_v24.size(), plainIn.data(), 351 plainIn.size())); 352 EXPECT_EQ(output_len_message, (int)output_len_v24 - tagSize); 353 EXPECT_EQ(0, memcmp(cipher_message.data(), cipher_v24.data(), 354 output_len_message)); 355 EXPECT_EQ(0, memcmp(chacha_message_params.pTag, 356 cipher_v24.data() + output_len_message, tagSize)); 357 // now make sure we can decrypt 358 EXPECT_EQ( 359 SECSuccess, 360 PK11_AEADRawOp(decrypt_message_context.get(), &chacha_message_params, 361 sizeof(chacha_message_params), aad.data(), aad.size(), 362 plainOut_message.data(), &output_len_message, 363 plainOut_message.size(), cipher_message.data(), 364 output_len_message)); 365 EXPECT_EQ(output_len_message, (int)plainIn.size()); 366 EXPECT_EQ( 367 0, memcmp(plainOut_message.data(), plainIn.data(), plainIn.size())); 368 EXPECT_EQ(SECSuccess, 369 PK11_AEADRawOp(decrypt_simulated_context.get(), 370 &chacha_simulated_params, 371 sizeof(chacha_simulated_params), aad.data(), 372 aad.size(), plainOut_simulated.data(), 373 &output_len_simulated, plainOut_simulated.size(), 374 cipher_message.data(), output_len_simulated)); 375 EXPECT_EQ(output_len_simulated, (int)plainIn.size()); 376 EXPECT_EQ( 377 0, memcmp(plainOut_simulated.data(), plainIn.data(), plainIn.size())); 378 if (separateTag) { 379 // in the separateTag case, we need to copy the tag back to the 380 // end of the cipher_message.data() before using the v2.4 interface 381 memcpy(cipher_message.data() + output_len_message, 382 chacha_message_params.pTag, tagSize); 383 } 384 EXPECT_EQ(SECSuccess, 385 PK11_Decrypt(sym_key.get(), mech, ¶ms, plainOut_v24.data(), 386 &output_len_v24, plainOut_v24.size(), 387 cipher_message.data(), output_len_v24)); 388 EXPECT_EQ(output_len_v24, plainIn.size()); 389 EXPECT_EQ(0, memcmp(plainOut_v24.data(), plainIn.data(), plainIn.size())); 390 } 391 return; 392 } 393 394 protected: 395 }; 396 397 TEST_F(Pkcs11ChaCha20Poly1305Test, GenerateEncryptDecrypt) { 398 // Generate a random key. 399 ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); 400 ScopedPK11SymKey key(PK11_KeyGen(slot.get(), kMech, nullptr, 32, nullptr)); 401 EXPECT_TRUE(!!key); 402 403 // Generate random data. 404 std::vector<uint8_t> input(512); 405 SECStatus rv = 406 PK11_GenerateRandomOnSlot(slot.get(), input.data(), input.size()); 407 EXPECT_EQ(rv, SECSuccess); 408 409 // Generate random AAD. 410 std::vector<uint8_t> aad(16); 411 rv = PK11_GenerateRandomOnSlot(slot.get(), aad.data(), aad.size()); 412 EXPECT_EQ(rv, SECSuccess); 413 414 // Generate random IV. 415 std::vector<uint8_t> iv(12); 416 rv = PK11_GenerateRandomOnSlot(slot.get(), iv.data(), iv.size()); 417 EXPECT_EQ(rv, SECSuccess); 418 419 // Check. 420 EncryptDecrypt(key, false, false, input.data(), input.size(), aad.data(), 421 aad.size(), iv.data(), iv.size()); 422 } 423 424 TEST_F(Pkcs11ChaCha20Poly1305Test, Xor) { 425 ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); 426 SECItem keyItem = {siBuffer, toUcharPtr(kKeyData), 427 static_cast<unsigned int>(sizeof(kKeyData))}; 428 ScopedPK11SymKey key(PK11_ImportSymKey( 429 slot.get(), kMechXor, PK11_OriginUnwrap, CKA_ENCRYPT, &keyItem, nullptr)); 430 EXPECT_TRUE(!!key); 431 432 SECItem params = {siBuffer, 433 toUcharPtr(reinterpret_cast<const uint8_t*>(&kXorParams)), 434 static_cast<unsigned int>(sizeof(kXorParams))}; 435 uint8_t encrypted[sizeof(kData)]; 436 unsigned int encrypted_len = 88; // This should be overwritten. 437 SECStatus rv = 438 PK11_Encrypt(key.get(), kMechXor, ¶ms, encrypted, &encrypted_len, 439 sizeof(encrypted), kData, sizeof(kData)); 440 ASSERT_EQ(SECSuccess, rv); 441 ASSERT_EQ(sizeof(kExpectedXor), static_cast<size_t>(encrypted_len)); 442 EXPECT_EQ(0, memcmp(kExpectedXor, encrypted, sizeof(kExpectedXor))); 443 444 // Decrypting has the same effect. 445 rv = PK11_Decrypt(key.get(), kMechXor, ¶ms, encrypted, &encrypted_len, 446 sizeof(encrypted), kData, sizeof(kData)); 447 ASSERT_EQ(SECSuccess, rv); 448 ASSERT_EQ(sizeof(kData), static_cast<size_t>(encrypted_len)); 449 EXPECT_EQ(0, memcmp(kExpectedXor, encrypted, sizeof(kExpectedXor))); 450 451 // Operating in reverse too. 452 rv = PK11_Encrypt(key.get(), kMechXor, ¶ms, encrypted, &encrypted_len, 453 sizeof(encrypted), kExpectedXor, sizeof(kExpectedXor)); 454 ASSERT_EQ(SECSuccess, rv); 455 ASSERT_EQ(sizeof(kExpectedXor), static_cast<size_t>(encrypted_len)); 456 EXPECT_EQ(0, memcmp(kData, encrypted, sizeof(kData))); 457 } 458 459 TEST_F(Pkcs11ChaCha20Poly1305Test, XorLegacy) { 460 ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); 461 SECItem keyItem = {siBuffer, toUcharPtr(kKeyData), 462 static_cast<unsigned int>(sizeof(kKeyData))}; 463 ScopedPK11SymKey key(PK11_ImportSymKey(slot.get(), kMechXorLegacy, 464 PK11_OriginUnwrap, CKA_ENCRYPT, 465 &keyItem, nullptr)); 466 EXPECT_TRUE(!!key); 467 468 SECItem ctrNonceItem = {siBuffer, toUcharPtr(kXorParamsLegacy), 469 static_cast<unsigned int>(sizeof(kXorParamsLegacy))}; 470 uint8_t encrypted[sizeof(kData)]; 471 unsigned int encrypted_len = 88; // This should be overwritten. 472 SECStatus rv = 473 PK11_Encrypt(key.get(), kMechXorLegacy, &ctrNonceItem, encrypted, 474 &encrypted_len, sizeof(encrypted), kData, sizeof(kData)); 475 ASSERT_EQ(SECSuccess, rv); 476 ASSERT_EQ(sizeof(kExpectedXor), static_cast<size_t>(encrypted_len)); 477 EXPECT_EQ(0, memcmp(kExpectedXor, encrypted, sizeof(kExpectedXor))); 478 479 // Decrypting has the same effect. 480 rv = PK11_Decrypt(key.get(), kMechXorLegacy, &ctrNonceItem, encrypted, 481 &encrypted_len, sizeof(encrypted), kData, sizeof(kData)); 482 ASSERT_EQ(SECSuccess, rv); 483 ASSERT_EQ(sizeof(kData), static_cast<size_t>(encrypted_len)); 484 EXPECT_EQ(0, memcmp(kExpectedXor, encrypted, sizeof(kExpectedXor))); 485 486 // Operating in reverse too. 487 rv = PK11_Encrypt(key.get(), kMechXorLegacy, &ctrNonceItem, encrypted, 488 &encrypted_len, sizeof(encrypted), kExpectedXor, 489 sizeof(kExpectedXor)); 490 ASSERT_EQ(SECSuccess, rv); 491 ASSERT_EQ(sizeof(kExpectedXor), static_cast<size_t>(encrypted_len)); 492 EXPECT_EQ(0, memcmp(kData, encrypted, sizeof(kData))); 493 } 494 495 // This test just ensures that a key can be generated for use with the XOR 496 // function. The result is random and therefore cannot be checked. 497 TEST_F(Pkcs11ChaCha20Poly1305Test, GenerateXor) { 498 ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); 499 ScopedPK11SymKey key(PK11_KeyGen(slot.get(), kMechXor, nullptr, 32, nullptr)); 500 EXPECT_TRUE(!!key); 501 502 std::vector<uint8_t> iv(16); 503 SECStatus rv = PK11_GenerateRandomOnSlot(slot.get(), iv.data(), iv.size()); 504 EXPECT_EQ(SECSuccess, rv); 505 506 CK_CHACHA20_PARAMS chacha_params; 507 chacha_params.pBlockCounter = iv.data(); 508 chacha_params.blockCounterBits = 32; 509 chacha_params.pNonce = iv.data() + 4; 510 chacha_params.ulNonceBits = 96; 511 512 SECItem params = { 513 siBuffer, toUcharPtr(reinterpret_cast<const uint8_t*>(&chacha_params)), 514 static_cast<unsigned int>(sizeof(chacha_params))}; 515 uint8_t encrypted[sizeof(kData)]; 516 unsigned int encrypted_len = 88; // This should be overwritten. 517 rv = PK11_Encrypt(key.get(), kMechXor, ¶ms, encrypted, &encrypted_len, 518 sizeof(encrypted), kData, sizeof(kData)); 519 ASSERT_EQ(SECSuccess, rv); 520 ASSERT_EQ(sizeof(kData), static_cast<size_t>(encrypted_len)); 521 } 522 523 TEST_F(Pkcs11ChaCha20Poly1305Test, GenerateXorLegacy) { 524 ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); 525 ScopedPK11SymKey key( 526 PK11_KeyGen(slot.get(), kMechXorLegacy, nullptr, 32, nullptr)); 527 EXPECT_TRUE(!!key); 528 529 std::vector<uint8_t> iv(16); 530 SECStatus rv = PK11_GenerateRandomOnSlot(slot.get(), iv.data(), iv.size()); 531 EXPECT_EQ(SECSuccess, rv); 532 533 SECItem params = {siBuffer, toUcharPtr(iv.data()), 534 static_cast<unsigned int>(iv.size())}; 535 uint8_t encrypted[sizeof(kData)]; 536 unsigned int encrypted_len = 88; // This should be overwritten. 537 rv = PK11_Encrypt(key.get(), kMechXorLegacy, ¶ms, encrypted, 538 &encrypted_len, sizeof(encrypted), kData, sizeof(kData)); 539 ASSERT_EQ(SECSuccess, rv); 540 ASSERT_EQ(sizeof(kData), static_cast<size_t>(encrypted_len)); 541 } 542 543 TEST_F(Pkcs11ChaCha20Poly1305Test, XorInvalidParams) { 544 ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); 545 ScopedPK11SymKey key(PK11_KeyGen(slot.get(), kMech, nullptr, 32, nullptr)); 546 EXPECT_TRUE(!!key); 547 548 SECItem params = {siBuffer, 549 toUcharPtr(reinterpret_cast<const uint8_t*>(&kXorParams)), 550 static_cast<unsigned int>(sizeof(kXorParams)) - 1}; 551 uint8_t encrypted[sizeof(kData)]; 552 unsigned int encrypted_len = 88; 553 SECStatus rv = 554 PK11_Encrypt(key.get(), kMechXor, ¶ms, encrypted, &encrypted_len, 555 sizeof(encrypted), kData, sizeof(kData)); 556 EXPECT_EQ(SECFailure, rv); 557 558 params.data = nullptr; 559 rv = PK11_Encrypt(key.get(), kMechXor, ¶ms, encrypted, &encrypted_len, 560 sizeof(encrypted), kData, sizeof(kData)); 561 EXPECT_EQ(SECFailure, rv); 562 EXPECT_EQ(SEC_ERROR_BAD_DATA, PORT_GetError()); 563 } 564 565 TEST_F(Pkcs11ChaCha20Poly1305Test, XorLegacyInvalidParams) { 566 ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); 567 ScopedPK11SymKey key(PK11_KeyGen(slot.get(), kMech, nullptr, 32, nullptr)); 568 EXPECT_TRUE(!!key); 569 570 SECItem params = {siBuffer, toUcharPtr(kXorParamsLegacy), 571 static_cast<unsigned int>(sizeof(kXorParamsLegacy)) - 1}; 572 uint8_t encrypted[sizeof(kData)]; 573 unsigned int encrypted_len = 88; 574 SECStatus rv = 575 PK11_Encrypt(key.get(), kMechXor, ¶ms, encrypted, &encrypted_len, 576 sizeof(encrypted), kData, sizeof(kData)); 577 EXPECT_EQ(SECFailure, rv); 578 579 params.data = nullptr; 580 rv = PK11_Encrypt(key.get(), kMechXor, ¶ms, encrypted, &encrypted_len, 581 sizeof(encrypted), kData, sizeof(kData)); 582 EXPECT_EQ(SECFailure, rv); 583 EXPECT_EQ(SEC_ERROR_BAD_DATA, PORT_GetError()); 584 } 585 586 TEST_P(Pkcs11ChaCha20Poly1305Test, TestVectors) { EncryptDecrypt(GetParam()); } 587 588 INSTANTIATE_TEST_SUITE_P(NSSTestVector, Pkcs11ChaCha20Poly1305Test, 589 ::testing::ValuesIn(kChaCha20Vectors)); 590 591 INSTANTIATE_TEST_SUITE_P(WycheproofTestVector, Pkcs11ChaCha20Poly1305Test, 592 ::testing::ValuesIn(kChaCha20WycheproofVectors)); 593 594 // basic message interface it's the most common configuration 595 TEST_F(Pkcs11ChaCha20Poly1305Test, ChaCha201305MessageInterfaceBasic) { 596 MessageInterfaceTest(CKM_CHACHA20_POLY1305, 16, PR_FALSE); 597 } 598 599 // basic interface, but return the tags in a separate buffer. This triggers 600 // different behaviour in the simulated case, which has to buffer the 601 // intermediate values in a separate buffer. 602 TEST_F(Pkcs11ChaCha20Poly1305Test, 603 ChaCha20Poly1305MessageInterfaceSeparateTags) { 604 MessageInterfaceTest(CKM_CHACHA20_POLY1305, 16, PR_TRUE); 605 } 606 607 } // namespace nss_test