blob: 1ab7bec21192ebde099d85c241d532320cea2649 [file] [log] [blame]
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///////////////////////////////////////////////////////////////////////////////
#include "tink/experimental/pqcrypto/kem/subtle/cecpq2_hkdf_recipient_kem_boringssl.h"
#include <string>
#include <utility>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/status/status.h"
#include "openssl/curve25519.h"
#include "openssl/hrss.h"
#include "tink/config/tink_fips.h"
#include "tink/subtle/random.h"
#include "tink/util/test_matchers.h"
#include "tink/util/test_util.h"
using ::crypto::tink::test::IsOk;
using ::crypto::tink::test::StatusIs;
using ::testing::HasSubstr;
namespace crypto {
namespace tink {
namespace subtle {
namespace {
// CECPQ2 test vector from BoringSSL
const char kHrssKeyGenEntropy[] =
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324"
"25262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243444546474849"
"4a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e"
"6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f90919293"
"9495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8"
"b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdd"
"dedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff000102"
"030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324252627"
"28292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c"
"4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f7071"
"72737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f90919293949596"
"9798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babb"
"bcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0"
"e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff000102030405"
"060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a"
"2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f"
"505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f7071727374"
"75767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f90919293949596979899"
"9a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbebfc0"
"c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5"
"e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff000102030405060708090a"
"0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f"
"303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f5051525354"
"55565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f70717273747576777879"
"7a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e"
"9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3"
"c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8"
"e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff000102030405060708090a0b0c0d"
"0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132"
"333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f5051525354555657"
"58595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c"
"7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1"
"a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6"
"c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaeb"
"ecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff000102030405060708090a0b0c0d0e0f10"
"1112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435"
"363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a"
"5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797c7d7e7f8081"
"82838485868788898a8b8c8d8e8f909192939495969798999a9b";
const char kCecpq2KemBytes[] =
"5b9cbc8389eb7b6ce907a61d63b6ea1e46f77b65821fb394bc8508d7584f7365e0c077eb7a"
"487d744e4f6db95c18e95b476c789d9802849ff24543860ec69348d820ff82389e78b42cb3"
"42e4b3abdfed65240ca5952cbf4c28fcb8e7c6bc76a0f53f297323f16c107c088e163ada17"
"a30d4644ee6f70f1885135339176eb98c104db97ab88b90487d9b834d338e790052e45e0ac"
"360c5958b1f5656d281a39d9d28317eeeb6f7d293c79cf48f16d35c28ce86718cc9d9b8d07"
"7a4e56a8002e6767bbc1da4a7b9fa64a5c40cce4ddf5c044fea5a21cdcf231f4011f69157e"
"8c54b6470c1d9f1afaf746a3cb342c184565c4f20ef8c7961d295c90d3dfb28e21f915407e"
"d384521dd9eeede8711cdb48f52082c461fd6d719fd803908efced4dab6eb2e966fdcc3aa3"
"99533576ea0888baf0b753f34c1a8f7fe41b8bfc993e4ca9d917106460fd8176e637b0e33e"
"c0f7067e34a5f4b95f66e681c85eb2266b8cadd0940122f6be1a0b34fc33c084a5e0128a08"
"ae8aaf550c344b2bdda37cc0ede88d98477c81251b9f08269dfc198e39c41a3c4270493757"
"870f76b1c4be255e1c0657c6883428df603309c5ccf4c433858b48e827b7722244ffe789f9"
"7199ed6247b0229ea67cafa9982b5c8a423477a3c8131ecf32a770a8adc1665c8faf146dc4"
"4505cdcb80fa0ea6ca7286d2b7392677f814d0cdddf7dcda258e3c21fdef92ee52f7c3c7e2"
"2d1c575abad8aa0d09a7b3cca15ddb042182efbac2c854b1bed72a91d8eb7254c17424245a"
"03f7cdab91d163f1609f2207ad102b971c6fcec029c2b2b81bbd14c8b98066c186fc935f6e"
"0b7a7b8e428c08d160b9f866247d88582fd252753a8a1cfa1ea11c9146799ae58addc275ed"
"0db82b4f8f95cace21a47a0d147f2d98f088c36fadb50424914165d3a57efb531cccd0f77c"
"91080eddd46c73aaa57ad224c93b6fda068adb2ea8e9e13e08eebe966572686ff750e7a718"
"dac294dae3bcca03d8f77acc44a160a87fdcef80f462c6064eb6ac7717b7b33ef86d8a6183"
"3afdbb935b1a33f8ee7d9e5cf8c9d53e3d429be50decc90f6f03b04185b9fef9b1b4c3d913"
"03fa0de7d1b4c8f6b5117a9209217ba9894c19900d96324f77fc7f8ca3392a56e65cd1860a"
"72f4a31ba530043c15204be42d1af14448fcdac141db71fd920053e470d0baf6ef1772b8ea"
"6d41164d1f5918bd1fc56b6a6c2ea61a33748bc59f1601777e37e763e1a38c1f71e94fad15"
"8bf3c9acdc19ad921800f6a1d597a33d9e7802c38f75d8ad22bfef195d15341a7c9bafd4f2"
"f95f72889ce458da468f79302bd93bbcab2877750e2c23479514ebf04a3e5393a7f4829c34"
"8b8042b2a7b07c6ce107f4343eed339cb3dea59161258e8c5456be1aac17d27aa412542a51"
"d00ed1c144500539a7b61445caf85f066b5d5ec7e9276f38e031cff8cc2eb94a101bb4344b"
"90bbf2e03c797f39590c014c0d2d71f1bdda1a78cf266fb5a90720e68cd0add4ca246cc528"
"1dfbcce79372996163604c5ca9b61532a4bc1ff663612c26a70e5f1b25ce3f64df6db08fd2"
"e93b35d0598122f165861510e8a7a16fb4341c79d59e8dc8a5bb8271810034556b9656130e"
"e739a26fbe542a130313d21d719abe0900e18d59b54402";
const char kCecpq2X25519PrivateKeyHex[] =
"b79cbf241478d6f5139d517cf1beae62296a9e86d05d9e14fcb52d80d30eaebe";
const char kCorrectSharedSecret[] =
"4ba608d54c2c2159e7aa8f576df5d4403b9ad8d2718cf76e461da09343948e63";
const char kFailSharedSecret[] =
"c3d8a7f03b25ce23287dd6e7c49596104732fa855266e4f6a4dc79eaaf2757ad";
const char kSaltHex[] = "0b0b0b0b";
const char kInfoHex[] = "0b0b0b0b0b0b0b0b";
// This test evaluates the creation of a Cecpq2HkdfRecipientKemBoringSslTest
// instance with an unknown curve type. It should fail with an
// absl::StatusCode::kUnimplemented error.
TEST(Cecpq2HkdfRecipientKemBoringSslTest, TestUnknownCurve) {
if (IsFipsModeEnabled()) {
GTEST_SKIP() << "Not supported in FIPS-only mode";
}
// Creating the CECPQ2 recipient KEM using HRSS and X25519 private keys
util::SecretData hrss_private_key_seed =
util::SecretDataFromStringView(test::HexDecodeOrDie(kHrssKeyGenEntropy));
auto status_or_recipient_kem = Cecpq2HkdfRecipientKemBoringSsl::New(
EllipticCurveType::UNKNOWN_CURVE,
util::SecretDataFromStringView(
test::HexDecodeOrDie(kCecpq2X25519PrivateKeyHex)),
std::move(hrss_private_key_seed));
// The instance creation above should fail with an unimplemented algorithm
// error given the UNKNOWN_CURVE parameter
EXPECT_EQ(absl::StatusCode::kUnimplemented,
status_or_recipient_kem.status().code());
}
// This test evaluates the case where a unsupported curve (NIST_P256) is
// specified. This test should fail with an absl::StatusCode::kUnimplemented
// error.
TEST(Cecpq2HkdfRecipientKemBoringSslTest, TestUnsupportedCurve) {
if (IsFipsModeEnabled()) {
GTEST_SKIP() << "Not supported in FIPS-only mode";
}
// Creating the CECPQ2 recipient KEM using HRSS and X25519 private keys
util::SecretData hrss_private_key_seed =
util::SecretDataFromStringView(test::HexDecodeOrDie(kHrssKeyGenEntropy));
auto status_or_recipient_kem = Cecpq2HkdfRecipientKemBoringSsl::New(
EllipticCurveType::NIST_P256,
util::SecretDataFromStringView(
test::HexDecodeOrDie(kCecpq2X25519PrivateKeyHex)),
std::move(hrss_private_key_seed));
// The instance creation above should fail with an unimplemented algorithm
// error given the UNKNOWN_CURVE parameter
EXPECT_EQ(absl::StatusCode::kUnimplemented,
status_or_recipient_kem.status().code());
}
// This test checks that an error is triggered if an output key lenth smaller
// than 32 bytes is specified.
TEST(Cecpq2HkdfRecipientKemBoringSslTest, TestNotPostQuantumSecureKeyLength) {
if (IsFipsModeEnabled()) {
GTEST_SKIP() << "Not supported in FIPS-only mode";
}
// Not post-quantum secure output key length
int out_len = 31;
// Creating the CECPQ2 recipient KEM using HRSS and X25519 private keys
util::SecretData hrss_private_key_seed =
util::SecretDataFromStringView(test::HexDecodeOrDie(kHrssKeyGenEntropy));
auto cecpq2_recipient_kem_or = Cecpq2HkdfRecipientKemBoringSsl::New(
EllipticCurveType::CURVE25519,
util::SecretDataFromStringView(
test::HexDecodeOrDie(kCecpq2X25519PrivateKeyHex)),
std::move(hrss_private_key_seed));
ASSERT_THAT(cecpq2_recipient_kem_or, IsOk());
auto cecpq2_recipient_kem = std::move(cecpq2_recipient_kem_or).value();
// Recovering the symmetric key
auto kem_key_or = cecpq2_recipient_kem->GenerateKey(
test::HexDecodeOrDie(kCecpq2KemBytes), HashType::SHA256,
test::HexDecodeOrDie(kSaltHex), test::HexDecodeOrDie(kInfoHex), out_len,
EcPointFormat::COMPRESSED);
EXPECT_THAT(kem_key_or.status(),
StatusIs(absl::StatusCode::kInvalidArgument,
HasSubstr("not post-quantum secure")));
}
TEST(Cecpq2HkdfRecipientKemBoringSslTest, TestRecipientFlowSuccess) {
if (IsFipsModeEnabled()) {
GTEST_SKIP() << "Not supported in FIPS-only mode";
}
int out_len = 32;
// Creating the CECPQ2 recipient KEM using HRSS and X25519 private keys
util::SecretData hrss_private_key_seed =
util::SecretDataFromStringView(test::HexDecodeOrDie(kHrssKeyGenEntropy));
auto cecpq2_recipient_kem_or = Cecpq2HkdfRecipientKemBoringSsl::New(
EllipticCurveType::CURVE25519,
util::SecretDataFromStringView(
test::HexDecodeOrDie(kCecpq2X25519PrivateKeyHex)),
std::move(hrss_private_key_seed));
ASSERT_THAT(cecpq2_recipient_kem_or, IsOk());
auto cecpq2_recipient_kem = std::move(cecpq2_recipient_kem_or).value();
// Recovering the symmetric key
auto kem_key_or = cecpq2_recipient_kem->GenerateKey(
test::HexDecodeOrDie(kCecpq2KemBytes), HashType::SHA256,
test::HexDecodeOrDie(kSaltHex), test::HexDecodeOrDie(kInfoHex), out_len,
EcPointFormat::COMPRESSED);
ASSERT_THAT(kem_key_or, IsOk());
// The generated symmetric key should match the expected one
EXPECT_EQ(kCorrectSharedSecret,
test::HexEncode(util::SecretDataAsStringView(kem_key_or.value())));
}
TEST(Cecpq2HkdfRecipientKemBoringSslTest, TestRecipientFlowFailure) {
if (IsFipsModeEnabled()) {
GTEST_SKIP() << "Not supported in FIPS-only mode";
}
int out_len = 32;
// The following kem_bytes is not correct. The 50-th position of the HRSS
// kem_bytes has been modified (its original value xored with 4). This
// modified HRSS kem_bytes matches the one used in BoringSSL test vector. This
// change will result in an HRSS decapsulation failure which produces a
// symmetric key using a deterministic algorithm based on HMAC-SHA256.
std::string kem_bytes_modified = test::HexDecodeOrDie(kCecpq2KemBytes);
kem_bytes_modified[X25519_PUBLIC_VALUE_LEN + 50] ^= 0x04;
// Creating the CECPQ2 recipient KEM using HRSS and X25519 private keys
util::SecretData hrss_private_key_seed =
util::SecretDataFromStringView(test::HexDecodeOrDie(kHrssKeyGenEntropy));
auto cecpq2_recipient_kem_or = Cecpq2HkdfRecipientKemBoringSsl::New(
EllipticCurveType::CURVE25519,
util::SecretDataFromStringView(
test::HexDecodeOrDie(kCecpq2X25519PrivateKeyHex)),
std::move(hrss_private_key_seed));
ASSERT_THAT(cecpq2_recipient_kem_or, IsOk());
auto cecpq2_recipient_kem = std::move(cecpq2_recipient_kem_or).value();
// Recovering the symmetric key
auto kem_key_or = cecpq2_recipient_kem->GenerateKey(
kem_bytes_modified, HashType::SHA256, test::HexDecodeOrDie(kSaltHex),
test::HexDecodeOrDie(kInfoHex), out_len, EcPointFormat::COMPRESSED);
ASSERT_THAT(kem_key_or, IsOk());
// The produced symmetric key should match the one produced by CECPQ2 in case
// of HRSS decapsulation failure for the altered HRSS kem_bytes
EXPECT_EQ(kFailSharedSecret,
test::HexEncode(util::SecretDataAsStringView(kem_key_or.value())));
}
} // namespace
} // namespace subtle
} // namespace tink
} // namespace crypto