1 // Copyright 2020 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 ///////////////////////////////////////////////////////////////////////////////
16
17 #include "tink/experimental/pqcrypto/kem/subtle/cecpq2_hkdf_recipient_kem_boringssl.h"
18
19 #include <string>
20 #include <utility>
21
22 #include "gmock/gmock.h"
23 #include "gtest/gtest.h"
24 #include "absl/status/status.h"
25 #include "openssl/curve25519.h"
26 #include "openssl/hrss.h"
27 #include "tink/config/tink_fips.h"
28 #include "tink/subtle/random.h"
29 #include "tink/util/test_matchers.h"
30 #include "tink/util/test_util.h"
31
32 using ::crypto::tink::test::IsOk;
33 using ::crypto::tink::test::StatusIs;
34 using ::testing::HasSubstr;
35
36 namespace crypto {
37 namespace tink {
38 namespace subtle {
39 namespace {
40
41 // CECPQ2 test vector from BoringSSL
42 const char kHrssKeyGenEntropy[] =
43 "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324"
44 "25262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f40414243444546474849"
45 "4a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e"
46 "6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f90919293"
47 "9495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8"
48 "b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdd"
49 "dedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff000102"
50 "030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324252627"
51 "28292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c"
52 "4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f7071"
53 "72737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f90919293949596"
54 "9798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babb"
55 "bcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0"
56 "e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff000102030405"
57 "060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a"
58 "2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f"
59 "505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f7071727374"
60 "75767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f90919293949596979899"
61 "9a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbebfc0"
62 "c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5"
63 "e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff000102030405060708090a"
64 "0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f"
65 "303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f5051525354"
66 "55565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f70717273747576777879"
67 "7a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e"
68 "9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3"
69 "c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8"
70 "e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff000102030405060708090a0b0c0d"
71 "0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132"
72 "333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f5051525354555657"
73 "58595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c"
74 "7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1"
75 "a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6"
76 "c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaeb"
77 "ecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff000102030405060708090a0b0c0d0e0f10"
78 "1112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435"
79 "363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a"
80 "5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797c7d7e7f8081"
81 "82838485868788898a8b8c8d8e8f909192939495969798999a9b";
82 const char kCecpq2KemBytes[] =
83 "5b9cbc8389eb7b6ce907a61d63b6ea1e46f77b65821fb394bc8508d7584f7365e0c077eb7a"
84 "487d744e4f6db95c18e95b476c789d9802849ff24543860ec69348d820ff82389e78b42cb3"
85 "42e4b3abdfed65240ca5952cbf4c28fcb8e7c6bc76a0f53f297323f16c107c088e163ada17"
86 "a30d4644ee6f70f1885135339176eb98c104db97ab88b90487d9b834d338e790052e45e0ac"
87 "360c5958b1f5656d281a39d9d28317eeeb6f7d293c79cf48f16d35c28ce86718cc9d9b8d07"
88 "7a4e56a8002e6767bbc1da4a7b9fa64a5c40cce4ddf5c044fea5a21cdcf231f4011f69157e"
89 "8c54b6470c1d9f1afaf746a3cb342c184565c4f20ef8c7961d295c90d3dfb28e21f915407e"
90 "d384521dd9eeede8711cdb48f52082c461fd6d719fd803908efced4dab6eb2e966fdcc3aa3"
91 "99533576ea0888baf0b753f34c1a8f7fe41b8bfc993e4ca9d917106460fd8176e637b0e33e"
92 "c0f7067e34a5f4b95f66e681c85eb2266b8cadd0940122f6be1a0b34fc33c084a5e0128a08"
93 "ae8aaf550c344b2bdda37cc0ede88d98477c81251b9f08269dfc198e39c41a3c4270493757"
94 "870f76b1c4be255e1c0657c6883428df603309c5ccf4c433858b48e827b7722244ffe789f9"
95 "7199ed6247b0229ea67cafa9982b5c8a423477a3c8131ecf32a770a8adc1665c8faf146dc4"
96 "4505cdcb80fa0ea6ca7286d2b7392677f814d0cdddf7dcda258e3c21fdef92ee52f7c3c7e2"
97 "2d1c575abad8aa0d09a7b3cca15ddb042182efbac2c854b1bed72a91d8eb7254c17424245a"
98 "03f7cdab91d163f1609f2207ad102b971c6fcec029c2b2b81bbd14c8b98066c186fc935f6e"
99 "0b7a7b8e428c08d160b9f866247d88582fd252753a8a1cfa1ea11c9146799ae58addc275ed"
100 "0db82b4f8f95cace21a47a0d147f2d98f088c36fadb50424914165d3a57efb531cccd0f77c"
101 "91080eddd46c73aaa57ad224c93b6fda068adb2ea8e9e13e08eebe966572686ff750e7a718"
102 "dac294dae3bcca03d8f77acc44a160a87fdcef80f462c6064eb6ac7717b7b33ef86d8a6183"
103 "3afdbb935b1a33f8ee7d9e5cf8c9d53e3d429be50decc90f6f03b04185b9fef9b1b4c3d913"
104 "03fa0de7d1b4c8f6b5117a9209217ba9894c19900d96324f77fc7f8ca3392a56e65cd1860a"
105 "72f4a31ba530043c15204be42d1af14448fcdac141db71fd920053e470d0baf6ef1772b8ea"
106 "6d41164d1f5918bd1fc56b6a6c2ea61a33748bc59f1601777e37e763e1a38c1f71e94fad15"
107 "8bf3c9acdc19ad921800f6a1d597a33d9e7802c38f75d8ad22bfef195d15341a7c9bafd4f2"
108 "f95f72889ce458da468f79302bd93bbcab2877750e2c23479514ebf04a3e5393a7f4829c34"
109 "8b8042b2a7b07c6ce107f4343eed339cb3dea59161258e8c5456be1aac17d27aa412542a51"
110 "d00ed1c144500539a7b61445caf85f066b5d5ec7e9276f38e031cff8cc2eb94a101bb4344b"
111 "90bbf2e03c797f39590c014c0d2d71f1bdda1a78cf266fb5a90720e68cd0add4ca246cc528"
112 "1dfbcce79372996163604c5ca9b61532a4bc1ff663612c26a70e5f1b25ce3f64df6db08fd2"
113 "e93b35d0598122f165861510e8a7a16fb4341c79d59e8dc8a5bb8271810034556b9656130e"
114 "e739a26fbe542a130313d21d719abe0900e18d59b54402";
115 const char kCecpq2X25519PrivateKeyHex[] =
116 "b79cbf241478d6f5139d517cf1beae62296a9e86d05d9e14fcb52d80d30eaebe";
117 const char kCorrectSharedSecret[] =
118 "4ba608d54c2c2159e7aa8f576df5d4403b9ad8d2718cf76e461da09343948e63";
119 const char kFailSharedSecret[] =
120 "c3d8a7f03b25ce23287dd6e7c49596104732fa855266e4f6a4dc79eaaf2757ad";
121 const char kSaltHex[] = "0b0b0b0b";
122 const char kInfoHex[] = "0b0b0b0b0b0b0b0b";
123
124 // This test evaluates the creation of a Cecpq2HkdfRecipientKemBoringSslTest
125 // instance with an unknown curve type. It should fail with an
126 // absl::StatusCode::kUnimplemented error.
TEST(Cecpq2HkdfRecipientKemBoringSslTest,TestUnknownCurve)127 TEST(Cecpq2HkdfRecipientKemBoringSslTest, TestUnknownCurve) {
128 if (IsFipsModeEnabled()) {
129 GTEST_SKIP() << "Not supported in FIPS-only mode";
130 }
131
132 // Creating the CECPQ2 recipient KEM using HRSS and X25519 private keys
133 util::SecretData hrss_private_key_seed =
134 util::SecretDataFromStringView(test::HexDecodeOrDie(kHrssKeyGenEntropy));
135 auto status_or_recipient_kem = Cecpq2HkdfRecipientKemBoringSsl::New(
136 EllipticCurveType::UNKNOWN_CURVE,
137 util::SecretDataFromStringView(
138 test::HexDecodeOrDie(kCecpq2X25519PrivateKeyHex)),
139 std::move(hrss_private_key_seed));
140
141 // The instance creation above should fail with an unimplemented algorithm
142 // error given the UNKNOWN_CURVE parameter
143 EXPECT_EQ(absl::StatusCode::kUnimplemented,
144 status_or_recipient_kem.status().code());
145 }
146
147 // This test evaluates the case where a unsupported curve (NIST_P256) is
148 // specified. This test should fail with an absl::StatusCode::kUnimplemented
149 // error.
TEST(Cecpq2HkdfRecipientKemBoringSslTest,TestUnsupportedCurve)150 TEST(Cecpq2HkdfRecipientKemBoringSslTest, TestUnsupportedCurve) {
151 if (IsFipsModeEnabled()) {
152 GTEST_SKIP() << "Not supported in FIPS-only mode";
153 }
154
155 // Creating the CECPQ2 recipient KEM using HRSS and X25519 private keys
156 util::SecretData hrss_private_key_seed =
157 util::SecretDataFromStringView(test::HexDecodeOrDie(kHrssKeyGenEntropy));
158 auto status_or_recipient_kem = Cecpq2HkdfRecipientKemBoringSsl::New(
159 EllipticCurveType::NIST_P256,
160 util::SecretDataFromStringView(
161 test::HexDecodeOrDie(kCecpq2X25519PrivateKeyHex)),
162 std::move(hrss_private_key_seed));
163
164 // The instance creation above should fail with an unimplemented algorithm
165 // error given the UNKNOWN_CURVE parameter
166 EXPECT_EQ(absl::StatusCode::kUnimplemented,
167 status_or_recipient_kem.status().code());
168 }
169
170 // This test checks that an error is triggered if an output key lenth smaller
171 // than 32 bytes is specified.
TEST(Cecpq2HkdfRecipientKemBoringSslTest,TestNotPostQuantumSecureKeyLength)172 TEST(Cecpq2HkdfRecipientKemBoringSslTest, TestNotPostQuantumSecureKeyLength) {
173 if (IsFipsModeEnabled()) {
174 GTEST_SKIP() << "Not supported in FIPS-only mode";
175 }
176
177 // Not post-quantum secure output key length
178 int out_len = 31;
179
180 // Creating the CECPQ2 recipient KEM using HRSS and X25519 private keys
181 util::SecretData hrss_private_key_seed =
182 util::SecretDataFromStringView(test::HexDecodeOrDie(kHrssKeyGenEntropy));
183 auto cecpq2_recipient_kem_or = Cecpq2HkdfRecipientKemBoringSsl::New(
184 EllipticCurveType::CURVE25519,
185 util::SecretDataFromStringView(
186 test::HexDecodeOrDie(kCecpq2X25519PrivateKeyHex)),
187 std::move(hrss_private_key_seed));
188 ASSERT_THAT(cecpq2_recipient_kem_or, IsOk());
189 auto cecpq2_recipient_kem = std::move(cecpq2_recipient_kem_or).value();
190
191 // Recovering the symmetric key
192 auto kem_key_or = cecpq2_recipient_kem->GenerateKey(
193 test::HexDecodeOrDie(kCecpq2KemBytes), HashType::SHA256,
194 test::HexDecodeOrDie(kSaltHex), test::HexDecodeOrDie(kInfoHex), out_len,
195 EcPointFormat::COMPRESSED);
196 EXPECT_THAT(kem_key_or.status(),
197 StatusIs(absl::StatusCode::kInvalidArgument,
198 HasSubstr("not post-quantum secure")));
199 }
200
TEST(Cecpq2HkdfRecipientKemBoringSslTest,TestRecipientFlowSuccess)201 TEST(Cecpq2HkdfRecipientKemBoringSslTest, TestRecipientFlowSuccess) {
202 if (IsFipsModeEnabled()) {
203 GTEST_SKIP() << "Not supported in FIPS-only mode";
204 }
205 int out_len = 32;
206
207 // Creating the CECPQ2 recipient KEM using HRSS and X25519 private keys
208 util::SecretData hrss_private_key_seed =
209 util::SecretDataFromStringView(test::HexDecodeOrDie(kHrssKeyGenEntropy));
210 auto cecpq2_recipient_kem_or = Cecpq2HkdfRecipientKemBoringSsl::New(
211 EllipticCurveType::CURVE25519,
212 util::SecretDataFromStringView(
213 test::HexDecodeOrDie(kCecpq2X25519PrivateKeyHex)),
214 std::move(hrss_private_key_seed));
215 ASSERT_THAT(cecpq2_recipient_kem_or, IsOk());
216 auto cecpq2_recipient_kem = std::move(cecpq2_recipient_kem_or).value();
217
218 // Recovering the symmetric key
219 auto kem_key_or = cecpq2_recipient_kem->GenerateKey(
220 test::HexDecodeOrDie(kCecpq2KemBytes), HashType::SHA256,
221 test::HexDecodeOrDie(kSaltHex), test::HexDecodeOrDie(kInfoHex), out_len,
222 EcPointFormat::COMPRESSED);
223 ASSERT_THAT(kem_key_or, IsOk());
224
225 // The generated symmetric key should match the expected one
226 EXPECT_EQ(kCorrectSharedSecret,
227 test::HexEncode(util::SecretDataAsStringView(kem_key_or.value())));
228 }
229
TEST(Cecpq2HkdfRecipientKemBoringSslTest,TestRecipientFlowFailure)230 TEST(Cecpq2HkdfRecipientKemBoringSslTest, TestRecipientFlowFailure) {
231 if (IsFipsModeEnabled()) {
232 GTEST_SKIP() << "Not supported in FIPS-only mode";
233 }
234 int out_len = 32;
235 // The following kem_bytes is not correct. The 50-th position of the HRSS
236 // kem_bytes has been modified (its original value xored with 4). This
237 // modified HRSS kem_bytes matches the one used in BoringSSL test vector. This
238 // change will result in an HRSS decapsulation failure which produces a
239 // symmetric key using a deterministic algorithm based on HMAC-SHA256.
240
241 std::string kem_bytes_modified = test::HexDecodeOrDie(kCecpq2KemBytes);
242 kem_bytes_modified[X25519_PUBLIC_VALUE_LEN + 50] ^= 0x04;
243
244 // Creating the CECPQ2 recipient KEM using HRSS and X25519 private keys
245 util::SecretData hrss_private_key_seed =
246 util::SecretDataFromStringView(test::HexDecodeOrDie(kHrssKeyGenEntropy));
247 auto cecpq2_recipient_kem_or = Cecpq2HkdfRecipientKemBoringSsl::New(
248 EllipticCurveType::CURVE25519,
249 util::SecretDataFromStringView(
250 test::HexDecodeOrDie(kCecpq2X25519PrivateKeyHex)),
251 std::move(hrss_private_key_seed));
252 ASSERT_THAT(cecpq2_recipient_kem_or, IsOk());
253 auto cecpq2_recipient_kem = std::move(cecpq2_recipient_kem_or).value();
254
255 // Recovering the symmetric key
256 auto kem_key_or = cecpq2_recipient_kem->GenerateKey(
257 kem_bytes_modified, HashType::SHA256, test::HexDecodeOrDie(kSaltHex),
258 test::HexDecodeOrDie(kInfoHex), out_len, EcPointFormat::COMPRESSED);
259 ASSERT_THAT(kem_key_or, IsOk());
260
261 // The produced symmetric key should match the one produced by CECPQ2 in case
262 // of HRSS decapsulation failure for the altered HRSS kem_bytes
263 EXPECT_EQ(kFailSharedSecret,
264 test::HexEncode(util::SecretDataAsStringView(kem_key_or.value())));
265 }
266
267 } // namespace
268 } // namespace subtle
269 } // namespace tink
270 } // namespace crypto
271