xref: /aosp_15_r20/external/tink/cc/subtle/aes_gcm_hkdf_stream_segment_encrypter.h (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
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 #ifndef TINK_SUBTLE_AES_GCM_HKDF_STREAM_SEGMENT_ENCRYPTER_H_
18 #define TINK_SUBTLE_AES_GCM_HKDF_STREAM_SEGMENT_ENCRYPTER_H_
19 
20 #include <memory>
21 #include <string>
22 #include <vector>
23 
24 #include "tink/aead/internal/ssl_aead.h"
25 #include "tink/subtle/stream_segment_encrypter.h"
26 #include "tink/util/secret_data.h"
27 #include "tink/util/statusor.h"
28 
29 namespace crypto {
30 namespace tink {
31 namespace subtle {
32 
33 // StreamSegmentEncrypter for streaming encryption using AES-GCM with HKDF as
34 // key derivation function.
35 //
36 // Each ciphertext uses a new AES-GCM key that is derived from the key
37 // derivation key, a randomly chosen salt of the same size as the key and a
38 // nonce prefix.
39 //
40 // The format of a ciphertext is
41 //   header || segment_0 || segment_1 || ... || segment_k.
42 // where:
43 //  - segment_i is the i-th segment of the ciphertext.
44 //  - the size of segment_1 .. segment_{k-1} is get_ciphertext_segment_size()
45 //  - segment_0 is shorter, so that segment_0, the header and other information
46 //    of size get_ciphertext_offset() align with get_ciphertext_segment_size().
47 //
48 // The format of the header is
49 //   header_size || salt || nonce_prefix
50 // where
51 //  - header_size is 1 byte determining the size of the header
52 //  - salt is a salt used in the key derivation
53 //  - nonce_prefix is the prefix of the nonce
54 //
55 // In principle header_size is redundant information, since the length of the
56 // header can be determined from the key size.
57 
58 class AesGcmHkdfStreamSegmentEncrypter : public StreamSegmentEncrypter {
59  public:
60   // The size of the IVs for GCM.
61   static constexpr int kNonceSizeInBytes = 12;
62 
63   // The nonce has the format nonce_prefix || ctr || last_block, where:
64   //  - nonce_prefix is a constant of kNoncePrefixSizeInBytes bytes
65   //    for the whole file
66   //  - ctr is a 32 bit counter
67   //  - last_block is a byte equal to 1 for the last block of the file
68   //    and 0 otherwise.
69   static constexpr int kNoncePrefixSizeInBytes = 7;
70 
71   // The size of the tags of each ciphertext segment.
72   static constexpr int kTagSizeInBytes = 16;
73 
74   struct Params {
75     util::SecretData key;
76     std::string salt;
77     int ciphertext_offset;
78     int ciphertext_segment_size;
79   };
80 
81   static util::StatusOr<std::unique_ptr<StreamSegmentEncrypter>> New(
82       Params params);
83 
84   util::Status EncryptSegment(const std::vector<uint8_t>& plaintext,
85                               bool is_last_segment,
86                               std::vector<uint8_t>* ciphertext_buffer) override;
87 
get_header()88   const std::vector<uint8_t>& get_header() const override { return header_; }
get_segment_number()89   int64_t get_segment_number() const override { return segment_number_; }
90   int get_plaintext_segment_size() const override;
get_ciphertext_segment_size()91   int get_ciphertext_segment_size() const override {
92     return ciphertext_segment_size_;
93   }
get_ciphertext_offset()94   int get_ciphertext_offset() const override { return ciphertext_offset_; }
95 
96  protected:
IncSegmentNumber()97   void IncSegmentNumber() override { segment_number_++; }
98 
99  private:
100   AesGcmHkdfStreamSegmentEncrypter(
101       std::unique_ptr<internal::SslOneShotAead> aead, const Params& params);
102 
103   // When OpenSSL is used, this uses a thread-safe implementation that makes a
104   // copy of the context for each EncryptSegment call, which may result in some
105   // extra latency compared to BoringSSL.
106   const std::unique_ptr<internal::SslOneShotAead> aead_;
107 
108   const std::string nonce_prefix_;
109   const std::vector<uint8_t> header_;
110   const int ciphertext_segment_size_;
111   const int ciphertext_offset_;
112 
113   int64_t segment_number_ = 0;
114 };
115 
116 }  // namespace subtle
117 }  // namespace tink
118 }  // namespace crypto
119 
120 #endif  // TINK_SUBTLE_AES_GCM_HKDF_STREAM_SEGMENT_ENCRYPTER_H_
121