• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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