xref: /aosp_15_r20/external/tink/cc/subtle/aes_gcm_hkdf_streaming_test.cc (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 #include "tink/subtle/aes_gcm_hkdf_streaming.h"
18 
19 #include <sstream>
20 #include <string>
21 #include <utility>
22 
23 #include "gtest/gtest.h"
24 #include "absl/memory/memory.h"
25 #include "absl/status/status.h"
26 #include "absl/strings/str_cat.h"
27 #include "tink/config/tink_fips.h"
28 #include "tink/output_stream.h"
29 #include "tink/subtle/common_enums.h"
30 #include "tink/subtle/random.h"
31 #include "tink/subtle/streaming_aead_test_util.h"
32 #include "tink/subtle/test_util.h"
33 #include "tink/util/istream_input_stream.h"
34 #include "tink/util/ostream_output_stream.h"
35 #include "tink/util/status.h"
36 #include "tink/util/statusor.h"
37 #include "tink/util/test_matchers.h"
38 
39 namespace crypto {
40 namespace tink {
41 namespace subtle {
42 namespace {
43 
44 using ::crypto::tink::test::IsOk;
45 using ::crypto::tink::test::StatusIs;
46 
TEST(AesGcmHkdfStreamingTest,testBasic)47 TEST(AesGcmHkdfStreamingTest, testBasic) {
48   if (IsFipsModeEnabled()) {
49     GTEST_SKIP() << "Not supported in FIPS-only mode";
50   }
51   for (HashType hkdf_hash : {SHA1, SHA256, SHA512}) {
52     for (int ikm_size : {16, 32}) {
53       for (int derived_key_size = 16;
54            derived_key_size <= ikm_size;
55            derived_key_size += 16) {
56         for (int ct_segment_size : {80, 128, 200}) {
57           for (int ciphertext_offset : {0, 10, 16}) {
58             SCOPED_TRACE(absl::StrCat(
59                 "hkdf_hash = ", EnumToString(hkdf_hash),
60                 ", ikm_size = ", ikm_size,
61                 ", derived_key_size = ", derived_key_size,
62                 ", ciphertext_segment_size = ", ct_segment_size,
63                 ", ciphertext_offset = ", ciphertext_offset));
64             // Create AesGcmHkdfStreaming.
65             AesGcmHkdfStreaming::Params params;
66             params.ikm = Random::GetRandomKeyBytes(ikm_size);
67             params.hkdf_hash = hkdf_hash;
68             params.derived_key_size = derived_key_size;
69             params.ciphertext_segment_size = ct_segment_size;
70             params.ciphertext_offset = ciphertext_offset;
71             auto result = AesGcmHkdfStreaming::New(std::move(params));
72             EXPECT_TRUE(result.ok()) << result.status();
73             auto streaming_aead = std::move(result.value());
74 
75             // Try to get an encrypting stream to a "null" ct_destination.
76             std::string associated_data = "some associated data";
77             auto failed_result = streaming_aead->NewEncryptingStream(
78                 nullptr, associated_data);
79             EXPECT_FALSE(failed_result.ok());
80             EXPECT_EQ(absl::StatusCode::kInvalidArgument,
81                       failed_result.status().code());
82             EXPECT_PRED_FORMAT2(testing::IsSubstring, "non-null",
83                                 std::string(failed_result.status().message()));
84 
85             for (int pt_size : {0, 16, 100, 1000, 10000}) {
86               SCOPED_TRACE(absl::StrCat(" pt_size = ", pt_size));
87               std::string pt = Random::GetRandomBytes(pt_size);
88               EXPECT_THAT(
89                   EncryptThenDecrypt(streaming_aead.get(), streaming_aead.get(),
90                                      pt, associated_data, ciphertext_offset),
91                   IsOk());
92             }
93           }
94         }
95       }
96     }
97   }
98 }
99 
TEST(AesGcmHkdfStreamingTest,testIkmSmallerThanDerivedKey)100 TEST(AesGcmHkdfStreamingTest, testIkmSmallerThanDerivedKey) {
101   if (IsFipsModeEnabled()) {
102     GTEST_SKIP() << "Not supported in FIPS-only mode";
103   }
104   AesGcmHkdfStreaming::Params params;
105   int ikm_size = 16;
106   params.ikm = Random::GetRandomKeyBytes(ikm_size);
107   params.derived_key_size = 17;
108   params.ciphertext_segment_size = 100;
109   params.ciphertext_offset = 10;
110   params.hkdf_hash = SHA256;
111   auto result = AesGcmHkdfStreaming::New(std::move(params));
112   EXPECT_FALSE(result.ok());
113   EXPECT_EQ(absl::StatusCode::kInvalidArgument, result.status().code());
114   EXPECT_PRED_FORMAT2(testing::IsSubstring, "ikm too small",
115                       std::string(result.status().message()));
116 }
117 
TEST(AesGcmHkdfStreamingTest,testIkmSize)118 TEST(AesGcmHkdfStreamingTest, testIkmSize) {
119   if (IsFipsModeEnabled()) {
120     GTEST_SKIP() << "Not supported in FIPS-only mode";
121   }
122   for (int ikm_size : {5, 10, 15}) {
123     AesGcmHkdfStreaming::Params params;
124     params.ikm = Random::GetRandomKeyBytes(ikm_size);
125     params.derived_key_size = 17;
126     params.ciphertext_segment_size = 100;
127     params.ciphertext_offset = 0;
128     params.hkdf_hash = SHA256;
129 
130     auto result = AesGcmHkdfStreaming::New(std::move(params));
131     EXPECT_FALSE(result.ok());
132     EXPECT_EQ(absl::StatusCode::kInvalidArgument, result.status().code());
133     EXPECT_PRED_FORMAT2(testing::IsSubstring, "ikm too small",
134                         std::string(result.status().message()));
135   }
136 }
137 
TEST(AesGcmHkdfStreamingTest,testWrongHkdfHash)138 TEST(AesGcmHkdfStreamingTest, testWrongHkdfHash) {
139   if (IsFipsModeEnabled()) {
140     GTEST_SKIP() << "Not supported in FIPS-only mode";
141   }
142   AesGcmHkdfStreaming::Params params;
143   int ikm_size = 16;
144   params.ikm = Random::GetRandomKeyBytes(ikm_size);
145   params.derived_key_size = 16;
146   params.ciphertext_segment_size = 100;
147   params.ciphertext_offset = 10;
148   params.hkdf_hash = SHA384;
149 
150   auto result = AesGcmHkdfStreaming::New(std::move(params));
151   EXPECT_FALSE(result.ok());
152   EXPECT_EQ(absl::StatusCode::kInvalidArgument, result.status().code());
153   EXPECT_PRED_FORMAT2(testing::IsSubstring, "unsupported hkdf_hash",
154                       std::string(result.status().message()));
155 }
156 
TEST(AesGcmHkdfStreamingTest,testWrongDerivedKeySize)157 TEST(AesGcmHkdfStreamingTest, testWrongDerivedKeySize) {
158   if (IsFipsModeEnabled()) {
159     GTEST_SKIP() << "Not supported in FIPS-only mode";
160   }
161   AesGcmHkdfStreaming::Params params;
162   int ikm_size = 20;
163   params.ikm = Random::GetRandomKeyBytes(ikm_size);
164   params.derived_key_size = 20;
165   params.ciphertext_segment_size = 100;
166   params.ciphertext_offset = 10;
167   params.hkdf_hash = SHA256;
168 
169   auto result = AesGcmHkdfStreaming::New(std::move(params));
170   EXPECT_FALSE(result.ok());
171   EXPECT_EQ(absl::StatusCode::kInvalidArgument, result.status().code());
172   EXPECT_PRED_FORMAT2(testing::IsSubstring, "must be 16 or 32",
173                       std::string(result.status().message()));
174 }
175 
TEST(AesGcmHkdfStreamingTest,testWrongCiphertextOffset)176 TEST(AesGcmHkdfStreamingTest, testWrongCiphertextOffset) {
177   if (IsFipsModeEnabled()) {
178     GTEST_SKIP() << "Not supported in FIPS-only mode";
179   }
180   AesGcmHkdfStreaming::Params params;
181   int ikm_size = 32;
182   params.ikm = Random::GetRandomKeyBytes(ikm_size);
183   params.derived_key_size = 32;
184   params.ciphertext_segment_size = 100;
185   params.ciphertext_offset = -5;
186   params.hkdf_hash = SHA256;
187 
188   auto result = AesGcmHkdfStreaming::New(std::move(params));
189   EXPECT_FALSE(result.ok());
190   EXPECT_EQ(absl::StatusCode::kInvalidArgument, result.status().code());
191   EXPECT_PRED_FORMAT2(testing::IsSubstring, "must be non-negative",
192                       std::string(result.status().message()));
193 }
194 
TEST(AesGcmHkdfStreamingTest,testWrongCiphertextSegmentSize)195 TEST(AesGcmHkdfStreamingTest, testWrongCiphertextSegmentSize) {
196   if (IsFipsModeEnabled()) {
197     GTEST_SKIP() << "Not supported in FIPS-only mode";
198   }
199   AesGcmHkdfStreaming::Params params;
200   int ikm_size = 32;
201   params.ikm = Random::GetRandomKeyBytes(ikm_size);
202   params.derived_key_size = 32;
203   params.ciphertext_segment_size = 64;
204   params.ciphertext_offset = 40;
205   params.hkdf_hash = SHA256;
206 
207   auto result = AesGcmHkdfStreaming::New(std::move(params));
208   EXPECT_FALSE(result.ok());
209   EXPECT_EQ(absl::StatusCode::kInvalidArgument, result.status().code());
210   EXPECT_PRED_FORMAT2(testing::IsSubstring, "ciphertext_segment_size too small",
211                       std::string(result.status().message()));
212 }
213 
214 
215 // FIPS only mode tests
TEST(AesGcmHkdfStreamingTest,TestFipsOnly)216 TEST(AesGcmHkdfStreamingTest, TestFipsOnly) {
217   if (!IsFipsModeEnabled()) {
218     GTEST_SKIP() << "Only supported in FIPS-only mode";
219   }
220   AesGcmHkdfStreaming::Params params;
221   int ikm_size = 32;
222   params.ikm = Random::GetRandomKeyBytes(ikm_size);
223   params.derived_key_size = 32;
224   params.ciphertext_segment_size = 64;
225   params.ciphertext_offset = 40;
226   params.hkdf_hash = SHA256;
227 
228   EXPECT_THAT(AesGcmHkdfStreaming::New(std::move(params)).status(),
229               StatusIs(absl::StatusCode::kInternal));
230 }
231 
232 }  // namespace
233 }  // namespace subtle
234 }  // namespace tink
235 }  // namespace crypto
236