1 // Copyright 2021 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/signature/falcon_verify_key_manager.h"
18
19 #include <memory>
20 #include <string>
21
22 #include "gmock/gmock.h"
23 #include "gtest/gtest.h"
24 #include "absl/container/flat_hash_set.h"
25 #include "absl/strings/str_cat.h"
26 #include "tink/experimental/pqcrypto/signature/falcon_sign_key_manager.h"
27 #include "tink/experimental/pqcrypto/signature/subtle/falcon_sign.h"
28 #include "tink/experimental/pqcrypto/signature/subtle/falcon_subtle_utils.h"
29 #include "tink/experimental/pqcrypto/signature/subtle/falcon_verify.h"
30 #include "tink/public_key_verify.h"
31 #include "tink/util/secret_data.h"
32 #include "tink/util/status.h"
33 #include "tink/util/statusor.h"
34 #include "tink/util/test_matchers.h"
35
36 namespace crypto {
37 namespace tink {
38 namespace {
39
40 using ::crypto::tink::test::IsOk;
41 using ::crypto::tink::util::StatusOr;
42 using ::google::crypto::tink::FalconKeyFormat;
43 using ::google::crypto::tink::FalconPrivateKey;
44 using ::google::crypto::tink::FalconPublicKey;
45 using ::google::crypto::tink::KeyData;
46 using ::testing::Eq;
47 using ::testing::Not;
48
49 struct FalconTestCase {
50 std::string test_name;
51 int32_t private_key_size;
52 int32_t public_key_size;
53 };
54
55 using FalconVerifyKeyManagerTest = testing::TestWithParam<FalconTestCase>;
56
57 // Helper function that returns a valid falcon private key.
CreateValidPrivateKey(int32_t private_key_size)58 StatusOr<FalconPrivateKey> CreateValidPrivateKey(int32_t private_key_size) {
59 FalconKeyFormat key_format;
60 key_format.set_key_size(private_key_size);
61
62 return FalconSignKeyManager().CreateKey(key_format);
63 }
64
65 // Helper function that returns a valid falcon public key.
CreateValidPublicKey(int32_t private_key_size)66 StatusOr<FalconPublicKey> CreateValidPublicKey(int32_t private_key_size) {
67 StatusOr<FalconPrivateKey> private_key =
68 CreateValidPrivateKey(private_key_size);
69
70 if (!private_key.ok()) return private_key.status();
71 return FalconSignKeyManager().GetPublicKey(*private_key);
72 }
73
TEST(FalconVerifyKeyManagerTest,Basics)74 TEST(FalconVerifyKeyManagerTest, Basics) {
75 EXPECT_THAT(FalconVerifyKeyManager().get_version(), Eq(0));
76 EXPECT_THAT(FalconVerifyKeyManager().key_material_type(),
77 Eq(KeyData::ASYMMETRIC_PUBLIC));
78 EXPECT_THAT(FalconVerifyKeyManager().get_key_type(),
79 Eq("type.googleapis.com/google.crypto.tink.FalconPublicKey"));
80 }
81
TEST(FalconVerifyKeyManagerTest,ValidateEmptyKey)82 TEST(FalconVerifyKeyManagerTest, ValidateEmptyKey) {
83 EXPECT_THAT(FalconVerifyKeyManager().ValidateKey(FalconPublicKey()),
84 Not(IsOk()));
85 }
86
TEST_P(FalconVerifyKeyManagerTest,PublicKeyValid)87 TEST_P(FalconVerifyKeyManagerTest, PublicKeyValid) {
88 const FalconTestCase& test_case = GetParam();
89
90 StatusOr<FalconPublicKey> public_key =
91 CreateValidPublicKey(test_case.private_key_size);
92 ASSERT_THAT(public_key, IsOk());
93
94 EXPECT_THAT(FalconVerifyKeyManager().ValidateKey(*public_key), IsOk());
95 }
96
TEST_P(FalconVerifyKeyManagerTest,PublicKeyWrongVersion)97 TEST_P(FalconVerifyKeyManagerTest, PublicKeyWrongVersion) {
98 const FalconTestCase& test_case = GetParam();
99
100 StatusOr<FalconPublicKey> public_key =
101 CreateValidPublicKey(test_case.private_key_size);
102 ASSERT_THAT(public_key, IsOk());
103
104 public_key->set_version(1);
105 EXPECT_THAT(FalconVerifyKeyManager().ValidateKey(*public_key), Not(IsOk()));
106 }
107
TEST_P(FalconVerifyKeyManagerTest,Create)108 TEST_P(FalconVerifyKeyManagerTest, Create) {
109 const FalconTestCase& test_case = GetParam();
110
111 StatusOr<FalconPrivateKey> private_key =
112 CreateValidPrivateKey(test_case.private_key_size);
113 ASSERT_THAT(private_key, IsOk());
114
115 StatusOr<FalconPublicKey> public_key =
116 FalconSignKeyManager().GetPublicKey(*private_key);
117 ASSERT_THAT(public_key, IsOk());
118
119 StatusOr<subtle::FalconPrivateKeyPqclean> falcon_private_key_pqclean =
120 subtle::FalconPrivateKeyPqclean::NewPrivateKey(
121 util::SecretDataFromStringView(private_key->key_value()));
122
123 util::StatusOr<std::unique_ptr<PublicKeySign>> direct_signer =
124 subtle::FalconSign::New(*falcon_private_key_pqclean);
125 ASSERT_THAT(direct_signer, IsOk());
126
127 util::StatusOr<std::unique_ptr<PublicKeyVerify>> verifier =
128 FalconVerifyKeyManager().GetPrimitive<PublicKeyVerify>(*public_key);
129 ASSERT_THAT(verifier, IsOk());
130
131 std::string message = "Some message";
132 util::StatusOr<std::string> signature = (*direct_signer)->Sign(message);
133 ASSERT_THAT(signature, IsOk());
134 EXPECT_THAT((*verifier)->Verify(*signature, message), IsOk());
135 }
136
TEST_P(FalconVerifyKeyManagerTest,CreateInvalidPublicKey)137 TEST_P(FalconVerifyKeyManagerTest, CreateInvalidPublicKey) {
138 const FalconTestCase& test_case = GetParam();
139
140 StatusOr<FalconPrivateKey> private_key =
141 CreateValidPrivateKey(test_case.private_key_size);
142 ASSERT_THAT(private_key, IsOk());
143
144 StatusOr<FalconPublicKey> public_key =
145 FalconSignKeyManager().GetPublicKey(*private_key);
146 ASSERT_THAT(public_key, IsOk());
147
148 std::string bad_public_key_data = "bad_public_key";
149 public_key->set_key_value(bad_public_key_data);
150
151 util::StatusOr<std::unique_ptr<PublicKeyVerify>> verifier =
152 FalconVerifyKeyManager().GetPrimitive<PublicKeyVerify>(*public_key);
153 EXPECT_THAT(verifier, Not(IsOk()));
154 }
155
TEST_P(FalconVerifyKeyManagerTest,CreateDifferentPublicKey)156 TEST_P(FalconVerifyKeyManagerTest, CreateDifferentPublicKey) {
157 const FalconTestCase& test_case = GetParam();
158
159 StatusOr<FalconPrivateKey> private_key =
160 CreateValidPrivateKey(test_case.private_key_size);
161 ASSERT_THAT(private_key, IsOk());
162
163 // Create a new public key derived from a diffferent private key.
164 StatusOr<FalconPrivateKey> new_private_key =
165 CreateValidPrivateKey(test_case.private_key_size);
166 ASSERT_THAT(new_private_key, IsOk());
167 StatusOr<FalconPublicKey> public_key =
168 FalconSignKeyManager().GetPublicKey(*new_private_key);
169 ASSERT_THAT(public_key, IsOk());
170
171 StatusOr<subtle::FalconPrivateKeyPqclean> falcon_private_key_pqclean =
172 subtle::FalconPrivateKeyPqclean::NewPrivateKey(
173 util::SecretDataFromStringView(private_key->key_value()));
174
175 util::StatusOr<std::unique_ptr<PublicKeySign>> direct_signer =
176 subtle::FalconSign::New(*falcon_private_key_pqclean);
177 ASSERT_THAT(direct_signer, IsOk());
178
179 util::StatusOr<std::unique_ptr<PublicKeyVerify>> verifier =
180 FalconVerifyKeyManager().GetPrimitive<PublicKeyVerify>(*public_key);
181 ASSERT_THAT(verifier, IsOk());
182
183 std::string message = "Some message";
184 util::StatusOr<std::string> signature = (*direct_signer)->Sign(message);
185 ASSERT_THAT(signature, IsOk());
186 EXPECT_THAT((*verifier)->Verify(*signature, message), Not(IsOk()));
187 }
188
189 INSTANTIATE_TEST_SUITE_P(
190 FalconVeirfyKeyManagerTests, FalconVerifyKeyManagerTest,
191 testing::ValuesIn<FalconTestCase>(
192 {{"Falcon512", subtle::kFalcon512PrivateKeySize,
193 subtle::kFalcon512PublicKeySize},
194 {"Falcon1024", subtle::kFalcon1024PrivateKeySize,
195 subtle::kFalcon1024PublicKeySize}}),
196 [](const testing::TestParamInfo<FalconVerifyKeyManagerTest::ParamType>&
__anon504bd5ca0202(const testing::TestParamInfo<FalconVerifyKeyManagerTest::ParamType>& info) 197 info) { return info.param.test_name; });
198
199 } // namespace
200
201 } // namespace tink
202 } // namespace crypto
203