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/aead/xchacha20_poly1305_key_manager.h"
18
19 #include <memory>
20 #include <sstream>
21 #include <string>
22
23 #include "gmock/gmock.h"
24 #include "gtest/gtest.h"
25 #include "absl/memory/memory.h"
26 #include "absl/status/status.h"
27 #include "tink/aead.h"
28 #include "tink/internal/ssl_util.h"
29 #include "tink/subtle/aead_test_util.h"
30 #include "tink/subtle/xchacha20_poly1305_boringssl.h"
31 #include "tink/util/istream_input_stream.h"
32 #include "tink/util/secret_data.h"
33 #include "tink/util/status.h"
34 #include "tink/util/statusor.h"
35 #include "tink/util/test_matchers.h"
36 #include "proto/tink.pb.h"
37 #include "proto/xchacha20_poly1305.pb.h"
38
39 namespace crypto {
40 namespace tink {
41
42 namespace {
43
44 using ::crypto::tink::test::IsOk;
45 using ::crypto::tink::test::StatusIs;
46 using ::crypto::tink::util::StatusOr;
47 using ::google::crypto::tink::XChaCha20Poly1305Key;
48 using ::google::crypto::tink::XChaCha20Poly1305KeyFormat;
49 using ::testing::Eq;
50 using ::testing::HasSubstr;
51 using ::testing::Not;
52 using ::testing::SizeIs;
53
TEST(XChaCha20Poly1305KeyManagerTest,Basics)54 TEST(XChaCha20Poly1305KeyManagerTest, Basics) {
55 EXPECT_THAT(XChaCha20Poly1305KeyManager().get_version(), Eq(0));
56 EXPECT_THAT(
57 XChaCha20Poly1305KeyManager().get_key_type(),
58 Eq("type.googleapis.com/google.crypto.tink.XChaCha20Poly1305Key"));
59 EXPECT_THAT(XChaCha20Poly1305KeyManager().key_material_type(),
60 Eq(google::crypto::tink::KeyData::SYMMETRIC));
61 }
62
TEST(XChaCha20Poly1305KeyManagerTest,ValidateEmptyKey)63 TEST(XChaCha20Poly1305KeyManagerTest, ValidateEmptyKey) {
64 EXPECT_THAT(XChaCha20Poly1305KeyManager().ValidateKey(XChaCha20Poly1305Key()),
65 StatusIs(absl::StatusCode::kInvalidArgument));
66 }
67
TEST(XChaCha20Poly1305KeyManagerTest,ValidateValid32ByteKey)68 TEST(XChaCha20Poly1305KeyManagerTest, ValidateValid32ByteKey) {
69 XChaCha20Poly1305Key key;
70 key.set_version(0);
71 key.set_key_value("01234567890123456789012345678901");
72 EXPECT_THAT(XChaCha20Poly1305KeyManager().ValidateKey(key), IsOk());
73 }
74
TEST(XChaCha20Poly1305KeyManagerTest,ValidateInvalid16ByteKey)75 TEST(XChaCha20Poly1305KeyManagerTest, ValidateInvalid16ByteKey) {
76 XChaCha20Poly1305Key key;
77 key.set_version(0);
78 key.set_key_value("0123456789012345");
79 EXPECT_THAT(XChaCha20Poly1305KeyManager().ValidateKey(key), Not(IsOk()));
80 }
81
TEST(XChaCha20Poly1305KeyManagerTest,ValidateInvalid31ByteKey)82 TEST(XChaCha20Poly1305KeyManagerTest, ValidateInvalid31ByteKey) {
83 XChaCha20Poly1305Key key;
84 key.set_version(0);
85 key.set_key_value("0123456789012345678901234567890");
86 EXPECT_THAT(XChaCha20Poly1305KeyManager().ValidateKey(key), Not(IsOk()));
87 }
88
TEST(XChaCha20Poly1305KeyManagerTest,ValidateInvalid33ByteKey)89 TEST(XChaCha20Poly1305KeyManagerTest, ValidateInvalid33ByteKey) {
90 XChaCha20Poly1305Key key;
91 key.set_version(0);
92 key.set_key_value("012345678901234567890123456789012");
93 EXPECT_THAT(XChaCha20Poly1305KeyManager().ValidateKey(key), Not(IsOk()));
94 }
95
TEST(XChaCha20Poly1305KeyManagerTest,ValidateInvalidVersion)96 TEST(XChaCha20Poly1305KeyManagerTest, ValidateInvalidVersion) {
97 XChaCha20Poly1305Key key;
98 key.set_version(1);
99 key.set_key_value("01234567890123456789012345678901");
100 EXPECT_THAT(XChaCha20Poly1305KeyManager().ValidateKey(key), Not(IsOk()));
101 }
102
TEST(XChaCha20Poly1305KeyManagerTest,ValidateKeyFormat)103 TEST(XChaCha20Poly1305KeyManagerTest, ValidateKeyFormat) {
104 EXPECT_THAT(XChaCha20Poly1305KeyManager().ValidateKeyFormat(
105 XChaCha20Poly1305KeyFormat()),
106 IsOk());
107 }
108
TEST(XChaCha20Poly1305KeyManagerTest,CreateKey)109 TEST(XChaCha20Poly1305KeyManagerTest, CreateKey) {
110 StatusOr<XChaCha20Poly1305Key> key_or =
111 XChaCha20Poly1305KeyManager().CreateKey(XChaCha20Poly1305KeyFormat());
112
113 ASSERT_THAT(key_or, IsOk());
114 EXPECT_THAT(key_or.value().key_value(), SizeIs(32));
115 EXPECT_THAT(key_or.value().version(), Eq(0));
116 }
117
TEST(XChaCha20Poly1305KeyManagerTest,DeriveKey)118 TEST(XChaCha20Poly1305KeyManagerTest, DeriveKey) {
119 util::IstreamInputStream input_stream{
120 absl::make_unique<std::stringstream>("0123456789abcdef0123456789abcdef")};
121 XChaCha20Poly1305KeyFormat format;
122 format.set_version(0);
123 StatusOr<XChaCha20Poly1305Key> key_or =
124 XChaCha20Poly1305KeyManager().DeriveKey(format, &input_stream);
125
126 ASSERT_THAT(key_or, IsOk());
127 EXPECT_THAT(key_or.value().key_value(), SizeIs(32));
128 EXPECT_THAT(key_or.value().version(), Eq(0));
129 }
130
TEST(XChaCha20Poly1305KeyManagerTest,DeriveKeyFromLongSeed)131 TEST(XChaCha20Poly1305KeyManagerTest, DeriveKeyFromLongSeed) {
132 util::IstreamInputStream input_stream{absl::make_unique<std::stringstream>(
133 "0123456789abcdef0123456789abcdefXXX")};
134
135 XChaCha20Poly1305KeyFormat format;
136 format.set_version(0);
137 auto key_or = XChaCha20Poly1305KeyManager().DeriveKey(format, &input_stream);
138
139 ASSERT_THAT(key_or, IsOk());
140 EXPECT_THAT(key_or.value().key_value(),
141 Eq("0123456789abcdef0123456789abcdef"));
142 }
143
TEST(XChaCha20Poly1305KeyManagerTest,DeriveKeyWithoutEnoughEntropy)144 TEST(XChaCha20Poly1305KeyManagerTest, DeriveKeyWithoutEnoughEntropy) {
145 util::IstreamInputStream input_stream{
146 absl::make_unique<std::stringstream>("0")};
147 XChaCha20Poly1305KeyFormat format;
148 format.set_version(0);
149
150 StatusOr<XChaCha20Poly1305Key> key_or =
151 XChaCha20Poly1305KeyManager().DeriveKey(format, &input_stream);
152
153 ASSERT_THAT(key_or.status(), StatusIs(absl::StatusCode::kInvalidArgument,
154 HasSubstr("pseudorandomness")));
155 }
156
TEST(XChaCha20Poly1305KeyManagerTest,DeriveKeyWrongVersion)157 TEST(XChaCha20Poly1305KeyManagerTest, DeriveKeyWrongVersion) {
158 util::IstreamInputStream input_stream{
159 absl::make_unique<std::stringstream>("0123456789abcdef0123456789abcdef")};
160 XChaCha20Poly1305KeyFormat format;
161 format.set_version(1);
162 StatusOr<XChaCha20Poly1305Key> key_or =
163 XChaCha20Poly1305KeyManager().DeriveKey(format, &input_stream);
164
165 ASSERT_THAT(key_or.status(), StatusIs(absl::StatusCode::kInvalidArgument,
166 HasSubstr("version")));
167 }
168
TEST(XChaCha20Poly1305KeyManagerTest,CreateKeyValid)169 TEST(XChaCha20Poly1305KeyManagerTest, CreateKeyValid) {
170 StatusOr<XChaCha20Poly1305Key> key_or =
171 XChaCha20Poly1305KeyManager().CreateKey(XChaCha20Poly1305KeyFormat());
172
173 ASSERT_THAT(key_or, IsOk());
174 EXPECT_THAT(XChaCha20Poly1305KeyManager().ValidateKey(key_or.value()),
175 IsOk());
176 }
177
TEST(XChaCha20Poly1305KeyManagerTest,CreateAeadFailsWithOpenSsl)178 TEST(XChaCha20Poly1305KeyManagerTest, CreateAeadFailsWithOpenSsl) {
179 if (internal::IsBoringSsl()) {
180 GTEST_SKIP() << "OpenSSL-only test, skipping because Tink uses BoringSSL";
181 }
182 StatusOr<XChaCha20Poly1305Key> key =
183 XChaCha20Poly1305KeyManager().CreateKey(XChaCha20Poly1305KeyFormat());
184 ASSERT_THAT(key, IsOk());
185 EXPECT_THAT(XChaCha20Poly1305KeyManager().GetPrimitive<Aead>(*key).status(),
186 Not(IsOk()));
187 EXPECT_THAT(subtle::XChacha20Poly1305BoringSsl::New(
188 util::SecretDataFromStringView(key->key_value()))
189 .status(),
190 Not(IsOk()));
191 }
192
TEST(XChaCha20Poly1305KeyManagerTest,CreateAeadSucceedsWithBoringSsl)193 TEST(XChaCha20Poly1305KeyManagerTest, CreateAeadSucceedsWithBoringSsl) {
194 if (!internal::IsBoringSsl()) {
195 GTEST_SKIP() << "XChaCha20-Poly1305 is not supported when OpenSSL is used";
196 }
197 StatusOr<XChaCha20Poly1305Key> key =
198 XChaCha20Poly1305KeyManager().CreateKey(XChaCha20Poly1305KeyFormat());
199 ASSERT_THAT(key, IsOk());
200
201 StatusOr<std::unique_ptr<Aead>> aead =
202 XChaCha20Poly1305KeyManager().GetPrimitive<Aead>(*key);
203 ASSERT_THAT(aead, IsOk());
204
205 StatusOr<std::unique_ptr<Aead>> direct_aead =
206 subtle::XChacha20Poly1305BoringSsl::New(
207 util::SecretDataFromStringView(key->key_value()));
208 ASSERT_THAT(direct_aead, IsOk());
209 EXPECT_THAT(EncryptThenDecrypt(**aead, **direct_aead, "message", "aad"),
210 IsOk());
211 }
212
213 } // namespace
214 } // namespace tink
215 } // namespace crypto
216