1 // Copyright 2019 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/streamingaead/aes_ctr_hmac_streaming_key_manager.h"
18
19 #include <string>
20
21 #include "absl/status/status.h"
22 #include "tink/subtle/aes_ctr_hmac_streaming.h"
23 #include "tink/subtle/random.h"
24 #include "tink/util/input_stream_util.h"
25 #include "tink/util/status.h"
26 #include "tink/util/validation.h"
27
28 namespace crypto {
29 namespace tink {
30
31 using ::crypto::tink::subtle::AesCtrHmacStreaming;
32 using ::crypto::tink::util::Status;
33 using ::crypto::tink::util::StatusOr;
34 using ::google::crypto::tink::AesCtrHmacStreamingKey;
35 using ::google::crypto::tink::AesCtrHmacStreamingKeyFormat;
36 using ::google::crypto::tink::AesCtrHmacStreamingParams;
37 using ::google::crypto::tink::HashType;
38
39 namespace {
40
ValidateParams(const AesCtrHmacStreamingParams & params)41 Status ValidateParams(const AesCtrHmacStreamingParams& params) {
42 if (!(params.hkdf_hash_type() == HashType::SHA1 ||
43 params.hkdf_hash_type() == HashType::SHA256 ||
44 params.hkdf_hash_type() == HashType::SHA512)) {
45 return Status(absl::StatusCode::kInvalidArgument,
46 "unsupported hkdf_hash_type");
47 }
48 if (!(params.hmac_params().hash() == HashType::SHA1 ||
49 params.hmac_params().hash() == HashType::SHA256 ||
50 params.hmac_params().hash() == HashType::SHA512)) {
51 return Status(absl::StatusCode::kInvalidArgument,
52 "unsupported hmac_params.hash");
53 }
54 if (params.hmac_params().tag_size() < 10) {
55 return Status(absl::StatusCode::kInvalidArgument,
56 "hmac_params.tag_size too small");
57 }
58 if ((params.hmac_params().hash() == HashType::SHA1 &&
59 params.hmac_params().tag_size() > 20) ||
60 (params.hmac_params().hash() == HashType::SHA256 &&
61 params.hmac_params().tag_size() > 32) ||
62 (params.hmac_params().hash() == HashType::SHA512 &&
63 params.hmac_params().tag_size() > 64)) {
64 return Status(absl::StatusCode::kInvalidArgument,
65 "hmac_params.tag_size too big");
66 }
67 int header_size = 1 + params.derived_key_size() +
68 AesCtrHmacStreaming::kNoncePrefixSizeInBytes;
69 if (params.ciphertext_segment_size() <=
70 header_size + params.hmac_params().tag_size()) {
71 return Status(absl::StatusCode::kInvalidArgument,
72 "ciphertext_segment_size too small");
73 }
74 if (params.ciphertext_segment_size() > 0x7fffffff) {
75 return Status(absl::StatusCode::kInvalidArgument,
76 "ciphertext_segment_size too big");
77 }
78 return ValidateAesKeySize(params.derived_key_size());
79 }
80
81 } // namespace
82
83 crypto::tink::util::StatusOr<google::crypto::tink::AesCtrHmacStreamingKey>
CreateKey(const google::crypto::tink::AesCtrHmacStreamingKeyFormat & key_format) const84 AesCtrHmacStreamingKeyManager::CreateKey(
85 const google::crypto::tink::AesCtrHmacStreamingKeyFormat& key_format)
86 const {
87 AesCtrHmacStreamingKey key;
88 key.set_version(get_version());
89 key.set_key_value(subtle::Random::GetRandomBytes(key_format.key_size()));
90 *key.mutable_params() = key_format.params();
91 return key;
92 };
93
94 crypto::tink::util::StatusOr<google::crypto::tink::AesCtrHmacStreamingKey>
DeriveKey(const google::crypto::tink::AesCtrHmacStreamingKeyFormat & key_format,InputStream * input_stream) const95 AesCtrHmacStreamingKeyManager::DeriveKey(
96 const google::crypto::tink::AesCtrHmacStreamingKeyFormat& key_format,
97 InputStream* input_stream) const {
98 crypto::tink::util::Status status =
99 ValidateVersion(key_format.version(), get_version());
100 if (!status.ok()) return status;
101
102 crypto::tink::util::StatusOr<std::string> randomness_or =
103 ReadBytesFromStream(key_format.key_size(), input_stream);
104 if (!randomness_or.ok()) {
105 return randomness_or.status();
106 }
107 AesCtrHmacStreamingKey key;
108 key.set_version(get_version());
109 key.set_key_value(randomness_or.value());
110 *key.mutable_params() = key_format.params();
111 return key;
112 }
113
ValidateKey(const AesCtrHmacStreamingKey & key) const114 Status AesCtrHmacStreamingKeyManager::ValidateKey(
115 const AesCtrHmacStreamingKey& key) const {
116 Status status = ValidateVersion(key.version(), get_version());
117 if (!status.ok()) return status;
118 if (key.key_value().size() < key.params().derived_key_size()) {
119 return Status(absl::StatusCode::kInvalidArgument,
120 "key_value (i.e. ikm) too short");
121 }
122 return ValidateParams(key.params());
123 }
124
ValidateKeyFormat(const AesCtrHmacStreamingKeyFormat & key_format) const125 Status AesCtrHmacStreamingKeyManager::ValidateKeyFormat(
126 const AesCtrHmacStreamingKeyFormat& key_format) const {
127 if (key_format.key_size() < key_format.params().derived_key_size()) {
128 return Status(absl::StatusCode::kInvalidArgument,
129 "key_size must not be smaller than derived_key_size");
130 }
131 return ValidateParams(key_format.params());
132 }
133
134 } // namespace tink
135 } // namespace crypto
136