xref: /aosp_15_r20/external/tink/cc/util/test_util.h (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 #ifndef TINK_UTIL_TEST_UTIL_H_
18 #define TINK_UTIL_TEST_UTIL_H_
19 
20 #include <limits>
21 #include <memory>
22 #include <ostream>
23 #include <string>
24 #include <utility>
25 
26 #include "absl/base/thread_annotations.h"
27 #include "absl/status/status.h"
28 #include "absl/strings/cord.h"
29 #include "absl/strings/match.h"
30 #include "absl/strings/str_cat.h"
31 #include "absl/strings/string_view.h"
32 #include "absl/synchronization/mutex.h"
33 #include "tink/aead.h"
34 #include "tink/aead/cord_aead.h"
35 #include "tink/deterministic_aead.h"
36 #include "tink/hybrid_decrypt.h"
37 #include "tink/hybrid_encrypt.h"
38 #include "tink/input_stream.h"
39 #include "tink/keyset_handle.h"
40 #include "tink/kms_client.h"
41 #include "tink/mac.h"
42 #include "tink/output_stream.h"
43 #include "tink/public_key_sign.h"
44 #include "tink/public_key_verify.h"
45 #include "tink/random_access_stream.h"
46 #include "tink/streaming_aead.h"
47 #include "tink/subtle/common_enums.h"
48 #include "tink/subtle/mac/stateful_mac.h"
49 #include "tink/util/buffer.h"
50 #include "tink/util/constants.h"
51 #include "tink/util/protobuf_helper.h"
52 #include "tink/util/status.h"
53 #include "tink/util/statusor.h"
54 #include "proto/common.pb.h"
55 #include "proto/ecdsa.pb.h"
56 #include "proto/ecies_aead_hkdf.pb.h"
57 #include "proto/ed25519.pb.h"
58 #include "proto/tink.pb.h"
59 
60 namespace crypto {
61 namespace tink {
62 namespace test {
63 
64 // Various utilities for testing.
65 ///////////////////////////////////////////////////////////////////////////////
66 
67 // Reads the test file specified by `filename`, and returns its contents.
68 std::string ReadTestFile(absl::string_view filename);
69 
70 // Converts a hexadecimal string into a string of bytes.
71 // Returns a status if the size of the input is odd or if the input contains
72 // characters that are not hexadecimal.
73 crypto::tink::util::StatusOr<std::string> HexDecode(absl::string_view hex);
74 
75 // Converts a hexadecimal string into a string of bytes.
76 // Dies if the input is not a valid hexadecimal string.
77 std::string HexDecodeOrDie(absl::string_view hex);
78 
79 // Converts a string of bytes into a hexadecimal string.
80 std::string HexEncode(absl::string_view bytes);
81 
82 // Returns a temporary directory suitable for temporary testing files.
83 std::string TmpDir();
84 
85 // Adds the given 'keyData' with specified status, key_id, and
86 // output_prefix_type to the keyset.
87 void AddKeyData(const google::crypto::tink::KeyData& key_data, uint32_t key_id,
88                 google::crypto::tink::OutputPrefixType output_prefix,
89                 google::crypto::tink::KeyStatusType key_status,
90                 google::crypto::tink::Keyset* keyset);
91 
92 // Adds the given 'key' with specified parameters and output_prefix_type=TINK
93 // to the specified 'keyset'.
94 void AddTinkKey(const std::string& key_type, uint32_t key_id,
95                 const portable_proto::MessageLite& key,
96                 google::crypto::tink::KeyStatusType key_status,
97                 google::crypto::tink::KeyData::KeyMaterialType material_type,
98                 google::crypto::tink::Keyset* keyset);
99 
100 // Adds the given 'key' with specified parameters and output_prefix_type=LEGACY
101 // to the specified 'keyset'.
102 void AddLegacyKey(const std::string& key_type, uint32_t key_id,
103                   const portable_proto::MessageLite& key,
104                   google::crypto::tink::KeyStatusType key_status,
105                   google::crypto::tink::KeyData::KeyMaterialType material_type,
106                   google::crypto::tink::Keyset* keyset);
107 
108 // Adds the given 'key' with specified parameters and output_prefix_type=RAW
109 // to the specified 'keyset'.
110 void AddRawKey(const std::string& key_type, uint32_t key_id,
111                const portable_proto::MessageLite& key,
112                google::crypto::tink::KeyStatusType key_status,
113                google::crypto::tink::KeyData::KeyMaterialType material_type,
114                google::crypto::tink::Keyset* keyset);
115 
116 // Generates a fresh test key for ECIES-AEAD-HKDF for the given curve,
117 // using AesGcm with the specified key size as AEAD, and HKDF with 'hash_type'.
118 google::crypto::tink::EciesAeadHkdfPrivateKey GetEciesAesGcmHkdfTestKey(
119     subtle::EllipticCurveType curve_type, subtle::EcPointFormat ec_point_format,
120     subtle::HashType hash_type, uint32_t aes_gcm_key_size);
121 
122 // Generates a fresh test key for ECIES-AEAD-HKDF for the given curve,
123 // using AesGcm with the specified key size as AEAD, and HKDF with 'hash_type'.
124 google::crypto::tink::EciesAeadHkdfPrivateKey GetEciesAesGcmHkdfTestKey(
125     google::crypto::tink::EllipticCurveType curve_type,
126     google::crypto::tink::EcPointFormat ec_point_format,
127     google::crypto::tink::HashType hash_type, uint32_t aes_gcm_key_size);
128 
129 // Generates a fresh test key for ECIES-AEAD-HKDF for the given curve,
130 // using XChaCha20Poly1305 as AEAD, and HKDF with 'hash_type'.
131 google::crypto::tink::EciesAeadHkdfPrivateKey
132 GetEciesXChaCha20Poly1305HkdfTestKey(
133     google::crypto::tink::EllipticCurveType curve_type,
134     google::crypto::tink::EcPointFormat ec_point_format,
135     google::crypto::tink::HashType hash_type);
136 
137 // Generates a fresh test key for ECIES-AEAD-HKDF for the given curve,
138 // using AesCtrHmac with the specified AEAD params, and HKDF with 'hash_type'.
139 google::crypto::tink::EciesAeadHkdfPrivateKey GetEciesAesCtrHmacHkdfTestKey(
140     google::crypto::tink::EllipticCurveType curve_type,
141     google::crypto::tink::EcPointFormat ec_point_format,
142     google::crypto::tink::HashType hash_type, uint32_t aes_ctr_key_size,
143     uint32_t aes_ctr_iv_size, google::crypto::tink::HashType hmac_hash_type,
144     uint32_t hmac_tag_size, uint32_t hmac_key_size);
145 
146 // Generates a fresh test key for ECIES-AEAD-HKDF for the given curve,
147 // using AesSiv as the determinisitic AEAD, and HKDF with 'hash_type'.
148 google::crypto::tink::EciesAeadHkdfPrivateKey GetEciesAesSivHkdfTestKey(
149     google::crypto::tink::EllipticCurveType curve_type,
150     google::crypto::tink::EcPointFormat ec_point_format,
151     google::crypto::tink::HashType hash_type);
152 
153 // Generates a fresh test key for EC DSA for the given 'curve_type', 'hash_type'
154 // and 'encoding'.
155 google::crypto::tink::EcdsaPrivateKey GetEcdsaTestPrivateKey(
156     subtle::EllipticCurveType curve_type, subtle::HashType hash_type,
157     subtle::EcdsaSignatureEncoding encoding);
158 
159 // Generates a fresh test key for EC DSA for the given 'curve_type', 'hash_type'
160 // and 'encoding'.
161 google::crypto::tink::EcdsaPrivateKey GetEcdsaTestPrivateKey(
162     google::crypto::tink::EllipticCurveType curve_type,
163     google::crypto::tink::HashType hash_type,
164     google::crypto::tink::EcdsaSignatureEncoding encoding);
165 
166 // TODO(ambrosin): Remove because it is unused.
167 // Generates a fresh test key for ED25519.
168 google::crypto::tink::Ed25519PrivateKey GetEd25519TestPrivateKey();
169 
170 // Embeds the given Proto into a KeyData proto.
171 template <typename Proto>
AsKeyData(const Proto & proto,google::crypto::tink::KeyData::KeyMaterialType key_material_type)172 google::crypto::tink::KeyData AsKeyData(
173     const Proto& proto,
174     google::crypto::tink::KeyData::KeyMaterialType key_material_type) {
175   google::crypto::tink::KeyData result;
176   result.set_value(proto.SerializeAsString());
177   result.set_type_url(absl::StrCat(kTypeGoogleapisCom, proto.GetTypeName()));
178   result.set_key_material_type(key_material_type);
179   return result;
180 }
181 
182 // Uses a z test on the given byte string, expecting all bits to be uniformly
183 // set with probability 1/2. Returns non ok status if the z test fails by more
184 // than 10 standard deviations.
185 //
186 // With less statistics jargon: This counts the number of bits set and expects
187 // the number to be roughly half of the length of the string. The law of large
188 // numbers suggests that we can assume that the longer the string is, the more
189 // accurate that estimate becomes for a random string. This test is useful to
190 // detect things like strings that are entirely zero.
191 //
192 // Note: By itself, this is a very weak test for randomness.
193 util::Status ZTestUniformString(absl::string_view bytes);
194 // Tests that the crosscorrelation of two strings of equal length points to
195 // independent and uniformly distributed strings. Returns non ok status if the z
196 // test fails by more than 10 standard deviations.
197 //
198 // With less statistics jargon: This xors two strings and then performs the
199 // ZTestUniformString on the result. If the two strings are independent and
200 // uniformly distributed, the xor'ed string is as well. A cross correlation test
201 // will find whether two strings overlap more or less than it would be expected.
202 //
203 // Note: Having a correlation of zero is only a necessary but not sufficient
204 // condition for independence.
205 util::Status ZTestCrosscorrelationUniformStrings(absl::string_view bytes1,
206                                                  absl::string_view bytes2);
207 // Tests that the autocorrelation of a string points to the bits being
208 // independent and uniformly distributed. Rotates the string in a cyclic
209 // fashion. Returns non ok status if the z test fails by more than 10 standard
210 // deviations.
211 //
212 // With less statistics jargon: This rotates the string bit by bit and performs
213 // ZTestCrosscorrelationUniformStrings on each of the rotated strings and the
214 // original. This will find self similarity of the input string, especially
215 // periodic self similarity. For example, it is a decent test to find English
216 // text (needs about 180 characters with the current settings).
217 //
218 // Note: Having a correlation of zero is only a necessary but not sufficient
219 // condition for independence.
220 util::Status ZTestAutocorrelationUniformString(absl::string_view bytes);
221 
222 // A dummy implementation of Aead-interface.
223 // An instance of DummyAead can be identified by a name specified
224 // as a parameter of the constructor.
225 class DummyAead : public Aead {
226  public:
DummyAead(absl::string_view aead_name)227   explicit DummyAead(absl::string_view aead_name) : aead_name_(aead_name) {}
228 
229   // Computes a dummy ciphertext, which is concatenation of provided 'plaintext'
230   // with the name of this DummyAead.
Encrypt(absl::string_view plaintext,absl::string_view associated_data)231   crypto::tink::util::StatusOr<std::string> Encrypt(
232       absl::string_view plaintext,
233       absl::string_view associated_data) const override {
234     return absl::StrCat(aead_name_.size(), ":", associated_data.size(), ":",
235                         aead_name_, associated_data, plaintext);
236   }
237 
Decrypt(absl::string_view ciphertext,absl::string_view associated_data)238   crypto::tink::util::StatusOr<std::string> Decrypt(
239       absl::string_view ciphertext,
240       absl::string_view associated_data) const override {
241     std::string prefix =
242         absl::StrCat(aead_name_.size(), ":", associated_data.size(), ":",
243                      aead_name_, associated_data);
244     if (!absl::StartsWith(ciphertext, prefix)) {
245       return crypto::tink::util::Status(absl::StatusCode::kInvalidArgument,
246                                         "Dummy operation failed.");
247     }
248     ciphertext.remove_prefix(prefix.size());
249     return std::string(ciphertext);
250   }
251 
252  private:
253   std::string aead_name_;
254 };
255 
256 // A dummy implementation of CordAead-interface.
257 // An instance of DummyCordAead can be identified by a name specified
258 // as a parameter of the constructor.
259 class DummyCordAead : public CordAead {
260  public:
DummyCordAead(absl::string_view aead_name)261   explicit DummyCordAead(absl::string_view aead_name) : aead_(aead_name) {}
262 
263   // Computes a dummy ciphertext, which is concatenation of provided 'plaintext'
264   // with the name of this DummyCordAead.
Encrypt(absl::Cord plaintext,absl::Cord associated_data)265   crypto::tink::util::StatusOr<absl::Cord> Encrypt(
266       absl::Cord plaintext, absl::Cord associated_data) const override {
267     auto ciphertext =
268         aead_.Encrypt(plaintext.Flatten(), associated_data.Flatten());
269 
270     if (!ciphertext.ok()) return ciphertext.status();
271 
272     absl::Cord ciphertext_cord;
273     ciphertext_cord.Append(ciphertext.value());
274     return ciphertext_cord;
275   }
276 
Decrypt(absl::Cord ciphertext,absl::Cord associated_data)277   crypto::tink::util::StatusOr<absl::Cord> Decrypt(
278       absl::Cord ciphertext, absl::Cord associated_data) const override {
279     auto plaintext =
280         aead_.Decrypt(ciphertext.Flatten(), associated_data.Flatten());
281 
282     if (!plaintext.ok()) return plaintext.status();
283 
284     absl::Cord plaintext_cord;
285     plaintext_cord.Append(plaintext.value());
286     return plaintext_cord;
287   }
288 
289  private:
290   DummyAead aead_;
291 };
292 
293 // A dummy implementation of DeterministicAead-interface.
294 // An instance of DummyDeterministicAead can be identified by a name specified
295 // as a parameter of the constructor.
296 // The implementation is the same as DummyAead.
297 class DummyDeterministicAead : public DeterministicAead {
298  public:
DummyDeterministicAead(absl::string_view daead_name)299   explicit DummyDeterministicAead(absl::string_view daead_name)
300       : aead_(daead_name) {}
301 
EncryptDeterministically(absl::string_view plaintext,absl::string_view associated_data)302   crypto::tink::util::StatusOr<std::string> EncryptDeterministically(
303       absl::string_view plaintext,
304       absl::string_view associated_data) const override {
305     return aead_.Encrypt(plaintext, associated_data);
306   }
307 
DecryptDeterministically(absl::string_view ciphertext,absl::string_view associated_data)308   crypto::tink::util::StatusOr<std::string> DecryptDeterministically(
309       absl::string_view ciphertext,
310       absl::string_view associated_data) const override {
311     return aead_.Decrypt(ciphertext, associated_data);
312   }
313 
314  private:
315   DummyAead aead_;
316 };
317 
318 // A dummy implementation of StreamingAead-interface.  An instance of
319 // DummyStreamingAead can be identified by a name specified as a parameter of
320 // the constructor.  This name concatenated with 'associated_data' for a
321 // specific stream yields a header of an encrypted stream produced/consumed
322 // by DummyStreamingAead.
323 class DummyStreamingAead : public StreamingAead {
324  public:
DummyStreamingAead(absl::string_view streaming_aead_name)325   explicit DummyStreamingAead(absl::string_view streaming_aead_name)
326       : streaming_aead_name_(streaming_aead_name) {}
327 
328   crypto::tink::util::StatusOr<std::unique_ptr<crypto::tink::OutputStream>>
NewEncryptingStream(std::unique_ptr<crypto::tink::OutputStream> ciphertext_destination,absl::string_view associated_data)329   NewEncryptingStream(
330       std::unique_ptr<crypto::tink::OutputStream> ciphertext_destination,
331       absl::string_view associated_data) const override {
332     return {absl::make_unique<DummyEncryptingStream>(
333         std::move(ciphertext_destination),
334         absl::StrCat(streaming_aead_name_, associated_data))};
335   }
336 
337   crypto::tink::util::StatusOr<std::unique_ptr<crypto::tink::InputStream>>
NewDecryptingStream(std::unique_ptr<crypto::tink::InputStream> ciphertext_source,absl::string_view associated_data)338   NewDecryptingStream(
339       std::unique_ptr<crypto::tink::InputStream> ciphertext_source,
340       absl::string_view associated_data) const override {
341     return {absl::make_unique<DummyDecryptingStream>(
342         std::move(ciphertext_source),
343         absl::StrCat(streaming_aead_name_, associated_data))};
344   }
345 
346   crypto::tink::util::StatusOr<
347       std::unique_ptr<crypto::tink::RandomAccessStream>>
NewDecryptingRandomAccessStream(std::unique_ptr<crypto::tink::RandomAccessStream> ciphertext_source,absl::string_view associated_data)348   NewDecryptingRandomAccessStream(
349       std::unique_ptr<crypto::tink::RandomAccessStream> ciphertext_source,
350       absl::string_view associated_data) const override {
351     return {absl::make_unique<DummyDecryptingRandomAccessStream>(
352         std::move(ciphertext_source),
353         absl::StrCat(streaming_aead_name_, associated_data))};
354   }
355 
356   // Upon first call to Next() writes to 'ct_dest' the specifed 'header',
357   // and subsequently forwards all methods calls to the corresponding
358   // methods of 'cd_dest'.
359   class DummyEncryptingStream : public crypto::tink::OutputStream {
360    public:
DummyEncryptingStream(std::unique_ptr<crypto::tink::OutputStream> ct_dest,absl::string_view header)361     DummyEncryptingStream(std::unique_ptr<crypto::tink::OutputStream> ct_dest,
362                           absl::string_view header)
363         : ct_dest_(std::move(ct_dest)),
364           header_(header),
365           after_init_(false),
366           status_(util::OkStatus()) {}
367 
Next(void ** data)368     crypto::tink::util::StatusOr<int> Next(void** data) override {
369       if (!after_init_) {  // Try to initialize.
370         after_init_ = true;
371         auto next_result = ct_dest_->Next(data);
372         if (!next_result.ok()) {
373           status_ = next_result.status();
374           return status_;
375         }
376         if (next_result.value() < header_.size()) {
377           status_ =
378               util::Status(absl::StatusCode::kInternal, "Buffer too small");
379         } else {
380           memcpy(*data, header_.data(), static_cast<int>(header_.size()));
381           ct_dest_->BackUp(next_result.value() - header_.size());
382         }
383       }
384       if (!status_.ok()) return status_;
385       return ct_dest_->Next(data);
386     }
387 
BackUp(int count)388     void BackUp(int count) override {
389       if (after_init_ && status_.ok()) {
390         ct_dest_->BackUp(count);
391       }
392     }
393 
Position()394     int64_t Position() const override {
395       if (after_init_ && status_.ok()) {
396         return ct_dest_->Position() - header_.size();
397       } else {
398         return 0;
399       }
400     }
Close()401     util::Status Close() override {
402       if (!after_init_) {  // Call Next() to write the header to ct_dest_.
403         void* buf;
404         auto next_result = Next(&buf);
405         if (next_result.ok()) {
406           BackUp(next_result.value());
407         } else {
408           status_ = next_result.status();
409           return status_;
410         }
411       }
412       return ct_dest_->Close();
413     }
414 
415    private:
416     std::unique_ptr<crypto::tink::OutputStream> ct_dest_;
417     std::string header_;
418     bool after_init_;
419     util::Status status_;
420   };  // class DummyEncryptingStream
421 
422   // Upon first call to Next() tries to read from 'ct_source' a header
423   // that is expected to be equal to 'expected_header'.  If this
424   // header matching succeeds, all subsequent method calls are forwarded
425   // to the corresponding methods of 'cd_source'.
426   class DummyDecryptingStream : public crypto::tink::InputStream {
427    public:
DummyDecryptingStream(std::unique_ptr<crypto::tink::InputStream> ct_source,absl::string_view expected_header)428     DummyDecryptingStream(std::unique_ptr<crypto::tink::InputStream> ct_source,
429                           absl::string_view expected_header)
430         : ct_source_(std::move(ct_source)),
431           exp_header_(expected_header),
432           after_init_(false),
433           status_(util::OkStatus()) {}
434 
Next(const void ** data)435     crypto::tink::util::StatusOr<int> Next(const void** data) override {
436       if (!after_init_) {  // Try to initialize.
437         after_init_ = true;
438         auto next_result = ct_source_->Next(data);
439         if (!next_result.ok()) {
440           status_ = next_result.status();
441           if (status_.code() == absl::StatusCode::kOutOfRange) {
442             status_ = util::Status(absl::StatusCode::kInvalidArgument,
443                                    "Could not read header");
444           }
445           return status_;
446         }
447         if (next_result.value() < exp_header_.size()) {
448           status_ =
449               util::Status(absl::StatusCode::kInternal, "Buffer too small");
450         } else if (memcmp((*data), exp_header_.data(),
451                           static_cast<int>(exp_header_.size()))) {
452           status_ = util::Status(absl::StatusCode::kInvalidArgument,
453                                  "Corrupted header");
454         }
455         if (status_.ok()) {
456           ct_source_->BackUp(next_result.value() - exp_header_.size());
457         }
458       }
459       if (!status_.ok()) return status_;
460       return ct_source_->Next(data);
461     }
462 
BackUp(int count)463     void BackUp(int count) override {
464       if (after_init_ && status_.ok()) {
465         ct_source_->BackUp(count);
466       }
467     }
468 
Position()469     int64_t Position() const override {
470       if (after_init_ && status_.ok()) {
471         return ct_source_->Position() - exp_header_.size();
472       } else {
473         return 0;
474       }
475     }
476 
477    private:
478     std::unique_ptr<crypto::tink::InputStream> ct_source_;
479     std::string exp_header_;
480     bool after_init_;
481     util::Status status_;
482   };  // class DummyDecryptingStream
483 
484   // Upon first call to PRead() tries to read from `ct_source` a header
485   // that is expected to be equal to `expected_header`.  If this
486   // header matching succeeds, all subsequent method calls are forwarded
487   // to `ct_source->PRead`.
488   class DummyDecryptingRandomAccessStream
489       : public crypto::tink::RandomAccessStream {
490    public:
DummyDecryptingRandomAccessStream(std::unique_ptr<crypto::tink::RandomAccessStream> ct_source,absl::string_view expected_header)491     DummyDecryptingRandomAccessStream(
492         std::unique_ptr<crypto::tink::RandomAccessStream> ct_source,
493         absl::string_view expected_header)
494         : ct_source_(std::move(ct_source)), exp_header_(expected_header) {}
495 
PRead(int64_t position,int count,crypto::tink::util::Buffer * dest_buffer)496     crypto::tink::util::Status PRead(
497         int64_t position, int count,
498         crypto::tink::util::Buffer* dest_buffer) override {
499       util::Status status = CheckHeader();
500       if (!status.ok()) {
501         return status;
502       }
503       status = dest_buffer->set_size(0);
504       if (!status.ok()) return status;
505       return ct_source_->PRead(position + exp_header_.size(), count,
506                                dest_buffer);
507     }
508 
size()509     util::StatusOr<int64_t> size() override {
510       util::Status status = CheckHeader();
511       if (!status.ok()) {
512         return status;
513       }
514       auto ct_size_result = ct_source_->size();
515       if (!ct_size_result.ok()) return ct_size_result.status();
516       auto pt_size = ct_size_result.value() - exp_header_.size();
517       if (pt_size >= 0) return pt_size;
518       return util::Status(absl::StatusCode::kUnavailable, "size not available");
519     }
520 
521    private:
CheckHeader()522     util::Status CheckHeader()
523         ABSL_LOCKS_EXCLUDED(header_check_status_mutex_) {
524       absl::MutexLock lock(&header_check_status_mutex_);
525       if (header_check_status_.code() != absl::StatusCode::kUnavailable) {
526         return header_check_status_;
527       }
528       auto buf = std::move(util::Buffer::New(exp_header_.size()).value());
529       header_check_status_ =
530           ct_source_->PRead(0, exp_header_.size(), buf.get());
531       if (!header_check_status_.ok() &&
532           header_check_status_.code() != absl::StatusCode::kOutOfRange) {
533         return header_check_status_;
534       }
535       // EOF or Ok indicate a valid read has happened.
536       header_check_status_ = util::OkStatus();
537       // Invalid header.
538       if (buf->size() < exp_header_.size()) {
539         header_check_status_ = util::Status(absl::StatusCode::kInvalidArgument,
540                                "Could not read header");
541       } else if (memcmp(buf->get_mem_block(), exp_header_.data(),
542                         static_cast<int>(exp_header_.size()))) {
543         header_check_status_ = util::Status(absl::StatusCode::kInvalidArgument,
544                                "Corrupted header");
545       }
546       return header_check_status_;
547     }
548 
549     std::unique_ptr<crypto::tink::RandomAccessStream> ct_source_;
550     std::string exp_header_;
551     mutable absl::Mutex header_check_status_mutex_;
552     util::Status header_check_status_
553         ABSL_GUARDED_BY(header_check_status_mutex_) =
554             util::Status(absl::StatusCode::kUnavailable, "Uninitialized");
555   };  // class DummyDecryptingRandomAccessStream
556 
557  private:
558   std::string streaming_aead_name_;
559 };  // class DummyStreamingAead
560 
561 // A dummy implementation of HybridEncrypt-interface.
562 // An instance of DummyHybridEncrypt can be identified by a name specified
563 // as a parameter of the constructor.
564 class DummyHybridEncrypt : public HybridEncrypt {
565  public:
DummyHybridEncrypt(absl::string_view hybrid_name)566   explicit DummyHybridEncrypt(absl::string_view hybrid_name)
567       : dummy_aead_(absl::StrCat("DummyHybrid:", hybrid_name)) {}
568 
569   // Computes a dummy ciphertext, which is concatenation of provided 'plaintext'
570   // with the name of this DummyHybridEncrypt.
Encrypt(absl::string_view plaintext,absl::string_view context_info)571   crypto::tink::util::StatusOr<std::string> Encrypt(
572       absl::string_view plaintext,
573       absl::string_view context_info) const override {
574     return dummy_aead_.Encrypt(plaintext, context_info);
575   }
576 
577  private:
578   DummyAead dummy_aead_;
579 };
580 
581 // A dummy implementation of HybridDecrypt-interface.
582 // An instance of DummyHybridDecrypt can be identified by a name specified
583 // as a parameter of the constructor.
584 class DummyHybridDecrypt : public HybridDecrypt {
585  public:
DummyHybridDecrypt(absl::string_view hybrid_name)586   explicit DummyHybridDecrypt(absl::string_view hybrid_name)
587       : dummy_aead_(absl::StrCat("DummyHybrid:", hybrid_name)) {}
588 
589   // Decrypts a dummy ciphertext, which should be a concatenation
590   // of a plaintext with the name of this DummyHybridDecrypt.
Decrypt(absl::string_view ciphertext,absl::string_view context_info)591   crypto::tink::util::StatusOr<std::string> Decrypt(
592       absl::string_view ciphertext,
593       absl::string_view context_info) const override {
594     return dummy_aead_.Decrypt(ciphertext, context_info);
595   }
596 
597  private:
598   DummyAead dummy_aead_;
599 };
600 
601 // A dummy implementation of PublicKeySign-interface.
602 // An instance of DummyPublicKeySign can be identified by a name specified
603 // as a parameter of the constructor.
604 class DummyPublicKeySign : public PublicKeySign {
605  public:
DummyPublicKeySign(absl::string_view signature_name)606   explicit DummyPublicKeySign(absl::string_view signature_name)
607       : dummy_aead_(absl::StrCat("DummySign:", signature_name)) {}
608 
609   // Computes a dummy signature, which is a concatenation of 'data'
610   // with the name of this DummyPublicKeySign.
Sign(absl::string_view data)611   crypto::tink::util::StatusOr<std::string> Sign(
612       absl::string_view data) const override {
613     return dummy_aead_.Encrypt("", data);
614   }
615 
616  private:
617   DummyAead dummy_aead_;
618 };
619 
620 // A dummy implementation of PublicKeyVerify-interface.
621 // An instance of DummyPublicKeyVerify can be identified by a name specified
622 // as a parameter of the constructor.
623 class DummyPublicKeyVerify : public PublicKeyVerify {
624  public:
DummyPublicKeyVerify(absl::string_view signature_name)625   explicit DummyPublicKeyVerify(absl::string_view signature_name)
626       : dummy_aead_(absl::StrCat("DummySign:", signature_name)) {}
627 
628   // Verifies a dummy signature, should be a concatenation of the name
629   // of this DummyPublicKeyVerify with the provided 'data'.
Verify(absl::string_view signature,absl::string_view data)630   crypto::tink::util::Status Verify(absl::string_view signature,
631                                     absl::string_view data) const override {
632     return dummy_aead_.Decrypt(signature, data).status();
633   }
634 
635  private:
636   DummyAead dummy_aead_;
637 };
638 
639 // A dummy implementation of Mac-interface.
640 // An instance of DummyMac can be identified by a name specified
641 // as a parameter of the constructor.
642 class DummyMac : public Mac {
643  public:
DummyMac(const std::string & mac_name)644   explicit DummyMac(const std::string& mac_name)
645       : dummy_aead_(absl::StrCat("DummyMac:", mac_name)) {}
646 
647   // Computes a dummy MAC, which is concatenation of provided 'data'
648   // with the name of this DummyMac.
ComputeMac(absl::string_view data)649   crypto::tink::util::StatusOr<std::string> ComputeMac(
650       absl::string_view data) const override {
651     return dummy_aead_.Encrypt("", data);
652   }
653 
VerifyMac(absl::string_view mac,absl::string_view data)654   crypto::tink::util::Status VerifyMac(absl::string_view mac,
655                                        absl::string_view data) const override {
656     return dummy_aead_.Decrypt(mac, data).status();
657   }
658 
659  private:
660   DummyAead dummy_aead_;
661 };
662 
663 // A dummy implementation of Stateful Mac interface.
664 // An instance of DummyStatefulMac can be identified by a name specified
665 // as a parameter of the constructor.
666 // Over the same inputs, the DummyStatefulMac and DummyMac should give the same
667 // output; DummyStatefulMac builds and internal_state_ and calls DummyMac.
668 class DummyStatefulMac : public subtle::StatefulMac {
669  public:
DummyStatefulMac(const std::string & mac_name)670   explicit DummyStatefulMac(const std::string& mac_name)
671       : dummy_aead_(absl::StrCat("DummyMac:", mac_name)), buffer_("") {}
672 
Update(absl::string_view data)673   util::Status Update(absl::string_view data) override {
674     absl::StrAppend(&buffer_, data);
675     return util::OkStatus();
676   }
Finalize()677   util::StatusOr<std::string> Finalize() override {
678     return dummy_aead_.Encrypt("", buffer_);
679   }
680 
681  private:
682   DummyAead dummy_aead_;
683   std::string buffer_;
684 };
685 
686 // A dummy implementation of KeysetWriter-interface.
687 class DummyKeysetWriter : public KeysetWriter {
688  public:
New(std::unique_ptr<std::ostream> destination_stream)689   static crypto::tink::util::StatusOr<std::unique_ptr<DummyKeysetWriter>> New(
690       std::unique_ptr<std::ostream> destination_stream) {
691     std::unique_ptr<DummyKeysetWriter> writer(
692         new DummyKeysetWriter(std::move(destination_stream)));
693     return std::move(writer);
694   }
695 
Write(const google::crypto::tink::Keyset & keyset)696   crypto::tink::util::Status Write(
697       const google::crypto::tink::Keyset& keyset) override {
698     return crypto::tink::util::OkStatus();
699   }
700 
Write(const google::crypto::tink::EncryptedKeyset & encrypted_keyset)701   crypto::tink::util::Status Write(
702       const google::crypto::tink::EncryptedKeyset& encrypted_keyset) override {
703     return crypto::tink::util::OkStatus();
704   }
705 
706  private:
DummyKeysetWriter(std::unique_ptr<std::ostream> destination_stream)707   explicit DummyKeysetWriter(std::unique_ptr<std::ostream> destination_stream)
708       : destination_stream_(std::move(destination_stream)) {}
709 
710   std::unique_ptr<std::ostream> destination_stream_;
711 };
712 
713 // A dummy implementation of KmsClient-interface.
714 class DummyKmsClient : public KmsClient {
715  public:
DummyKmsClient(absl::string_view uri_prefix,absl::string_view key_uri)716   DummyKmsClient(absl::string_view uri_prefix, absl::string_view key_uri)
717       : uri_prefix_(uri_prefix), key_uri_(key_uri) {}
718 
DoesSupport(absl::string_view key_uri)719   bool DoesSupport(absl::string_view key_uri) const override {
720     if (key_uri.empty()) return false;
721     if (key_uri_.empty()) return absl::StartsWith(key_uri, uri_prefix_);
722     return key_uri == key_uri_;
723   }
724 
GetAead(absl::string_view key_uri)725   crypto::tink::util::StatusOr<std::unique_ptr<Aead>> GetAead(
726       absl::string_view key_uri) const override {
727     if (!DoesSupport(key_uri))
728       return crypto::tink::util::Status(absl::StatusCode::kInvalidArgument,
729                                         "key_uri not supported");
730     return {absl::make_unique<DummyAead>(key_uri)};
731   }
732 
733   ~DummyKmsClient() override = default;
734 
735  private:
736   std::string uri_prefix_;
737   std::string key_uri_;
738 };
739 
740 }  // namespace test
741 }  // namespace tink
742 }  // namespace crypto
743 
744 #endif  // TINK_UTIL_TEST_UTIL_H_
745