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