1 // Copyright 2019 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/subtle/aes_gcm_hkdf_streaming.h"
18
19 #include <memory>
20 #include <string>
21 #include <utility>
22
23 #include "absl/memory/memory.h"
24 #include "absl/status/status.h"
25 #include "tink/subtle/aes_gcm_hkdf_stream_segment_decrypter.h"
26 #include "tink/subtle/aes_gcm_hkdf_stream_segment_encrypter.h"
27 #include "tink/subtle/common_enums.h"
28 #include "tink/subtle/hkdf.h"
29 #include "tink/subtle/random.h"
30 #include "tink/util/status.h"
31
32 namespace crypto {
33 namespace tink {
34 namespace subtle {
35
36 namespace {
Validate(const AesGcmHkdfStreaming::Params & params)37 util::Status Validate(const AesGcmHkdfStreaming::Params& params) {
38 if (!(params.hkdf_hash == SHA1 || params.hkdf_hash == SHA256 ||
39 params.hkdf_hash == SHA512)) {
40 return util::Status(absl::StatusCode::kInvalidArgument,
41 "unsupported hkdf_hash");
42 }
43 if (params.ikm.size() < 16 || params.ikm.size() < params.derived_key_size) {
44 return util::Status(absl::StatusCode::kInvalidArgument, "ikm too small");
45 }
46 if (params.derived_key_size != 16 && params.derived_key_size != 32) {
47 return util::Status(absl::StatusCode::kInvalidArgument,
48 "derived_key_size must be 16 or 32");
49 }
50 if (params.ciphertext_offset < 0) {
51 return util::Status(absl::StatusCode::kInvalidArgument,
52 "ciphertext_offset must be non-negative");
53 }
54 if (params.ciphertext_segment_size <=
55 params.ciphertext_offset + params.derived_key_size +
56 AesGcmHkdfStreamSegmentEncrypter::kTagSizeInBytes) {
57 return util::Status(absl::StatusCode::kInvalidArgument,
58 "ciphertext_segment_size too small");
59 }
60 return util::OkStatus();
61 }
62 } // namespace
63
New(Params params)64 util::StatusOr<std::unique_ptr<AesGcmHkdfStreaming>> AesGcmHkdfStreaming::New(
65 Params params) {
66 auto status = internal::CheckFipsCompatibility<AesGcmHkdfStreaming>();
67 if (!status.ok()) return status;
68
69 status = Validate(params);
70 if (!status.ok()) return status;
71 return {absl::WrapUnique(new AesGcmHkdfStreaming(std::move(params)))};
72 }
73
74 util::StatusOr<std::unique_ptr<StreamSegmentEncrypter>>
NewSegmentEncrypter(absl::string_view associated_data) const75 AesGcmHkdfStreaming::NewSegmentEncrypter(
76 absl::string_view associated_data) const {
77 AesGcmHkdfStreamSegmentEncrypter::Params params;
78 params.salt = Random::GetRandomBytes(derived_key_size_);
79 auto hkdf_result = Hkdf::ComputeHkdf(hkdf_hash_, ikm_, params.salt,
80 associated_data, derived_key_size_);
81 if (!hkdf_result.ok()) return hkdf_result.status();
82 params.key = std::move(hkdf_result).value();
83 params.ciphertext_offset = ciphertext_offset_;
84 params.ciphertext_segment_size = ciphertext_segment_size_;
85 return AesGcmHkdfStreamSegmentEncrypter::New(std::move(params));
86 }
87
88 util::StatusOr<std::unique_ptr<StreamSegmentDecrypter>>
NewSegmentDecrypter(absl::string_view associated_data) const89 AesGcmHkdfStreaming::NewSegmentDecrypter(
90 absl::string_view associated_data) const {
91 AesGcmHkdfStreamSegmentDecrypter::Params params;
92 params.ikm = ikm_;
93 params.hkdf_hash = hkdf_hash_;
94 params.derived_key_size = derived_key_size_;
95 params.ciphertext_offset = ciphertext_offset_;
96 params.ciphertext_segment_size = ciphertext_segment_size_;
97 params.associated_data = std::string(associated_data);
98 return AesGcmHkdfStreamSegmentDecrypter::New(std::move(params));
99 }
100
101 } // namespace subtle
102 } // namespace tink
103 } // namespace crypto
104