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/streamingaead/aes_gcm_hkdf_streaming_key_manager.h"
18
19 #include <string>
20
21 #include "absl/status/status.h"
22 #include "tink/subtle/aes_gcm_hkdf_stream_segment_encrypter.h"
23 #include "tink/subtle/random.h"
24 #include "tink/util/input_stream_util.h"
25 #include "tink/util/validation.h"
26
27 namespace crypto {
28 namespace tink {
29
30 using ::crypto::tink::subtle::AesGcmHkdfStreamSegmentEncrypter;
31 using ::crypto::tink::util::Status;
32 using ::crypto::tink::util::StatusOr;
33 using ::google::crypto::tink::AesGcmHkdfStreamingKey;
34 using ::google::crypto::tink::AesGcmHkdfStreamingKeyFormat;
35 using ::google::crypto::tink::AesGcmHkdfStreamingParams;
36 using ::google::crypto::tink::HashType;
37
38 namespace {
39
ValidateParams(const AesGcmHkdfStreamingParams & params)40 Status ValidateParams(const AesGcmHkdfStreamingParams& params) {
41 if (!(params.hkdf_hash_type() == HashType::SHA1 ||
42 params.hkdf_hash_type() == HashType::SHA256 ||
43 params.hkdf_hash_type() == HashType::SHA512)) {
44 return Status(absl::StatusCode::kInvalidArgument,
45 "unsupported hkdf_hash_type");
46 }
47 int header_size = 1 + params.derived_key_size() +
48 AesGcmHkdfStreamSegmentEncrypter::kNoncePrefixSizeInBytes;
49 if (params.ciphertext_segment_size() <=
50 header_size + AesGcmHkdfStreamSegmentEncrypter::kTagSizeInBytes) {
51 return Status(absl::StatusCode::kInvalidArgument,
52 "ciphertext_segment_size too small");
53 }
54 return ValidateAesKeySize(params.derived_key_size());
55 }
56
57 } // namespace
58
59 crypto::tink::util::StatusOr<google::crypto::tink::AesGcmHkdfStreamingKey>
CreateKey(const google::crypto::tink::AesGcmHkdfStreamingKeyFormat & key_format) const60 AesGcmHkdfStreamingKeyManager::CreateKey(
61 const google::crypto::tink::AesGcmHkdfStreamingKeyFormat& key_format)
62 const {
63 AesGcmHkdfStreamingKey key;
64 key.set_version(get_version());
65 key.set_key_value(subtle::Random::GetRandomBytes(key_format.key_size()));
66 *key.mutable_params() = key_format.params();
67 return key;
68 };
69
70 crypto::tink::util::StatusOr<google::crypto::tink::AesGcmHkdfStreamingKey>
DeriveKey(const google::crypto::tink::AesGcmHkdfStreamingKeyFormat & key_format,InputStream * input_stream) const71 AesGcmHkdfStreamingKeyManager::DeriveKey(
72 const google::crypto::tink::AesGcmHkdfStreamingKeyFormat& key_format,
73 InputStream* input_stream) const {
74 crypto::tink::util::Status status =
75 ValidateVersion(key_format.version(), get_version());
76 if (!status.ok()) return status;
77
78 crypto::tink::util::StatusOr<std::string> randomness_or =
79 ReadBytesFromStream(key_format.key_size(), input_stream);
80 if (!randomness_or.ok()) {
81 return randomness_or.status();
82 }
83 AesGcmHkdfStreamingKey key;
84 key.set_version(get_version());
85 key.set_key_value(randomness_or.value());
86 *key.mutable_params() = key_format.params();
87 return key;
88 }
89
ValidateKey(const AesGcmHkdfStreamingKey & key) const90 Status AesGcmHkdfStreamingKeyManager::ValidateKey(
91 const AesGcmHkdfStreamingKey& key) const {
92 Status status = ValidateVersion(key.version(), get_version());
93 if (!status.ok()) return status;
94 if (key.key_value().size() < key.params().derived_key_size()) {
95 return Status(absl::StatusCode::kInvalidArgument,
96 "key_value (i.e. ikm) too short");
97 }
98 return ValidateParams(key.params());
99 }
100
ValidateKeyFormat(const AesGcmHkdfStreamingKeyFormat & key_format) const101 Status AesGcmHkdfStreamingKeyManager::ValidateKeyFormat(
102 const AesGcmHkdfStreamingKeyFormat& key_format) const {
103 if (key_format.key_size() < key_format.params().derived_key_size()) {
104 return Status(absl::StatusCode::kInvalidArgument,
105 "key_size must not be smaller than derived_key_size");
106 }
107 return ValidateParams(key_format.params());
108 }
109
110 } // namespace tink
111 } // namespace crypto
112