xref: /aosp_15_r20/external/tink/cc/util/test_util.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
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