xref: /aosp_15_r20/external/tink/cc/subtle/aes_ctr_hmac_streaming.h (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
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 #ifndef TINK_SUBTLE_AES_CTR_HMAC_STREAMING_H_
18 #define TINK_SUBTLE_AES_CTR_HMAC_STREAMING_H_
19 
20 #include <memory>
21 #include <string>
22 #include <utility>
23 #include <vector>
24 
25 #include "absl/strings/string_view.h"
26 #include "openssl/evp.h"
27 #include "tink/internal/fips_utils.h"
28 #include "tink/mac.h"
29 #include "tink/subtle/common_enums.h"
30 #include "tink/subtle/nonce_based_streaming_aead.h"
31 #include "tink/subtle/stream_segment_decrypter.h"
32 #include "tink/subtle/stream_segment_encrypter.h"
33 #include "tink/util/secret_data.h"
34 #include "tink/util/status.h"
35 #include "tink/util/statusor.h"
36 
37 namespace crypto {
38 namespace tink {
39 namespace subtle {
40 
41 // Streaming encryption using AES-CTR and HMAC.
42 //
43 // Each ciphertext uses a new AES-CTR key and HMAC key that are derived from the
44 // key derivation key, a randomly chosen salt of the same size as the key and a
45 // nonce prefix using HKDF.
46 //
47 // The format of a ciphertext is
48 //   header || segment_0 || segment_1 || ... || segment_k.
49 // where:
50 //  - segment_i is the i-th segment of the ciphertext.
51 //  - the size of segment_1 .. segment_{k-1} is get_ciphertext_segment_size()
52 //  - segment_0 is shorter, so that segment_0, the header and other information
53 //    of size get_ciphertext_offset() align with get_ciphertext_segment_size().
54 //
55 // The format of the header is
56 //   header_size || salt || nonce_prefix
57 // where
58 //  - header_size is 1 byte determining the size of the header
59 //  - salt is a salt used in the key derivation
60 //  - nonce_prefix is the prefix of the nonce
61 //
62 // In principle header_size is redundant information, since the length of the
63 // header can be determined from the key size.
64 class AesCtrHmacStreaming : public NonceBasedStreamingAead {
65  public:
66   struct Params {
67     util::SecretData ikm;
68     HashType hkdf_algo;
69     int key_size;
70     int ciphertext_segment_size;
71     int ciphertext_offset;
72     HashType tag_algo;
73     int tag_size;
74   };
75 
76   // The size of the nonce for AES-CTR.
77   static constexpr int kNonceSizeInBytes = 16;
78 
79   // The nonce has the format nonce_prefix || ctr || last_block || 0 0 0 0,
80   // where:
81   //  - nonce_prefix is a constant of kNoncePrefixSizeInBytes bytes
82   //    for the whole file
83   //  - ctr is a big endian 32 bit counter
84   //  - last_block is a byte equal to 1 for the last block of the file
85   //    and 0 otherwise.
86   static constexpr int kNoncePrefixSizeInBytes = 7;
87 
88   static constexpr int kHmacKeySizeInBytes = 32;
89 
90   static util::StatusOr<std::unique_ptr<AesCtrHmacStreaming>> New(
91       Params params);
92 
93   static constexpr crypto::tink::internal::FipsCompatibility kFipsStatus =
94       crypto::tink::internal::FipsCompatibility::kNotFips;
95 
96  protected:
97   util::StatusOr<std::unique_ptr<StreamSegmentEncrypter>> NewSegmentEncrypter(
98       absl::string_view associated_data) const override;
99 
100   util::StatusOr<std::unique_ptr<StreamSegmentDecrypter>> NewSegmentDecrypter(
101       absl::string_view associated_data) const override;
102 
103  private:
AesCtrHmacStreaming(Params params)104   explicit AesCtrHmacStreaming(Params params) : params_(std::move(params)) {}
105   const Params params_;
106 };
107 
108 class AesCtrHmacStreamSegmentEncrypter : public StreamSegmentEncrypter {
109  public:
110   // A factory.
111   static util::StatusOr<std::unique_ptr<StreamSegmentEncrypter>> New(
112       const AesCtrHmacStreaming::Params& params,
113       absl::string_view associated_data);
114 
115   // Overridden methods of StreamSegmentEncrypter.
116   util::Status EncryptSegment(const std::vector<uint8_t>& plaintext,
117                               bool is_last_segment,
118                               std::vector<uint8_t>* ciphertext_buffer) override;
119 
get_header()120   const std::vector<uint8_t>& get_header() const override { return header_; }
get_segment_number()121   int64_t get_segment_number() const override { return segment_number_; }
get_plaintext_segment_size()122   int get_plaintext_segment_size() const override {
123     return ciphertext_segment_size_ - tag_size_;
124   }
get_ciphertext_segment_size()125   int get_ciphertext_segment_size() const override {
126     return ciphertext_segment_size_;
127   }
get_ciphertext_offset()128   int get_ciphertext_offset() const override { return ciphertext_offset_; }
129 
130  protected:
IncSegmentNumber()131   void IncSegmentNumber() override { segment_number_++; }
132 
133  private:
AesCtrHmacStreamSegmentEncrypter(util::SecretData key_value,absl::string_view header,absl::string_view nonce_prefix,int ciphertext_segment_size,int ciphertext_offset,int tag_size,const EVP_CIPHER * cipher,std::unique_ptr<Mac> mac)134   AesCtrHmacStreamSegmentEncrypter(util::SecretData key_value,
135                                    absl::string_view header,
136                                    absl::string_view nonce_prefix,
137                                    int ciphertext_segment_size,
138                                    int ciphertext_offset, int tag_size,
139                                    const EVP_CIPHER* cipher,
140                                    std::unique_ptr<Mac> mac)
141       : key_value_(std::move(key_value)),
142         header_(header.begin(), header.end()),
143         nonce_prefix_(nonce_prefix),
144         ciphertext_segment_size_(ciphertext_segment_size),
145         ciphertext_offset_(ciphertext_offset),
146         tag_size_(tag_size),
147         cipher_(cipher),
148         mac_(std::move(mac)),
149         segment_number_(0) {}
150 
151   const util::SecretData key_value_;
152   const std::vector<uint8_t> header_;
153   const std::string nonce_prefix_;
154   const int ciphertext_segment_size_;
155   const int ciphertext_offset_;
156   const int tag_size_;
157   const EVP_CIPHER* cipher_;
158   const std::unique_ptr<Mac> mac_;
159   int64_t segment_number_;
160 };
161 
162 class AesCtrHmacStreamSegmentDecrypter : public StreamSegmentDecrypter {
163  public:
164   // A factory.
165   static util::StatusOr<std::unique_ptr<StreamSegmentDecrypter>> New(
166       const AesCtrHmacStreaming::Params& params,
167       absl::string_view associated_data);
168 
169   // Overridden methods of StreamSegmentDecrypter.
170   util::Status Init(const std::vector<uint8_t>& header) override;
171 
172   util::Status DecryptSegment(const std::vector<uint8_t>& ciphertext,
173                               int64_t segment_number, bool is_last_segment,
174                               std::vector<uint8_t>* plaintext_buffer) override;
175 
get_header_size()176   int get_header_size() const override {
177     return 1 + key_size_ + AesCtrHmacStreaming::kNoncePrefixSizeInBytes;
178   }
get_plaintext_segment_size()179   int get_plaintext_segment_size() const override {
180     return ciphertext_segment_size_ - tag_size_;
181   }
get_ciphertext_segment_size()182   int get_ciphertext_segment_size() const override {
183     return ciphertext_segment_size_;
184   }
get_ciphertext_offset()185   int get_ciphertext_offset() const override { return ciphertext_offset_; }
186   ~AesCtrHmacStreamSegmentDecrypter() override = default;
187 
188  private:
AesCtrHmacStreamSegmentDecrypter(util::SecretData ikm,HashType hkdf_algo,int key_size,absl::string_view associated_data,int ciphertext_segment_size,int ciphertext_offset,HashType tag_algo,int tag_size)189   AesCtrHmacStreamSegmentDecrypter(util::SecretData ikm, HashType hkdf_algo,
190                                    int key_size,
191                                    absl::string_view associated_data,
192                                    int ciphertext_segment_size,
193                                    int ciphertext_offset, HashType tag_algo,
194                                    int tag_size)
195       : ikm_(std::move(ikm)),
196         hkdf_algo_(hkdf_algo),
197         key_size_(key_size),
198         associated_data_(associated_data),
199         ciphertext_segment_size_(ciphertext_segment_size),
200         ciphertext_offset_(ciphertext_offset),
201         tag_algo_(tag_algo),
202         tag_size_(tag_size) {}
203 
204   // Parameters set upon decrypter creation.
205   const util::SecretData ikm_;
206   const HashType hkdf_algo_;
207   const int key_size_;
208   const std::string associated_data_;
209   const int ciphertext_segment_size_;
210   const int ciphertext_offset_;
211   const HashType tag_algo_;
212   const int tag_size_;
213 
214   // Parameters set when initializing with data from stream header.
215   bool is_initialized_ = false;
216   util::SecretData key_value_;
217   std::string nonce_prefix_;
218   const EVP_CIPHER* cipher_;
219   std::unique_ptr<Mac> mac_;
220 };
221 
222 }  // namespace subtle
223 }  // namespace tink
224 }  // namespace crypto
225 
226 #endif  // TINK_SUBTLE_AES_CTR_HMAC_STREAMING_H_
227