1 // Copyright 2017 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/util/test_util.h"
18
19 #include <stdarg.h>
20 #include <stdlib.h>
21
22 #include <cmath>
23 #include <cstdint>
24 #include <cstdlib>
25 #include <fstream>
26 #include <ios>
27 #include <iostream>
28 #include <memory>
29 #include <ostream>
30 #include <sstream>
31 #include <string>
32 #include <vector>
33
34 #include "absl/memory/memory.h"
35 #include "absl/status/status.h"
36 #include "absl/strings/str_cat.h"
37 #include "absl/strings/str_join.h"
38 #include "tink/aead/aes_ctr_hmac_aead_key_manager.h"
39 #include "tink/aead/aes_gcm_key_manager.h"
40 #include "tink/aead/xchacha20_poly1305_key_manager.h"
41 #include "tink/cleartext_keyset_handle.h"
42 #include "tink/daead/aes_siv_key_manager.h"
43 #include "tink/internal/ec_util.h"
44 #include "tink/keyset_handle.h"
45 #include "tink/subtle/common_enums.h"
46 #include "tink/subtle/random.h"
47 #include "tink/util/enums.h"
48 #include "tink/util/protobuf_helper.h"
49 #include "tink/util/secret_data.h"
50 #include "tink/util/status.h"
51 #include "tink/util/statusor.h"
52 #include "proto/aes_ctr.pb.h"
53 #include "proto/aes_ctr_hmac_aead.pb.h"
54 #include "proto/aes_siv.pb.h"
55 #include "proto/common.pb.h"
56 #include "proto/ecdsa.pb.h"
57 #include "proto/ecies_aead_hkdf.pb.h"
58 #include "proto/ed25519.pb.h"
59 #include "proto/hmac.pb.h"
60 #include "proto/tink.pb.h"
61 #include "proto/xchacha20_poly1305.pb.h"
62
63 using crypto::tink::util::Enums;
64 using crypto::tink::util::Status;
65 using google::crypto::tink::AesGcmKeyFormat;
66 using google::crypto::tink::EcdsaPrivateKey;
67 using google::crypto::tink::EciesAeadHkdfPrivateKey;
68 using google::crypto::tink::Ed25519PrivateKey;
69 using google::crypto::tink::Keyset;
70 using google::crypto::tink::OutputPrefixType;
71
72 namespace crypto {
73 namespace tink {
74 namespace test {
75
ReadTestFile(absl::string_view filename)76 std::string ReadTestFile(absl::string_view filename) {
77 std::string full_filename = absl::StrCat(test::TmpDir(), "/", filename);
78 std::ifstream input_stream(full_filename, std::ios::binary);
79 if (!input_stream) {
80 std::clog << "Cannot open file " << full_filename << std::endl;
81 exit(1);
82 }
83 std::stringstream buffer;
84 buffer << input_stream.rdbuf();
85 return buffer.str();
86 }
87
HexDecode(absl::string_view hex)88 util::StatusOr<std::string> HexDecode(absl::string_view hex) {
89 if (hex.size() % 2 != 0) {
90 return util::Status(absl::StatusCode::kInvalidArgument,
91 "Input has odd size.");
92 }
93 std::string decoded(hex.size() / 2, static_cast<char>(0));
94 for (size_t i = 0; i < hex.size(); ++i) {
95 char c = hex[i];
96 char val;
97 if ('0' <= c && c <= '9')
98 val = c - '0';
99 else if ('a' <= c && c <= 'f')
100 val = c - 'a' + 10;
101 else if ('A' <= c && c <= 'F')
102 val = c - 'A' + 10;
103 else
104 return util::Status(absl::StatusCode::kInvalidArgument,
105 "Not hexadecimal");
106 decoded[i / 2] = (decoded[i / 2] << 4) | val;
107 }
108 return decoded;
109 }
110
HexDecodeOrDie(absl::string_view hex)111 std::string HexDecodeOrDie(absl::string_view hex) {
112 return HexDecode(hex).value();
113 }
114
HexEncode(absl::string_view bytes)115 std::string HexEncode(absl::string_view bytes) {
116 std::string hexchars = "0123456789abcdef";
117 std::string res(bytes.size() * 2, static_cast<char>(255));
118 for (size_t i = 0; i < bytes.size(); ++i) {
119 uint8_t c = static_cast<uint8_t>(bytes[i]);
120 res[2 * i] = hexchars[c / 16];
121 res[2 * i + 1] = hexchars[c % 16];
122 }
123 return res;
124 }
125
TmpDir()126 std::string TmpDir() {
127 // Try the following environment variables in order:
128 // - TEST_TMPDIR: Set by `bazel test`.
129 // - TMPDIR: Set by some Tink tests.
130 // - TEMP, TMP: Set on Windows; they contain the tmp dir's path.
131 for (const std::string& tmp_env_variable :
132 {"TEST_TMPDIR", "TMPDIR", "TEMP", "TMP"}) {
133 const char* env = getenv(tmp_env_variable.c_str());
134 if (env && env[0] != '\0') {
135 return env;
136 }
137 }
138 // Tmp dir on Linux/macOS.
139 return "/tmp";
140 }
141
AddKeyData(const google::crypto::tink::KeyData & key_data,uint32_t key_id,google::crypto::tink::OutputPrefixType output_prefix,google::crypto::tink::KeyStatusType key_status,google::crypto::tink::Keyset * keyset)142 void AddKeyData(const google::crypto::tink::KeyData& key_data, uint32_t key_id,
143 google::crypto::tink::OutputPrefixType output_prefix,
144 google::crypto::tink::KeyStatusType key_status,
145 google::crypto::tink::Keyset* keyset) {
146 Keyset::Key* key = keyset->add_key();
147 key->set_output_prefix_type(output_prefix);
148 key->set_key_id(key_id);
149 key->set_status(key_status);
150 *key->mutable_key_data() = key_data;
151 }
152
AddKey(const std::string & key_type,uint32_t key_id,const portable_proto::MessageLite & new_key,google::crypto::tink::OutputPrefixType output_prefix,google::crypto::tink::KeyStatusType key_status,google::crypto::tink::KeyData::KeyMaterialType material_type,google::crypto::tink::Keyset * keyset)153 void AddKey(const std::string& key_type, uint32_t key_id,
154 const portable_proto::MessageLite& new_key,
155 google::crypto::tink::OutputPrefixType output_prefix,
156 google::crypto::tink::KeyStatusType key_status,
157 google::crypto::tink::KeyData::KeyMaterialType material_type,
158 google::crypto::tink::Keyset* keyset) {
159 google::crypto::tink::KeyData key_data;
160 key_data.set_type_url(key_type);
161 key_data.set_key_material_type(material_type);
162 key_data.set_value(new_key.SerializeAsString());
163 AddKeyData(key_data, key_id, output_prefix, key_status, keyset);
164 }
165
AddTinkKey(const std::string & key_type,uint32_t key_id,const portable_proto::MessageLite & key,google::crypto::tink::KeyStatusType key_status,google::crypto::tink::KeyData::KeyMaterialType material_type,google::crypto::tink::Keyset * keyset)166 void AddTinkKey(const std::string& key_type, uint32_t key_id,
167 const portable_proto::MessageLite& key,
168 google::crypto::tink::KeyStatusType key_status,
169 google::crypto::tink::KeyData::KeyMaterialType material_type,
170 google::crypto::tink::Keyset* keyset) {
171 AddKey(key_type, key_id, key, OutputPrefixType::TINK,
172 key_status, material_type, keyset);
173 }
174
AddLegacyKey(const std::string & key_type,uint32_t key_id,const portable_proto::MessageLite & key,google::crypto::tink::KeyStatusType key_status,google::crypto::tink::KeyData::KeyMaterialType material_type,google::crypto::tink::Keyset * keyset)175 void AddLegacyKey(const std::string& key_type, uint32_t key_id,
176 const portable_proto::MessageLite& key,
177 google::crypto::tink::KeyStatusType key_status,
178 google::crypto::tink::KeyData::KeyMaterialType material_type,
179 google::crypto::tink::Keyset* keyset) {
180 AddKey(key_type, key_id, key, OutputPrefixType::LEGACY,
181 key_status, material_type, keyset);
182 }
183
AddRawKey(const std::string & key_type,uint32_t key_id,const portable_proto::MessageLite & key,google::crypto::tink::KeyStatusType key_status,google::crypto::tink::KeyData::KeyMaterialType material_type,google::crypto::tink::Keyset * keyset)184 void AddRawKey(const std::string& key_type, uint32_t key_id,
185 const portable_proto::MessageLite& key,
186 google::crypto::tink::KeyStatusType key_status,
187 google::crypto::tink::KeyData::KeyMaterialType material_type,
188 google::crypto::tink::Keyset* keyset) {
189 AddKey(key_type, key_id, key, OutputPrefixType::RAW,
190 key_status, material_type, keyset);
191 }
192
GetEciesAesGcmHkdfTestKey(subtle::EllipticCurveType curve_type,subtle::EcPointFormat ec_point_format,subtle::HashType hash_type,uint32_t aes_gcm_key_size)193 EciesAeadHkdfPrivateKey GetEciesAesGcmHkdfTestKey(
194 subtle::EllipticCurveType curve_type,
195 subtle::EcPointFormat ec_point_format,
196 subtle::HashType hash_type,
197 uint32_t aes_gcm_key_size) {
198 return GetEciesAesGcmHkdfTestKey(
199 Enums::SubtleToProto(curve_type),
200 Enums::SubtleToProto(ec_point_format),
201 Enums::SubtleToProto(hash_type),
202 aes_gcm_key_size);
203 }
204
GetEciesAeadHkdfTestKey(google::crypto::tink::EllipticCurveType curve_type,google::crypto::tink::EcPointFormat ec_point_format,google::crypto::tink::HashType hash_type)205 EciesAeadHkdfPrivateKey GetEciesAeadHkdfTestKey(
206 google::crypto::tink::EllipticCurveType curve_type,
207 google::crypto::tink::EcPointFormat ec_point_format,
208 google::crypto::tink::HashType hash_type) {
209 auto test_key = internal::NewEcKey(Enums::ProtoToSubtle(curve_type)).value();
210 EciesAeadHkdfPrivateKey ecies_key;
211 ecies_key.set_version(0);
212 ecies_key.set_key_value(
213 std::string(util::SecretDataAsStringView(test_key.priv)));
214 auto public_key = ecies_key.mutable_public_key();
215 public_key->set_version(0);
216 public_key->set_x(test_key.pub_x);
217 public_key->set_y(test_key.pub_y);
218 auto params = public_key->mutable_params();
219 params->set_ec_point_format(ec_point_format);
220 params->mutable_kem_params()->set_curve_type(curve_type);
221 params->mutable_kem_params()->set_hkdf_hash_type(hash_type);
222
223 return ecies_key;
224 }
225
GetEciesAesGcmHkdfTestKey(google::crypto::tink::EllipticCurveType curve_type,google::crypto::tink::EcPointFormat ec_point_format,google::crypto::tink::HashType hash_type,uint32_t aes_gcm_key_size)226 EciesAeadHkdfPrivateKey GetEciesAesGcmHkdfTestKey(
227 google::crypto::tink::EllipticCurveType curve_type,
228 google::crypto::tink::EcPointFormat ec_point_format,
229 google::crypto::tink::HashType hash_type, uint32_t aes_gcm_key_size) {
230 auto ecies_key =
231 GetEciesAeadHkdfTestKey(curve_type, ec_point_format, hash_type);
232 auto params = ecies_key.mutable_public_key()->mutable_params();
233
234 AesGcmKeyFormat key_format;
235 key_format.set_key_size(aes_gcm_key_size);
236 auto aead_dem = params->mutable_dem_params()->mutable_aead_dem();
237 std::unique_ptr<AesGcmKeyManager> key_manager(new AesGcmKeyManager());
238 std::string dem_key_type = key_manager->get_key_type();
239 aead_dem->set_type_url(dem_key_type);
240 aead_dem->set_value(key_format.SerializeAsString());
241 return ecies_key;
242 }
243
GetEciesAesCtrHmacHkdfTestKey(google::crypto::tink::EllipticCurveType curve_type,google::crypto::tink::EcPointFormat ec_point_format,google::crypto::tink::HashType hash_type,uint32_t aes_ctr_key_size,uint32_t aes_ctr_iv_size,google::crypto::tink::HashType hmac_hash_type,uint32_t hmac_tag_size,uint32_t hmac_key_size)244 EciesAeadHkdfPrivateKey GetEciesAesCtrHmacHkdfTestKey(
245 google::crypto::tink::EllipticCurveType curve_type,
246 google::crypto::tink::EcPointFormat ec_point_format,
247 google::crypto::tink::HashType hash_type, uint32_t aes_ctr_key_size,
248 uint32_t aes_ctr_iv_size, google::crypto::tink::HashType hmac_hash_type,
249 uint32_t hmac_tag_size, uint32_t hmac_key_size) {
250 auto ecies_key =
251 GetEciesAeadHkdfTestKey(curve_type, ec_point_format, hash_type);
252
253 google::crypto::tink::AesCtrHmacAeadKeyFormat key_format;
254 auto aes_ctr_key_format = key_format.mutable_aes_ctr_key_format();
255 auto aes_ctr_params = aes_ctr_key_format->mutable_params();
256 aes_ctr_params->set_iv_size(aes_ctr_iv_size);
257 aes_ctr_key_format->set_key_size(aes_ctr_key_size);
258
259 auto hmac_key_format = key_format.mutable_hmac_key_format();
260 auto hmac_params = hmac_key_format->mutable_params();
261 hmac_params->set_hash(hmac_hash_type);
262 hmac_params->set_tag_size(hmac_tag_size);
263 hmac_key_format->set_key_size(hmac_key_size);
264
265 auto params = ecies_key.mutable_public_key()->mutable_params();
266 auto aead_dem = params->mutable_dem_params()->mutable_aead_dem();
267
268 std::unique_ptr<AesCtrHmacAeadKeyManager> key_manager(
269 new AesCtrHmacAeadKeyManager());
270 std::string dem_key_type = key_manager->get_key_type();
271 aead_dem->set_type_url(dem_key_type);
272 aead_dem->set_value(key_format.SerializeAsString());
273 return ecies_key;
274 }
275
GetEciesXChaCha20Poly1305HkdfTestKey(google::crypto::tink::EllipticCurveType curve_type,google::crypto::tink::EcPointFormat ec_point_format,google::crypto::tink::HashType hash_type)276 EciesAeadHkdfPrivateKey GetEciesXChaCha20Poly1305HkdfTestKey(
277 google::crypto::tink::EllipticCurveType curve_type,
278 google::crypto::tink::EcPointFormat ec_point_format,
279 google::crypto::tink::HashType hash_type) {
280 auto ecies_key =
281 GetEciesAeadHkdfTestKey(curve_type, ec_point_format, hash_type);
282 auto params = ecies_key.mutable_public_key()->mutable_params();
283
284 google::crypto::tink::XChaCha20Poly1305KeyFormat key_format;
285 auto aead_dem = params->mutable_dem_params()->mutable_aead_dem();
286 std::unique_ptr<XChaCha20Poly1305KeyManager> key_manager(
287 new XChaCha20Poly1305KeyManager());
288 std::string dem_key_type = key_manager->get_key_type();
289 aead_dem->set_type_url(dem_key_type);
290 aead_dem->set_value(key_format.SerializeAsString());
291 return ecies_key;
292 }
293
GetEciesAesSivHkdfTestKey(google::crypto::tink::EllipticCurveType curve_type,google::crypto::tink::EcPointFormat ec_point_format,google::crypto::tink::HashType hash_type)294 google::crypto::tink::EciesAeadHkdfPrivateKey GetEciesAesSivHkdfTestKey(
295 google::crypto::tink::EllipticCurveType curve_type,
296 google::crypto::tink::EcPointFormat ec_point_format,
297 google::crypto::tink::HashType hash_type) {
298 auto ecies_key =
299 GetEciesAeadHkdfTestKey(curve_type, ec_point_format, hash_type);
300 auto params = ecies_key.mutable_public_key()->mutable_params();
301
302 google::crypto::tink::AesSivKeyFormat key_format;
303 key_format.set_key_size(64);
304 auto aead_dem = params->mutable_dem_params()->mutable_aead_dem();
305 AesSivKeyManager key_manager;
306 std::string dem_key_type = key_manager.get_key_type();
307 aead_dem->set_type_url(dem_key_type);
308 aead_dem->set_value(key_format.SerializeAsString());
309 return ecies_key;
310 }
311
GetEcdsaTestPrivateKey(subtle::EllipticCurveType curve_type,subtle::HashType hash_type,subtle::EcdsaSignatureEncoding encoding)312 EcdsaPrivateKey GetEcdsaTestPrivateKey(
313 subtle::EllipticCurveType curve_type, subtle::HashType hash_type,
314 subtle::EcdsaSignatureEncoding encoding) {
315 return GetEcdsaTestPrivateKey(Enums::SubtleToProto(curve_type),
316 Enums::SubtleToProto(hash_type),
317 Enums::SubtleToProto(encoding));
318 }
319
GetEcdsaTestPrivateKey(google::crypto::tink::EllipticCurveType curve_type,google::crypto::tink::HashType hash_type,google::crypto::tink::EcdsaSignatureEncoding encoding)320 EcdsaPrivateKey GetEcdsaTestPrivateKey(
321 google::crypto::tink::EllipticCurveType curve_type,
322 google::crypto::tink::HashType hash_type,
323 google::crypto::tink::EcdsaSignatureEncoding encoding) {
324 auto test_key = internal::NewEcKey(Enums::ProtoToSubtle(curve_type)).value();
325 EcdsaPrivateKey ecdsa_key;
326 ecdsa_key.set_version(0);
327 ecdsa_key.set_key_value(
328 std::string(util::SecretDataAsStringView(test_key.priv)));
329 auto public_key = ecdsa_key.mutable_public_key();
330 public_key->set_version(0);
331 public_key->set_x(test_key.pub_x);
332 public_key->set_y(test_key.pub_y);
333 auto params = public_key->mutable_params();
334 params->set_hash_type(hash_type);
335 params->set_curve(curve_type);
336 params->set_encoding(encoding);
337 return ecdsa_key;
338 }
339
GetEd25519TestPrivateKey()340 Ed25519PrivateKey GetEd25519TestPrivateKey() {
341 auto test_key = internal::NewEd25519Key().value();
342 Ed25519PrivateKey ed25519_key;
343 ed25519_key.set_version(0);
344 ed25519_key.set_key_value(test_key->private_key);
345
346 auto public_key = ed25519_key.mutable_public_key();
347 public_key->set_version(0);
348 public_key->set_key_value(test_key->public_key);
349
350 return ed25519_key;
351 }
352
ZTestUniformString(absl::string_view bytes)353 util::Status ZTestUniformString(absl::string_view bytes) {
354 double expected = bytes.size() * 8.0 / 2.0;
355 double stddev = std::sqrt(static_cast<double>(bytes.size()) * 8.0 / 4.0);
356 uint64_t num_set_bits = 0;
357 for (uint8_t byte : bytes) {
358 // Counting the number of bits set in byte:
359 while (byte != 0) {
360 num_set_bits++;
361 byte = byte & (byte - 1);
362 }
363 }
364 // Check that the number of bits is within 10 stddevs.
365 if (abs(static_cast<double>(num_set_bits) - expected) < 10.0 * stddev) {
366 return util::OkStatus();
367 }
368 return util::Status(
369 absl::StatusCode::kInternal,
370 absl::StrCat("Z test for uniformly distributed variable out of bounds; "
371 "Actual number of set bits was ",
372 num_set_bits, " expected was ", expected,
373 " 10 * standard deviation is 10 * ", stddev, " = ",
374 10.0 * stddev));
375 }
376
Rotate(absl::string_view bytes)377 std::string Rotate(absl::string_view bytes) {
378 std::string result(bytes.size(), '\0');
379 for (int i = 0; i < bytes.size(); i++) {
380 result[i] = (static_cast<uint8_t>(bytes[i]) >> 1) |
381 (bytes[(i == 0 ? bytes.size() : i) - 1] << 7);
382 }
383 return result;
384 }
385
ZTestCrosscorrelationUniformStrings(absl::string_view bytes1,absl::string_view bytes2)386 util::Status ZTestCrosscorrelationUniformStrings(absl::string_view bytes1,
387 absl::string_view bytes2) {
388 if (bytes1.size() != bytes2.size()) {
389 return util::Status(absl::StatusCode::kInvalidArgument,
390 "Strings are not of equal length");
391 }
392 std::string crossed(bytes1.size(), '\0');
393 for (int i = 0; i < bytes1.size(); i++) {
394 crossed[i] = bytes1[i] ^ bytes2[i];
395 }
396 return ZTestUniformString(crossed);
397 }
398
ZTestAutocorrelationUniformString(absl::string_view bytes)399 util::Status ZTestAutocorrelationUniformString(absl::string_view bytes) {
400 std::string rotated(bytes);
401 std::vector<int> violations;
402 for (int i = 1; i < bytes.size() * 8; i++) {
403 rotated = Rotate(rotated);
404 auto status = ZTestCrosscorrelationUniformStrings(bytes, rotated);
405 if (!status.ok()) {
406 violations.push_back(i);
407 }
408 }
409 if (violations.empty()) {
410 return util::OkStatus();
411 }
412 return util::Status(
413 absl::StatusCode::kInternal,
414 absl::StrCat("Autocorrelation exceeded 10 standard deviation at ",
415 violations.size(),
416 " indices: ", absl::StrJoin(violations, ", ")));
417 }
418
419 } // namespace test
420 } // namespace tink
421 } // namespace crypto
422