xref: /aosp_15_r20/external/tink/cc/mac/hmac_proto_serialization.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1 // Copyright 2023 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/mac/hmac_proto_serialization.h"
18 
19 #include <string>
20 
21 #include "absl/status/status.h"
22 #include "absl/types/optional.h"
23 #include "tink/internal/key_parser.h"
24 #include "tink/internal/key_serializer.h"
25 #include "tink/internal/mutable_serialization_registry.h"
26 #include "tink/internal/parameters_parser.h"
27 #include "tink/internal/parameters_serializer.h"
28 #include "tink/internal/proto_key_serialization.h"
29 #include "tink/internal/proto_parameters_serialization.h"
30 #include "tink/mac/hmac_key.h"
31 #include "tink/mac/hmac_parameters.h"
32 #include "tink/partial_key_access.h"
33 #include "tink/restricted_data.h"
34 #include "tink/secret_key_access_token.h"
35 #include "tink/util/status.h"
36 #include "tink/util/statusor.h"
37 #include "proto/common.pb.h"
38 #include "proto/hmac.pb.h"
39 #include "proto/tink.pb.h"
40 
41 namespace crypto {
42 namespace tink {
43 namespace {
44 
45 using ::google::crypto::tink::HashType;
46 using ::google::crypto::tink::HmacKeyFormat;
47 using ::google::crypto::tink::HmacParams;
48 using ::google::crypto::tink::OutputPrefixType;
49 
50 using HmacProtoParametersParserImpl =
51     internal::ParametersParserImpl<internal::ProtoParametersSerialization,
52                                    HmacParameters>;
53 using HmacProtoParametersSerializerImpl =
54     internal::ParametersSerializerImpl<HmacParameters,
55                                        internal::ProtoParametersSerialization>;
56 using HmacProtoKeyParserImpl =
57     internal::KeyParserImpl<internal::ProtoKeySerialization, HmacKey>;
58 using HmacProtoKeySerializerImpl =
59     internal::KeySerializerImpl<HmacKey, internal::ProtoKeySerialization>;
60 
61 const absl::string_view kTypeUrl =
62     "type.googleapis.com/google.crypto.tink.HmacKey";
63 
ToVariant(OutputPrefixType output_prefix_type)64 util::StatusOr<HmacParameters::Variant> ToVariant(
65     OutputPrefixType output_prefix_type) {
66   switch (output_prefix_type) {
67     case OutputPrefixType::CRUNCHY:
68       return HmacParameters::Variant::kCrunchy;
69     case OutputPrefixType::LEGACY:
70       return HmacParameters::Variant::kLegacy;
71     case OutputPrefixType::RAW:
72       return HmacParameters::Variant::kNoPrefix;
73     case OutputPrefixType::TINK:
74       return HmacParameters::Variant::kTink;
75     default:
76       return util::Status(absl::StatusCode::kInvalidArgument,
77                           "Could not determine HmacParameters::Variant");
78   }
79 }
80 
ToOutputPrefixType(HmacParameters::Variant variant)81 util::StatusOr<OutputPrefixType> ToOutputPrefixType(
82     HmacParameters::Variant variant) {
83   switch (variant) {
84     case HmacParameters::Variant::kCrunchy:
85       return OutputPrefixType::CRUNCHY;
86     case HmacParameters::Variant::kLegacy:
87       return OutputPrefixType::LEGACY;
88     case HmacParameters::Variant::kNoPrefix:
89       return OutputPrefixType::RAW;
90     case HmacParameters::Variant::kTink:
91       return OutputPrefixType::TINK;
92     default:
93       return util::Status(absl::StatusCode::kInvalidArgument,
94                           "Could not determine output prefix type");
95   }
96 }
97 
ToHashType(HashType hash_type)98 util::StatusOr<HmacParameters::HashType> ToHashType(HashType hash_type) {
99   switch (hash_type) {
100     case HashType::SHA1:
101       return HmacParameters::HashType::kSha1;
102     case HashType::SHA224:
103       return HmacParameters::HashType::kSha224;
104     case HashType::SHA256:
105       return HmacParameters::HashType::kSha256;
106     case HashType::SHA384:
107       return HmacParameters::HashType::kSha384;
108     case HashType::SHA512:
109       return HmacParameters::HashType::kSha512;
110     default:
111       return util::Status(absl::StatusCode::kInvalidArgument,
112                           "Could not determine HashType");
113   }
114 }
115 
ToProtoHashType(HmacParameters::HashType hash_type)116 util::StatusOr<HashType> ToProtoHashType(HmacParameters::HashType hash_type) {
117   switch (hash_type) {
118     case HmacParameters::HashType::kSha1:
119       return HashType::SHA1;
120     case HmacParameters::HashType::kSha224:
121       return HashType::SHA224;
122     case HmacParameters::HashType::kSha256:
123       return HashType::SHA256;
124     case HmacParameters::HashType::kSha384:
125       return HashType::SHA384;
126     case HmacParameters::HashType::kSha512:
127       return HashType::SHA512;
128     default:
129       return util::Status(absl::StatusCode::kInvalidArgument,
130                           "Could not determine HmacParameters::HashType");
131   }
132 }
133 
ParseParameters(const internal::ProtoParametersSerialization & serialization)134 util::StatusOr<HmacParameters> ParseParameters(
135     const internal::ProtoParametersSerialization& serialization) {
136   if (serialization.GetKeyTemplate().type_url() != kTypeUrl) {
137     return util::Status(absl::StatusCode::kInvalidArgument,
138                         "Wrong type URL when parsing HmacParameters.");
139   }
140 
141   HmacKeyFormat proto_key_format;
142   if (!proto_key_format.ParseFromString(
143           serialization.GetKeyTemplate().value())) {
144     return util::Status(absl::StatusCode::kInvalidArgument,
145                         "Failed to parse HmacKeyFormat proto");
146   }
147   if (proto_key_format.version() != 0) {
148     return util::Status(
149         absl::StatusCode::kInvalidArgument,
150         "Parsing HmacParameters failed: only version 0 is accepted");
151   }
152 
153   util::StatusOr<HmacParameters::Variant> variant =
154       ToVariant(serialization.GetKeyTemplate().output_prefix_type());
155   if (!variant.ok()) return variant.status();
156 
157   util::StatusOr<HmacParameters::HashType> hash_type =
158       ToHashType(proto_key_format.params().hash());
159   if (!hash_type.ok()) return variant.status();
160 
161   return HmacParameters::Create(proto_key_format.key_size(),
162                                 proto_key_format.params().tag_size(),
163                                 *hash_type, *variant);
164 }
165 
SerializeParameters(const HmacParameters & parameters)166 util::StatusOr<internal::ProtoParametersSerialization> SerializeParameters(
167     const HmacParameters& parameters) {
168   util::StatusOr<OutputPrefixType> output_prefix_type =
169       ToOutputPrefixType(parameters.GetVariant());
170   if (!output_prefix_type.ok()) return output_prefix_type.status();
171   util::StatusOr<HashType> proto_hash_type =
172       ToProtoHashType(parameters.GetHashType());
173   if (!proto_hash_type.ok()) return proto_hash_type.status();
174 
175   HmacParams proto_params;
176   proto_params.set_tag_size(parameters.CryptographicTagSizeInBytes());
177   proto_params.set_hash(*proto_hash_type);
178   HmacKeyFormat proto_key_format;
179   proto_key_format.set_key_size(parameters.KeySizeInBytes());
180   proto_key_format.set_version(0);
181   *proto_key_format.mutable_params() = proto_params;
182 
183   return internal::ProtoParametersSerialization::Create(
184       kTypeUrl, *output_prefix_type, proto_key_format.SerializeAsString());
185 }
186 
ParseKey(const internal::ProtoKeySerialization & serialization,absl::optional<SecretKeyAccessToken> token)187 util::StatusOr<HmacKey> ParseKey(
188     const internal::ProtoKeySerialization& serialization,
189     absl::optional<SecretKeyAccessToken> token) {
190   if (serialization.TypeUrl() != kTypeUrl) {
191     return util::Status(absl::StatusCode::kInvalidArgument,
192                         "Wrong type URL when parsing HmacKey.");
193   }
194   if (!token.has_value()) {
195     return util::Status(absl::StatusCode::kInvalidArgument,
196                         "SecretKeyAccess is required");
197   }
198 
199   google::crypto::tink::HmacKey proto_key;
200   RestrictedData restricted_data = serialization.SerializedKeyProto();
201   // OSS proto library complains if input is not converted to a string.
202   if (!proto_key.ParseFromString(
203           std::string(restricted_data.GetSecret(*token)))) {
204     return util::Status(absl::StatusCode::kInvalidArgument,
205                         "Failed to parse HmacKey proto");
206   }
207   if (proto_key.version() != 0) {
208     return util::Status(absl::StatusCode::kInvalidArgument,
209                         "Only version 0 keys are accepted.");
210   }
211 
212   util::StatusOr<HmacParameters::Variant> variant =
213       ToVariant(serialization.GetOutputPrefixType());
214   if (!variant.ok()) return variant.status();
215   util::StatusOr<HmacParameters::HashType> hash_type =
216       ToHashType(proto_key.params().hash());
217   if (!hash_type.ok()) return variant.status();
218 
219   util::StatusOr<HmacParameters> parameters = HmacParameters::Create(
220       proto_key.key_value().length(), proto_key.params().tag_size(), *hash_type,
221       *variant);
222   if (!parameters.ok()) return parameters.status();
223 
224   return HmacKey::Create(*parameters,
225                          RestrictedData(proto_key.key_value(), *token),
226                          serialization.IdRequirement(), GetPartialKeyAccess());
227 }
228 
SerializeKey(const HmacKey & key,absl::optional<SecretKeyAccessToken> token)229 util::StatusOr<internal::ProtoKeySerialization> SerializeKey(
230     const HmacKey& key, absl::optional<SecretKeyAccessToken> token) {
231   util::StatusOr<RestrictedData> restricted_input =
232       key.GetKeyBytes(GetPartialKeyAccess());
233   if (!token.has_value()) {
234     return util::Status(absl::StatusCode::kInvalidArgument,
235                         "SecretKeyAccess is required");
236   }
237   if (!restricted_input.ok()) return restricted_input.status();
238   util::StatusOr<HashType> proto_hash_type =
239       ToProtoHashType(key.GetParameters().GetHashType());
240   if (!proto_hash_type.ok()) return proto_hash_type.status();
241 
242   HmacParams proto_params;
243   proto_params.set_tag_size(key.GetParameters().CryptographicTagSizeInBytes());
244   proto_params.set_hash(*proto_hash_type);
245   google::crypto::tink::HmacKey proto_key;
246   *proto_key.mutable_params() = proto_params;
247   proto_key.set_version(0);
248   // OSS proto library complains if input is not converted to a string.
249   proto_key.set_key_value(std::string(restricted_input->GetSecret(*token)));
250 
251   util::StatusOr<OutputPrefixType> output_prefix_type =
252       ToOutputPrefixType(key.GetParameters().GetVariant());
253   if (!output_prefix_type.ok()) return output_prefix_type.status();
254 
255   RestrictedData restricted_output =
256       RestrictedData(proto_key.SerializeAsString(), *token);
257   return internal::ProtoKeySerialization::Create(
258       kTypeUrl, restricted_output, google::crypto::tink::KeyData::SYMMETRIC,
259       *output_prefix_type, key.GetIdRequirement());
260 }
261 
HmacProtoParametersParser()262 HmacProtoParametersParserImpl* HmacProtoParametersParser() {
263   static auto* parser =
264       new HmacProtoParametersParserImpl(kTypeUrl, ParseParameters);
265   return parser;
266 }
267 
HmacProtoParametersSerializer()268 HmacProtoParametersSerializerImpl* HmacProtoParametersSerializer() {
269   static auto* serializer =
270       new HmacProtoParametersSerializerImpl(kTypeUrl, SerializeParameters);
271   return serializer;
272 }
273 
HmacProtoKeyParser()274 HmacProtoKeyParserImpl* HmacProtoKeyParser() {
275   static auto* parser = new HmacProtoKeyParserImpl(kTypeUrl, ParseKey);
276   return parser;
277 }
278 
HmacProtoKeySerializer()279 HmacProtoKeySerializerImpl* HmacProtoKeySerializer() {
280   static auto* serializer = new HmacProtoKeySerializerImpl(SerializeKey);
281   return serializer;
282 }
283 
284 }  // namespace
285 
RegisterHmacProtoSerialization()286 util::Status RegisterHmacProtoSerialization() {
287   util::Status status =
288       internal::MutableSerializationRegistry::GlobalInstance()
289           .RegisterParametersParser(HmacProtoParametersParser());
290   if (!status.ok()) return status;
291 
292   status = internal::MutableSerializationRegistry::GlobalInstance()
293                .RegisterParametersSerializer(HmacProtoParametersSerializer());
294   if (!status.ok()) return status;
295 
296   status = internal::MutableSerializationRegistry::GlobalInstance()
297                .RegisterKeyParser(HmacProtoKeyParser());
298   if (!status.ok()) return status;
299 
300   return internal::MutableSerializationRegistry::GlobalInstance()
301       .RegisterKeySerializer(HmacProtoKeySerializer());
302 }
303 
304 }  // namespace tink
305 }  // namespace crypto
306