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/subtle/sphincs_subtle_utils.h"
18
19 #include <string>
20 #include <utility>
21
22 #include "absl/memory/memory.h"
23 #include "absl/status/status.h"
24 #include "absl/strings/str_format.h"
25 #include "tink/experimental/pqcrypto/signature/subtle/sphincs_helper_pqclean.h"
26 #include "tink/util/secret_data.h"
27 #include "tink/util/status.h"
28 #include "tink/util/statusor.h"
29
30 namespace crypto {
31 namespace tink {
32 namespace subtle {
33
GenerateSphincsKeyPair(SphincsParamsPqclean params)34 crypto::tink::util::StatusOr<SphincsKeyPair> GenerateSphincsKeyPair(
35 SphincsParamsPqclean params) {
36 // Check if parameters are valid.
37 util::Status valid_parameters = ValidateParams(params);
38 if (!valid_parameters.ok()) {
39 return valid_parameters;
40 }
41
42 util::StatusOr<int32> key_size_index =
43 SphincsKeySizeToIndex(params.private_key_size);
44 if (!key_size_index.ok()) {
45 return key_size_index.status();
46 }
47
48 std::string public_key;
49 std::string private_key;
50 private_key.resize(params.private_key_size);
51
52 const SphincsHelperPqclean &sphincs_helper_pqclean =
53 GetSphincsHelperPqclean(params.hash_type, params.variant, *key_size_index,
54 params.sig_length_type);
55 public_key.resize(sphincs_helper_pqclean.GetPublicKeySize());
56
57 if (0 != sphincs_helper_pqclean.Keygen(
58 reinterpret_cast<uint8_t *>(public_key.data()),
59 reinterpret_cast<uint8_t *>(private_key.data()))) {
60 return util::Status(absl::StatusCode::kInternal, "Key generation failed.");
61 }
62
63 util::SecretData private_key_data =
64 util::SecretDataFromStringView(private_key);
65
66 SphincsKeyPair key_pair(SphincsPrivateKeyPqclean{private_key_data, params},
67 SphincsPublicKeyPqclean{public_key, params});
68
69 return key_pair;
70 }
71
ValidatePrivateKeySize(int32 key_size)72 crypto::tink::util::Status ValidatePrivateKeySize(int32 key_size) {
73 switch (key_size) {
74 case kSphincsPrivateKeySize64:
75 case kSphincsPrivateKeySize96:
76 case kSphincsPrivateKeySize128:
77 return util::OkStatus();
78 default:
79 return util::Status(
80 absl::StatusCode::kInvalidArgument,
81 absl::StrFormat("Invalid private key size (%d). "
82 "The only valid sizes are %d, %d, %d.",
83 key_size, kSphincsPrivateKeySize64,
84 kSphincsPrivateKeySize96, kSphincsPrivateKeySize128));
85 }
86 }
87
ValidatePublicKeySize(int32 key_size)88 crypto::tink::util::Status ValidatePublicKeySize(int32 key_size) {
89 switch (key_size) {
90 case kSphincsPublicKeySize32:
91 case kSphincsPublicKeySize48:
92 case kSphincsPublicKeySize64:
93 return util::OkStatus();
94 default:
95 return util::Status(
96 absl::StatusCode::kInvalidArgument,
97 absl::StrFormat("Invalid private key size (%d). "
98 "The only valid sizes are %d, %d, %d.",
99 key_size, kSphincsPublicKeySize32,
100 kSphincsPublicKeySize48, kSphincsPublicKeySize64));
101 }
102 }
103
SphincsKeySizeToIndex(int32 key_size)104 crypto::tink::util::StatusOr<int32> SphincsKeySizeToIndex(int32 key_size) {
105 switch (key_size) {
106 case kSphincsPrivateKeySize64:
107 return 0;
108 case kSphincsPrivateKeySize96:
109 return 1;
110 case kSphincsPrivateKeySize128:
111 return 2;
112 default:
113 return util::Status(absl::StatusCode::kInvalidArgument,
114 "Invalid key size");
115 }
116 }
117
ValidateParams(SphincsParamsPqclean params)118 crypto::tink::util::Status ValidateParams(SphincsParamsPqclean params) {
119 switch (params.hash_type) {
120 case SphincsHashType::HARAKA:
121 case SphincsHashType::SHA256:
122 case SphincsHashType::SHAKE256: {
123 break;
124 }
125 default: {
126 return util::Status(absl::StatusCode::kInvalidArgument,
127 "Invalid hash type");
128 }
129 }
130
131 switch (params.variant) {
132 case SphincsVariant::ROBUST:
133 case SphincsVariant::SIMPLE: {
134 break;
135 }
136 default: {
137 return util::Status(absl::StatusCode::kInvalidArgument,
138 "Invalid variant");
139 }
140 }
141
142 switch (params.sig_length_type) {
143 case SphincsSignatureType::FAST_SIGNING:
144 case SphincsSignatureType::SMALL_SIGNATURE: {
145 break;
146 }
147 default: {
148 return util::Status(absl::StatusCode::kInvalidArgument,
149 "Invalid signature type");
150 }
151 }
152
153 return ValidatePrivateKeySize(params.private_key_size);
154 }
155
156 } // namespace subtle
157 } // namespace tink
158 } // namespace crypto
159