xref: /aosp_15_r20/external/tink/cc/aead/aes_ctr_hmac_aead_key_manager.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
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/aead/aes_ctr_hmac_aead_key_manager.h"
18 
19 #include <cstdint>
20 #include <functional>
21 #include <map>
22 #include <memory>
23 #include <string>
24 #include <utility>
25 
26 #include "absl/status/status.h"
27 #include "absl/status/statusor.h"
28 #include "absl/strings/str_cat.h"
29 #include "tink/aead.h"
30 #include "tink/mac.h"
31 #include "tink/mac/hmac_key_manager.h"
32 #include "tink/subtle/aes_ctr_boringssl.h"
33 #include "tink/subtle/encrypt_then_authenticate.h"
34 #include "tink/subtle/ind_cpa_cipher.h"
35 #include "tink/subtle/random.h"
36 #include "tink/util/enums.h"
37 #include "tink/util/input_stream_util.h"
38 #include "tink/util/secret_data.h"
39 #include "tink/util/status.h"
40 #include "tink/util/statusor.h"
41 #include "tink/util/validation.h"
42 #include "proto/aes_ctr.pb.h"
43 #include "proto/aes_ctr_hmac_aead.pb.h"
44 #include "proto/common.pb.h"
45 #include "proto/hmac.pb.h"
46 
47 namespace crypto {
48 namespace tink {
49 
50 namespace {
51 constexpr int kMinKeySizeInBytes = 16;
52 constexpr int kMinIvSizeInBytes = 12;
53 constexpr int kMinTagSizeInBytes = 10;
54 }
55 
56 using ::crypto::tink::util::Enums;
57 using ::crypto::tink::util::Status;
58 using ::crypto::tink::util::StatusOr;
59 using ::google::crypto::tink::AesCtrHmacAeadKey;
60 using ::google::crypto::tink::AesCtrHmacAeadKeyFormat;
61 using ::google::crypto::tink::AesCtrKey;
62 using ::google::crypto::tink::HashType;
63 using ::google::crypto::tink::HmacKey;
64 
CreateKey(const AesCtrHmacAeadKeyFormat & aes_ctr_hmac_aead_key_format) const65 StatusOr<AesCtrHmacAeadKey> AesCtrHmacAeadKeyManager::CreateKey(
66     const AesCtrHmacAeadKeyFormat& aes_ctr_hmac_aead_key_format) const {
67   AesCtrHmacAeadKey aes_ctr_hmac_aead_key;
68   aes_ctr_hmac_aead_key.set_version(get_version());
69 
70   // Generate AesCtrKey.
71   auto aes_ctr_key = aes_ctr_hmac_aead_key.mutable_aes_ctr_key();
72   aes_ctr_key->set_version(get_version());
73   *(aes_ctr_key->mutable_params()) =
74       aes_ctr_hmac_aead_key_format.aes_ctr_key_format().params();
75   aes_ctr_key->set_key_value(subtle::Random::GetRandomBytes(
76       aes_ctr_hmac_aead_key_format.aes_ctr_key_format().key_size()));
77 
78   // Generate HmacKey.
79   auto hmac_key_or = HmacKeyManager().CreateKey(
80       aes_ctr_hmac_aead_key_format.hmac_key_format());
81   if (!hmac_key_or.status().ok()) {
82     return hmac_key_or.status();
83   }
84   *aes_ctr_hmac_aead_key.mutable_hmac_key() = hmac_key_or.value();
85 
86   return aes_ctr_hmac_aead_key;
87 }
88 
Create(const AesCtrHmacAeadKey & key) const89 StatusOr<std::unique_ptr<Aead>> AesCtrHmacAeadKeyManager::AeadFactory::Create(
90     const AesCtrHmacAeadKey& key) const {
91   auto aes_ctr_result = subtle::AesCtrBoringSsl::New(
92       util::SecretDataFromStringView(key.aes_ctr_key().key_value()),
93       key.aes_ctr_key().params().iv_size());
94   if (!aes_ctr_result.ok()) return aes_ctr_result.status();
95 
96   auto hmac_result = HmacKeyManager().GetPrimitive<Mac>(key.hmac_key());
97   if (!hmac_result.ok()) return hmac_result.status();
98 
99   auto cipher_res = subtle::EncryptThenAuthenticate::New(
100       std::move(aes_ctr_result.value()), std::move(hmac_result.value()),
101       key.hmac_key().params().tag_size());
102   if (!cipher_res.ok()) {
103     return cipher_res.status();
104   }
105   return std::move(cipher_res.value());
106 }
107 
ValidateKey(const AesCtrHmacAeadKey & key) const108 Status AesCtrHmacAeadKeyManager::ValidateKey(
109     const AesCtrHmacAeadKey& key) const {
110   Status status = ValidateVersion(key.version(), get_version());
111   if (!status.ok()) return status;
112 
113   status = ValidateVersion(key.aes_ctr_key().version(), get_version());
114   if (!status.ok()) return status;
115 
116   // Validate AesCtrKey.
117   auto aes_ctr_key = key.aes_ctr_key();
118   uint32_t aes_key_size = aes_ctr_key.key_value().size();
119   status = ValidateAesKeySize(aes_key_size);
120   if (!status.ok()) {
121     return status;
122   }
123   if (aes_ctr_key.params().iv_size() < kMinIvSizeInBytes ||
124       aes_ctr_key.params().iv_size() > 16) {
125     return util::Status(absl::StatusCode::kInvalidArgument,
126                         "Invalid AesCtrHmacAeadKey: IV size out of range.");
127   }
128   return HmacKeyManager().ValidateKey(key.hmac_key());
129 }
130 
ValidateKeyFormat(const AesCtrHmacAeadKeyFormat & key_format) const131 Status AesCtrHmacAeadKeyManager::ValidateKeyFormat(
132     const AesCtrHmacAeadKeyFormat& key_format) const {
133   // Validate AesCtrKeyFormat.
134   auto aes_ctr_key_format = key_format.aes_ctr_key_format();
135   auto status = ValidateAesKeySize(aes_ctr_key_format.key_size());
136   if (!status.ok()) {
137     return status;
138   }
139   if (aes_ctr_key_format.params().iv_size() < kMinIvSizeInBytes ||
140       aes_ctr_key_format.params().iv_size() > 16) {
141     return util::Status(
142         absl::StatusCode::kInvalidArgument,
143         "Invalid AesCtrHmacAeadKeyFormat: IV size out of range.");
144   }
145 
146   // Validate HmacKeyFormat.
147   auto hmac_key_format = key_format.hmac_key_format();
148   if (hmac_key_format.key_size() < kMinKeySizeInBytes) {
149     return util::Status(
150         absl::StatusCode::kInvalidArgument,
151         "Invalid AesCtrHmacAeadKeyFormat: HMAC key_size is too small.");
152   }
153   auto params = hmac_key_format.params();
154   if (params.tag_size() < kMinTagSizeInBytes) {
155     return util::Status(absl::StatusCode::kInvalidArgument,
156                         absl::StrCat("Invalid HmacParams: tag_size ",
157                                      params.tag_size(), " is too small."));
158   }
159   std::map<HashType, uint32_t> max_tag_size = {{HashType::SHA1, 20},
160                                                {HashType::SHA224, 28},
161                                                {HashType::SHA256, 32},
162                                                {HashType::SHA384, 48},
163                                                {HashType::SHA512, 64}};
164   if (max_tag_size.find(params.hash()) == max_tag_size.end()) {
165     return util::Status(
166         absl::StatusCode::kInvalidArgument,
167         absl::StrCat("Invalid HmacParams: HashType '",
168                      Enums::HashName(params.hash()), "' not supported."));
169   } else {
170     if (params.tag_size() > max_tag_size[params.hash()]) {
171       return util::Status(
172           absl::StatusCode::kInvalidArgument,
173           absl::StrCat("Invalid HmacParams: tag_size ", params.tag_size(),
174                        " is too big for HashType '",
175                        Enums::HashName(params.hash()), "'."));
176     }
177   }
178 
179   return HmacKeyManager().ValidateKeyFormat(key_format.hmac_key_format());
180 }
181 
182 // To ensure the resulting key can provide key commitment, the AES-CTR key must
183 // be derived first, then the HMAC key. This avoids situation where it's
184 // possible to brute force raw key material so that the 32th byte of the
185 // keystream is a 0 Give party A a key with this raw key material, saying that
186 // the size of the HMAC key is 32 bytes and the size of the AES key is 16 bytes.
187 // Give party B a key with this raw key material, saying that the size of the
188 // HMAC key is 31 bytes and the size of the AES key is 16 bytes. Since HMAC will
189 // pad the key with zeroes, this leads to both parties using the same HMAC key,
190 // but a different AES key (offset by 1 byte)
DeriveKey(const AesCtrHmacAeadKeyFormat & key_format,InputStream * input_stream) const191 StatusOr<AesCtrHmacAeadKey> AesCtrHmacAeadKeyManager::DeriveKey(
192     const AesCtrHmacAeadKeyFormat& key_format,
193     InputStream* input_stream) const {
194   Status status = ValidateKeyFormat(key_format);
195   if (!status.ok()) {
196     return status;
197   }
198   StatusOr<std::string> aes_ctr_randomness = ReadBytesFromStream(
199       key_format.aes_ctr_key_format().key_size(), input_stream);
200   if (!aes_ctr_randomness.ok()) {
201     if (absl::IsOutOfRange(aes_ctr_randomness.status())) {
202       return crypto::tink::util::Status(
203           absl::StatusCode::kInvalidArgument,
204           "Could not get enough pseudorandomness from input stream");
205     }
206     return aes_ctr_randomness.status();
207   }
208   StatusOr<HmacKey> hmac_key =
209       HmacKeyManager().DeriveKey(key_format.hmac_key_format(), input_stream);
210   if (!hmac_key.ok()) {
211     return hmac_key.status();
212   }
213 
214   google::crypto::tink::AesCtrHmacAeadKey key;
215   key.set_version(get_version());
216   *key.mutable_hmac_key() = hmac_key.value();
217 
218   AesCtrKey* aes_ctr_key = key.mutable_aes_ctr_key();
219   aes_ctr_key->set_version(get_version());
220   aes_ctr_key->set_key_value(aes_ctr_randomness.value());
221   *aes_ctr_key->mutable_params() = key_format.aes_ctr_key_format().params();
222 
223   status = ValidateKey(key);
224   if (!status.ok()) {
225     return status;
226   }
227   return key;
228 }
229 
230 }  // namespace tink
231 }  // namespace crypto
232