1 // Copyright 2017 Google Inc.
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/hybrid/ecies_aead_hkdf_dem_helper.h"
18
19 #include <stdint.h>
20
21 #include <memory>
22 #include <string>
23 #include <utility>
24
25 #include "absl/memory/memory.h"
26 #include "absl/status/status.h"
27 #include "absl/status/statusor.h"
28 #include "absl/strings/string_view.h"
29 #include "tink/aead.h"
30 #include "tink/aead/aes_ctr_hmac_aead_key_manager.h"
31 #include "tink/deterministic_aead.h"
32 #include "tink/subtle/aes_gcm_boringssl.h"
33 #include "tink/subtle/aes_siv_boringssl.h"
34 #include "tink/subtle/xchacha20_poly1305_boringssl.h"
35 #include "tink/util/errors.h"
36 #include "tink/util/protobuf_helper.h"
37 #include "tink/util/statusor.h"
38 #include "proto/aes_ctr.pb.h"
39 #include "proto/aes_ctr_hmac_aead.pb.h"
40 #include "proto/aes_gcm.pb.h"
41 #include "proto/aes_siv.pb.h"
42 #include "proto/hmac.pb.h"
43 #include "proto/tink.pb.h"
44 #include "proto/xchacha20_poly1305.pb.h"
45
46 namespace crypto {
47 namespace tink {
48 namespace {
49
50 using ::crypto::tink::subtle::AeadOrDaead;
51 using ::google::crypto::tink::AesCtrHmacAeadKey;
52 using ::google::crypto::tink::AesCtrHmacAeadKeyFormat;
53 using ::google::crypto::tink::AesGcmKeyFormat;
54 using ::google::crypto::tink::AesSivKeyFormat;
55 using ::google::crypto::tink::KeyTemplate;
56 using ::google::crypto::tink::XChaCha20Poly1305KeyFormat;
57
Wrap(crypto::tink::util::StatusOr<std::unique_ptr<crypto::tink::Aead>> aead_or)58 crypto::tink::util::StatusOr<std::unique_ptr<AeadOrDaead>> Wrap(
59 crypto::tink::util::StatusOr<std::unique_ptr<crypto::tink::Aead>> aead_or) {
60 if (!aead_or.ok()) {
61 return aead_or.status();
62 }
63 return std::make_unique<AeadOrDaead>(std::move(aead_or.value()));
64 }
65
Wrap(crypto::tink::util::StatusOr<std::unique_ptr<crypto::tink::DeterministicAead>> daead_or)66 crypto::tink::util::StatusOr<std::unique_ptr<AeadOrDaead>> Wrap(
67 crypto::tink::util::StatusOr<
68 std::unique_ptr<crypto::tink::DeterministicAead>>
69 daead_or) {
70 if (!daead_or.ok()) {
71 return daead_or.status();
72 }
73 return std::make_unique<AeadOrDaead>(std::move(daead_or.value()));
74 }
75
76 } // namespace
77
78 util::StatusOr<EciesAeadHkdfDemHelper::DemKeyParams>
GetKeyParams(const KeyTemplate & key_template)79 EciesAeadHkdfDemHelper::GetKeyParams(const KeyTemplate& key_template) {
80 const std::string& type_url = key_template.type_url();
81 if (type_url == "type.googleapis.com/google.crypto.tink.AesGcmKey") {
82 AesGcmKeyFormat key_format;
83 if (!key_format.ParseFromString(key_template.value())) {
84 return util::Status(absl::StatusCode::kInvalidArgument,
85 "Invalid AesGcmKeyFormat in DEM key template");
86 }
87 return {{AES_GCM_KEY, key_format.key_size()}};
88 }
89 if (type_url == "type.googleapis.com/google.crypto.tink.AesCtrHmacAeadKey") {
90 AesCtrHmacAeadKeyFormat key_format;
91 if (!key_format.ParseFromString(key_template.value())) {
92 return util::Status(absl::StatusCode::kInvalidArgument,
93 "Invalid AesCtrHmacKeyFormat in DEM key template");
94 }
95 uint32_t dem_key_size = key_format.aes_ctr_key_format().key_size() +
96 key_format.hmac_key_format().key_size();
97 return {{AES_CTR_HMAC_AEAD_KEY, dem_key_size,
98 key_format.aes_ctr_key_format().key_size(),
99 key_format.aes_ctr_key_format().params().iv_size(),
100 key_format.hmac_key_format().params().hash(),
101 key_format.hmac_key_format().params().tag_size()}};
102 }
103 if (type_url ==
104 "type.googleapis.com/google.crypto.tink.XChaCha20Poly1305Key") {
105 if (!XChaCha20Poly1305KeyFormat().ParseFromString(key_template.value())) {
106 return util::Status(absl::StatusCode::kInvalidArgument,
107 "Invalid XChaCha20KeyFormat in DEM key template");
108 }
109 return {{XCHACHA20_POLY1305_KEY, 32}};
110 }
111 if (type_url == "type.googleapis.com/google.crypto.tink.AesSivKey") {
112 AesSivKeyFormat key_format;
113
114 if (!key_format.ParseFromString(key_template.value())) {
115 return util::Status(absl::StatusCode::kInvalidArgument,
116 "Invalid AesSiveKeyFormat in DEM key template");
117 }
118 return {{AES_SIV_KEY, key_format.key_size()}};
119 }
120 return ToStatusF(absl::StatusCode::kInvalidArgument,
121 "Unsupported DEM key type '%s'.", type_url);
122 }
123
124 // static
125 util::StatusOr<std::unique_ptr<const EciesAeadHkdfDemHelper>>
New(const KeyTemplate & dem_key_template)126 EciesAeadHkdfDemHelper::New(const KeyTemplate& dem_key_template) {
127 auto key_params_or = GetKeyParams(dem_key_template);
128 if (!key_params_or.ok()) return key_params_or.status();
129 DemKeyParams key_params = key_params_or.value();
130 return absl::WrapUnique<const EciesAeadHkdfDemHelper>(
131 new EciesAeadHkdfDemHelper(dem_key_template, key_params));
132 }
133
134 crypto::tink::util::StatusOr<std::unique_ptr<AeadOrDaead>>
GetAeadOrDaead(const util::SecretData & symmetric_key_value) const135 EciesAeadHkdfDemHelper::GetAeadOrDaead(
136 const util::SecretData& symmetric_key_value) const {
137 if (symmetric_key_value.size() != key_params_.key_size_in_bytes) {
138 return util::Status(absl::StatusCode::kInternal,
139 "Wrong length of symmetric key.");
140 }
141 switch (key_params_.key_type) {
142 case AES_GCM_KEY:
143 return Wrap(subtle::AesGcmBoringSsl::New(symmetric_key_value));
144 case AES_CTR_HMAC_AEAD_KEY: {
145 AesCtrHmacAeadKey key;
146 auto aes_ctr_key = key.mutable_aes_ctr_key();
147 aes_ctr_key->mutable_params()->set_iv_size(
148 key_params_.aes_ctr_key_iv_size_in_bytes);
149 aes_ctr_key->set_key_value(
150 std::string(util::SecretDataAsStringView(symmetric_key_value)
151 .substr(0, key_params_.aes_ctr_key_size_in_bytes)));
152 auto hmac_key = key.mutable_hmac_key();
153 hmac_key->mutable_params()->set_tag_size(
154 key_params_.hmac_key_tag_size_in_bytes);
155 hmac_key->mutable_params()->set_hash(key_params_.hmac_key_hash);
156 hmac_key->set_key_value(
157 std::string(util::SecretDataAsStringView(symmetric_key_value)
158 .substr(key_params_.aes_ctr_key_size_in_bytes)));
159 return Wrap(AesCtrHmacAeadKeyManager().GetPrimitive<Aead>(key));
160 }
161 case XCHACHA20_POLY1305_KEY:
162 return Wrap(subtle::XChacha20Poly1305BoringSsl::New(symmetric_key_value));
163 case AES_SIV_KEY:
164 return Wrap(subtle::AesSivBoringSsl::New(symmetric_key_value));
165 }
166 }
167
168 } // namespace tink
169 } // namespace crypto
170