xref: /aosp_15_r20/external/tink/cc/mac/aes_cmac_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/aes_cmac_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/aes_cmac_key.h"
31 #include "tink/mac/aes_cmac_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/aes_cmac.pb.h"
38 #include "proto/tink.pb.h"
39 
40 namespace crypto {
41 namespace tink {
42 namespace {
43 
44 using ::google::crypto::tink::AesCmacKeyFormat;
45 using ::google::crypto::tink::AesCmacParams;
46 using ::google::crypto::tink::OutputPrefixType;
47 
48 using AesCmacProtoParametersParserImpl =
49     internal::ParametersParserImpl<internal::ProtoParametersSerialization,
50                                    AesCmacParameters>;
51 using AesCmacProtoParametersSerializerImpl =
52     internal::ParametersSerializerImpl<AesCmacParameters,
53                                        internal::ProtoParametersSerialization>;
54 using AesCmacProtoKeyParserImpl =
55     internal::KeyParserImpl<internal::ProtoKeySerialization, AesCmacKey>;
56 using AesCmacProtoKeySerializerImpl =
57     internal::KeySerializerImpl<AesCmacKey, internal::ProtoKeySerialization>;
58 
59 const absl::string_view kTypeUrl =
60     "type.googleapis.com/google.crypto.tink.AesCmacKey";
61 
ToVariant(OutputPrefixType output_prefix_type)62 util::StatusOr<AesCmacParameters::Variant> ToVariant(
63     OutputPrefixType output_prefix_type) {
64   switch (output_prefix_type) {
65     case OutputPrefixType::CRUNCHY:
66       return AesCmacParameters::Variant::kCrunchy;
67     case OutputPrefixType::LEGACY:
68       return AesCmacParameters::Variant::kLegacy;
69     case OutputPrefixType::RAW:
70       return AesCmacParameters::Variant::kNoPrefix;
71     case OutputPrefixType::TINK:
72       return AesCmacParameters::Variant::kTink;
73     default:
74       return util::Status(absl::StatusCode::kInvalidArgument,
75                           "Could not determine AesCmacParameters::Variant");
76   }
77 }
78 
ToOutputPrefixType(AesCmacParameters::Variant variant)79 util::StatusOr<OutputPrefixType> ToOutputPrefixType(
80     AesCmacParameters::Variant variant) {
81   switch (variant) {
82     case AesCmacParameters::Variant::kCrunchy:
83       return OutputPrefixType::CRUNCHY;
84     case AesCmacParameters::Variant::kLegacy:
85       return OutputPrefixType::LEGACY;
86     case AesCmacParameters::Variant::kNoPrefix:
87       return OutputPrefixType::RAW;
88     case AesCmacParameters::Variant::kTink:
89       return OutputPrefixType::TINK;
90     default:
91       return util::Status(absl::StatusCode::kInvalidArgument,
92                           "Could not determine output prefix type");
93   }
94 }
95 
ParseParameters(const internal::ProtoParametersSerialization & serialization)96 util::StatusOr<AesCmacParameters> ParseParameters(
97     const internal::ProtoParametersSerialization& serialization) {
98   if (serialization.GetKeyTemplate().type_url() != kTypeUrl) {
99     return util::Status(absl::StatusCode::kInvalidArgument,
100                         "Wrong type URL when parsing AesCmacParameters.");
101   }
102 
103   AesCmacKeyFormat proto_key_format;
104   if (!proto_key_format.ParseFromString(
105           serialization.GetKeyTemplate().value())) {
106     return util::Status(absl::StatusCode::kInvalidArgument,
107                         "Failed to parse AesCmacKeyFormat proto");
108   }
109 
110   util::StatusOr<AesCmacParameters::Variant> variant =
111       ToVariant(serialization.GetKeyTemplate().output_prefix_type());
112   if (!variant.ok()) return variant.status();
113 
114   return AesCmacParameters::Create(proto_key_format.key_size(),
115                                    proto_key_format.params().tag_size(),
116                                    *variant);
117 }
118 
SerializeParameters(const AesCmacParameters & parameters)119 util::StatusOr<internal::ProtoParametersSerialization> SerializeParameters(
120     const AesCmacParameters& parameters) {
121   util::StatusOr<OutputPrefixType> output_prefix_type =
122       ToOutputPrefixType(parameters.GetVariant());
123   if (!output_prefix_type.ok()) return output_prefix_type.status();
124 
125   AesCmacParams proto_params;
126   proto_params.set_tag_size(parameters.CryptographicTagSizeInBytes());
127   AesCmacKeyFormat proto_key_format;
128   proto_key_format.set_key_size(parameters.KeySizeInBytes());
129   *proto_key_format.mutable_params() = proto_params;
130 
131   return internal::ProtoParametersSerialization::Create(
132       kTypeUrl, *output_prefix_type, proto_key_format.SerializeAsString());
133 }
134 
ParseKey(const internal::ProtoKeySerialization & serialization,absl::optional<SecretKeyAccessToken> token)135 util::StatusOr<AesCmacKey> ParseKey(
136     const internal::ProtoKeySerialization& serialization,
137     absl::optional<SecretKeyAccessToken> token) {
138   if (serialization.TypeUrl() != kTypeUrl) {
139     return util::Status(absl::StatusCode::kInvalidArgument,
140                         "Wrong type URL when parsing AesCmacKey.");
141   }
142   if (!token.has_value()) {
143     return util::Status(absl::StatusCode::kInvalidArgument,
144                         "SecretKeyAccess is required");
145   }
146   google::crypto::tink::AesCmacKey proto_key;
147   RestrictedData restricted_data = serialization.SerializedKeyProto();
148   // OSS proto library complains if input is not converted to a string.
149   if (!proto_key.ParseFromString(
150           std::string(restricted_data.GetSecret(*token)))) {
151     return util::Status(absl::StatusCode::kInvalidArgument,
152                         "Failed to parse AesCmacKey proto");
153   }
154   if (proto_key.version() != 0) {
155     return util::Status(absl::StatusCode::kInvalidArgument,
156                         "Only version 0 keys are accepted.");
157   }
158 
159   util::StatusOr<AesCmacParameters::Variant> variant =
160       ToVariant(serialization.GetOutputPrefixType());
161   if (!variant.ok()) return variant.status();
162 
163   util::StatusOr<AesCmacParameters> parameters = AesCmacParameters::Create(
164       proto_key.key_value().length(), proto_key.params().tag_size(), *variant);
165   if (!parameters.ok()) return parameters.status();
166 
167   util::StatusOr<AesCmacKey> key = AesCmacKey::Create(
168       *parameters, RestrictedData(proto_key.key_value(), *token),
169       serialization.IdRequirement(), GetPartialKeyAccess());
170   if (!key.ok()) return key.status();
171 
172   return *key;
173 }
174 
SerializeKey(const AesCmacKey & key,absl::optional<SecretKeyAccessToken> token)175 util::StatusOr<internal::ProtoKeySerialization> SerializeKey(
176     const AesCmacKey& key, absl::optional<SecretKeyAccessToken> token) {
177   util::StatusOr<RestrictedData> restricted_input =
178       key.GetKeyBytes(GetPartialKeyAccess());
179   if (!restricted_input.ok()) return restricted_input.status();
180   if (!token.has_value()) {
181     return util::Status(absl::StatusCode::kInvalidArgument,
182                         "SecretKeyAccess is required");
183   }
184 
185   AesCmacParams proto_params;
186   proto_params.set_tag_size(key.GetParameters().CryptographicTagSizeInBytes());
187   google::crypto::tink::AesCmacKey proto_key;
188   *proto_key.mutable_params() = proto_params;
189   proto_key.set_version(0);
190   // OSS proto library complains if input is not converted to a string.
191   proto_key.set_key_value(std::string(restricted_input->GetSecret(*token)));
192 
193   util::StatusOr<OutputPrefixType> output_prefix_type =
194       ToOutputPrefixType(key.GetParameters().GetVariant());
195   if (!output_prefix_type.ok()) return output_prefix_type.status();
196 
197   RestrictedData restricted_output =
198       RestrictedData(proto_key.SerializeAsString(), *token);
199   return internal::ProtoKeySerialization::Create(
200       kTypeUrl, restricted_output, google::crypto::tink::KeyData::SYMMETRIC,
201       *output_prefix_type, key.GetIdRequirement());
202 }
203 
AesCmacProtoParametersParser()204 AesCmacProtoParametersParserImpl* AesCmacProtoParametersParser() {
205   static auto* parser =
206       new AesCmacProtoParametersParserImpl(kTypeUrl, ParseParameters);
207   return parser;
208 }
209 
AesCmacProtoParametersSerializer()210 AesCmacProtoParametersSerializerImpl* AesCmacProtoParametersSerializer() {
211   static auto* serializer =
212       new AesCmacProtoParametersSerializerImpl(kTypeUrl, SerializeParameters);
213   return serializer;
214 }
215 
AesCmacProtoKeyParser()216 AesCmacProtoKeyParserImpl* AesCmacProtoKeyParser() {
217   static auto* parser = new AesCmacProtoKeyParserImpl(kTypeUrl, ParseKey);
218   return parser;
219 }
220 
AesCmacProtoKeySerializer()221 AesCmacProtoKeySerializerImpl* AesCmacProtoKeySerializer() {
222   static auto* serializer = new AesCmacProtoKeySerializerImpl(SerializeKey);
223   return serializer;
224 }
225 
226 }  // namespace
227 
RegisterAesCmacProtoSerialization()228 util::Status RegisterAesCmacProtoSerialization() {
229   util::Status status =
230       internal::MutableSerializationRegistry::GlobalInstance()
231           .RegisterParametersParser(AesCmacProtoParametersParser());
232   if (!status.ok()) return status;
233 
234   status =
235       internal::MutableSerializationRegistry::GlobalInstance()
236           .RegisterParametersSerializer(AesCmacProtoParametersSerializer());
237   if (!status.ok()) return status;
238 
239   status = internal::MutableSerializationRegistry::GlobalInstance()
240                .RegisterKeyParser(AesCmacProtoKeyParser());
241   if (!status.ok()) return status;
242 
243   return internal::MutableSerializationRegistry::GlobalInstance()
244       .RegisterKeySerializer(AesCmacProtoKeySerializer());
245 }
246 
247 }  // namespace tink
248 }  // namespace crypto
249