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