1*e7b1675dSTing-Kang Chang // Copyright 2019 Google Inc. 2*e7b1675dSTing-Kang Chang // 3*e7b1675dSTing-Kang Chang // Licensed under the Apache License, Version 2.0 (the "License"); 4*e7b1675dSTing-Kang Chang // you may not use this file except in compliance with the License. 5*e7b1675dSTing-Kang Chang // You may obtain a copy of the License at 6*e7b1675dSTing-Kang Chang // 7*e7b1675dSTing-Kang Chang // http://www.apache.org/licenses/LICENSE-2.0 8*e7b1675dSTing-Kang Chang // 9*e7b1675dSTing-Kang Chang // Unless required by applicable law or agreed to in writing, software 10*e7b1675dSTing-Kang Chang // distributed under the License is distributed on an "AS IS" BASIS, 11*e7b1675dSTing-Kang Chang // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*e7b1675dSTing-Kang Chang // See the License for the specific language governing permissions and 13*e7b1675dSTing-Kang Chang // limitations under the License. 14*e7b1675dSTing-Kang Chang // 15*e7b1675dSTing-Kang Chang /////////////////////////////////////////////////////////////////////////////// 16*e7b1675dSTing-Kang Chang 17*e7b1675dSTing-Kang Chang #ifndef TINK_SUBTLE_TEST_UTIL_H_ 18*e7b1675dSTing-Kang Chang #define TINK_SUBTLE_TEST_UTIL_H_ 19*e7b1675dSTing-Kang Chang 20*e7b1675dSTing-Kang Chang #include <memory> 21*e7b1675dSTing-Kang Chang #include <string> 22*e7b1675dSTing-Kang Chang #include <vector> 23*e7b1675dSTing-Kang Chang 24*e7b1675dSTing-Kang Chang #include "absl/memory/memory.h" 25*e7b1675dSTing-Kang Chang #include "absl/status/status.h" 26*e7b1675dSTing-Kang Chang #include "absl/strings/str_cat.h" 27*e7b1675dSTing-Kang Chang #include "absl/strings/string_view.h" 28*e7b1675dSTing-Kang Chang #include "tink/input_stream.h" 29*e7b1675dSTing-Kang Chang #include "tink/output_stream.h" 30*e7b1675dSTing-Kang Chang #include "tink/subtle/nonce_based_streaming_aead.h" 31*e7b1675dSTing-Kang Chang #include "tink/subtle/stream_segment_decrypter.h" 32*e7b1675dSTing-Kang Chang #include "tink/subtle/stream_segment_encrypter.h" 33*e7b1675dSTing-Kang Chang #include "tink/util/status.h" 34*e7b1675dSTing-Kang Chang #include "tink/util/statusor.h" 35*e7b1675dSTing-Kang Chang 36*e7b1675dSTing-Kang Chang namespace crypto { 37*e7b1675dSTing-Kang Chang namespace tink { 38*e7b1675dSTing-Kang Chang namespace subtle { 39*e7b1675dSTing-Kang Chang namespace test { 40*e7b1675dSTing-Kang Chang 41*e7b1675dSTing-Kang Chang // Various utilities for testing. 42*e7b1675dSTing-Kang Chang /////////////////////////////////////////////////////////////////////////////// 43*e7b1675dSTing-Kang Chang 44*e7b1675dSTing-Kang Chang // Writes 'contents' the specified 'output_stream', and if 'close_stream' 45*e7b1675dSTing-Kang Chang // is true, then closes the stream. 46*e7b1675dSTing-Kang Chang // Returns the status of output_stream->Close()-operation, or a non-OK status 47*e7b1675dSTing-Kang Chang // of a prior output_stream->Next()-operation, if any. 48*e7b1675dSTing-Kang Chang util::Status WriteToStream(OutputStream* output_stream, 49*e7b1675dSTing-Kang Chang absl::string_view contents, 50*e7b1675dSTing-Kang Chang bool close_stream = true); 51*e7b1675dSTing-Kang Chang 52*e7b1675dSTing-Kang Chang // Reads all bytes from the specified 'input_stream', and puts 53*e7b1675dSTing-Kang Chang // them into 'output', where both 'input_stream' and 'output must be non-null. 54*e7b1675dSTing-Kang Chang // Returns a non-OK status only if reading fails for some reason. 55*e7b1675dSTing-Kang Chang // If the end of stream is reached ('input_stream' returns OUT_OF_RANGE), 56*e7b1675dSTing-Kang Chang // then this function returns OK. 57*e7b1675dSTing-Kang Chang util::Status ReadFromStream(InputStream* input_stream, std::string* output); 58*e7b1675dSTing-Kang Chang 59*e7b1675dSTing-Kang Chang // A dummy encrypter that "encrypts" by just appending to the plaintext 60*e7b1675dSTing-Kang Chang // the current segment number and a marker byte indicating whether 61*e7b1675dSTing-Kang Chang // the segment is last one. 62*e7b1675dSTing-Kang Chang class DummyStreamSegmentEncrypter : public StreamSegmentEncrypter { 63*e7b1675dSTing-Kang Chang public: 64*e7b1675dSTing-Kang Chang // Size of the per-segment tag added upon encryption. 65*e7b1675dSTing-Kang Chang static constexpr int kSegmentTagSize = sizeof(int64_t) + 1; 66*e7b1675dSTing-Kang Chang 67*e7b1675dSTing-Kang Chang // Bytes for marking whether a given segment is the last one. 68*e7b1675dSTing-Kang Chang static constexpr char kLastSegment = 'l'; 69*e7b1675dSTing-Kang Chang static constexpr char kNotLastSegment = 'n'; 70*e7b1675dSTing-Kang Chang DummyStreamSegmentEncrypter(int pt_segment_size,int header_size,int ct_offset)71*e7b1675dSTing-Kang Chang DummyStreamSegmentEncrypter(int pt_segment_size, 72*e7b1675dSTing-Kang Chang int header_size, 73*e7b1675dSTing-Kang Chang int ct_offset) : 74*e7b1675dSTing-Kang Chang pt_segment_size_(pt_segment_size), 75*e7b1675dSTing-Kang Chang ct_offset_(ct_offset), 76*e7b1675dSTing-Kang Chang segment_number_(0) { 77*e7b1675dSTing-Kang Chang // Fill the header with 'header_size' copies of letter 'h' 78*e7b1675dSTing-Kang Chang header_.resize(0); 79*e7b1675dSTing-Kang Chang header_.resize(header_size, static_cast<uint8_t>('h')); 80*e7b1675dSTing-Kang Chang generated_output_size_ = header_size; 81*e7b1675dSTing-Kang Chang } 82*e7b1675dSTing-Kang Chang 83*e7b1675dSTing-Kang Chang // Generates an expected ciphertext for the given 'plaintext'. GenerateCiphertext(absl::string_view plaintext)84*e7b1675dSTing-Kang Chang std::string GenerateCiphertext(absl::string_view plaintext) { 85*e7b1675dSTing-Kang Chang std::string ct(header_.begin(), header_.end()); 86*e7b1675dSTing-Kang Chang int64_t seg_no = 0; 87*e7b1675dSTing-Kang Chang int pos = 0; 88*e7b1675dSTing-Kang Chang do { 89*e7b1675dSTing-Kang Chang int seg_len = pt_segment_size_; 90*e7b1675dSTing-Kang Chang if (pos == 0) { // The first segment. 91*e7b1675dSTing-Kang Chang seg_len -= (ct_offset_ + header_.size()); 92*e7b1675dSTing-Kang Chang } 93*e7b1675dSTing-Kang Chang if (seg_len > plaintext.size() - pos) { // The last segment. 94*e7b1675dSTing-Kang Chang seg_len = plaintext.size() - pos; 95*e7b1675dSTing-Kang Chang } 96*e7b1675dSTing-Kang Chang ct.append(plaintext.substr(pos, seg_len).data(), seg_len); 97*e7b1675dSTing-Kang Chang pos += seg_len; 98*e7b1675dSTing-Kang Chang ct.append(reinterpret_cast<const char*>(&seg_no), sizeof(seg_no)); 99*e7b1675dSTing-Kang Chang ct.append(1, pos < plaintext.size() ? kNotLastSegment : kLastSegment); 100*e7b1675dSTing-Kang Chang seg_no++; 101*e7b1675dSTing-Kang Chang } while (pos < plaintext.size()); 102*e7b1675dSTing-Kang Chang return ct; 103*e7b1675dSTing-Kang Chang } 104*e7b1675dSTing-Kang Chang EncryptSegment(const std::vector<uint8_t> & plaintext,bool is_last_segment,std::vector<uint8_t> * ciphertext_buffer)105*e7b1675dSTing-Kang Chang util::Status EncryptSegment( 106*e7b1675dSTing-Kang Chang const std::vector<uint8_t>& plaintext, 107*e7b1675dSTing-Kang Chang bool is_last_segment, 108*e7b1675dSTing-Kang Chang std::vector<uint8_t>* ciphertext_buffer) override { 109*e7b1675dSTing-Kang Chang ciphertext_buffer->resize(plaintext.size() + kSegmentTagSize); 110*e7b1675dSTing-Kang Chang memcpy(ciphertext_buffer->data(), plaintext.data(), plaintext.size()); 111*e7b1675dSTing-Kang Chang memcpy(ciphertext_buffer->data() + plaintext.size(), 112*e7b1675dSTing-Kang Chang &segment_number_, sizeof(segment_number_)); 113*e7b1675dSTing-Kang Chang // The last byte of the a ciphertext segment. 114*e7b1675dSTing-Kang Chang ciphertext_buffer->back() = 115*e7b1675dSTing-Kang Chang is_last_segment ? kLastSegment : kNotLastSegment; 116*e7b1675dSTing-Kang Chang generated_output_size_ += ciphertext_buffer->size(); 117*e7b1675dSTing-Kang Chang IncSegmentNumber(); 118*e7b1675dSTing-Kang Chang return util::OkStatus(); 119*e7b1675dSTing-Kang Chang } 120*e7b1675dSTing-Kang Chang get_header()121*e7b1675dSTing-Kang Chang const std::vector<uint8_t>& get_header() const override { 122*e7b1675dSTing-Kang Chang return header_; 123*e7b1675dSTing-Kang Chang } 124*e7b1675dSTing-Kang Chang get_segment_number()125*e7b1675dSTing-Kang Chang int64_t get_segment_number() const override { 126*e7b1675dSTing-Kang Chang return segment_number_; 127*e7b1675dSTing-Kang Chang } 128*e7b1675dSTing-Kang Chang get_plaintext_segment_size()129*e7b1675dSTing-Kang Chang int get_plaintext_segment_size() const override { 130*e7b1675dSTing-Kang Chang return pt_segment_size_; 131*e7b1675dSTing-Kang Chang } 132*e7b1675dSTing-Kang Chang get_ciphertext_segment_size()133*e7b1675dSTing-Kang Chang int get_ciphertext_segment_size() const override { 134*e7b1675dSTing-Kang Chang return pt_segment_size_ + kSegmentTagSize; 135*e7b1675dSTing-Kang Chang } 136*e7b1675dSTing-Kang Chang get_ciphertext_offset()137*e7b1675dSTing-Kang Chang int get_ciphertext_offset() const override { 138*e7b1675dSTing-Kang Chang return ct_offset_; 139*e7b1675dSTing-Kang Chang } 140*e7b1675dSTing-Kang Chang 141*e7b1675dSTing-Kang Chang ~DummyStreamSegmentEncrypter() override = default; 142*e7b1675dSTing-Kang Chang get_generated_output_size()143*e7b1675dSTing-Kang Chang int get_generated_output_size() { 144*e7b1675dSTing-Kang Chang return generated_output_size_; 145*e7b1675dSTing-Kang Chang } 146*e7b1675dSTing-Kang Chang 147*e7b1675dSTing-Kang Chang protected: IncSegmentNumber()148*e7b1675dSTing-Kang Chang void IncSegmentNumber() override { 149*e7b1675dSTing-Kang Chang segment_number_++; 150*e7b1675dSTing-Kang Chang } 151*e7b1675dSTing-Kang Chang 152*e7b1675dSTing-Kang Chang private: 153*e7b1675dSTing-Kang Chang std::vector<uint8_t> header_; 154*e7b1675dSTing-Kang Chang int pt_segment_size_; 155*e7b1675dSTing-Kang Chang int ct_offset_; 156*e7b1675dSTing-Kang Chang int64_t segment_number_; 157*e7b1675dSTing-Kang Chang int64_t generated_output_size_; 158*e7b1675dSTing-Kang Chang }; // class DummyStreamSegmentEncrypter 159*e7b1675dSTing-Kang Chang 160*e7b1675dSTing-Kang Chang // A dummy decrypter that "decrypts" segments encrypted by 161*e7b1675dSTing-Kang Chang // DummyStreamSegmentEncrypter. 162*e7b1675dSTing-Kang Chang class DummyStreamSegmentDecrypter : public StreamSegmentDecrypter { 163*e7b1675dSTing-Kang Chang public: DummyStreamSegmentDecrypter(int pt_segment_size,int header_size,int ct_offset)164*e7b1675dSTing-Kang Chang DummyStreamSegmentDecrypter(int pt_segment_size, 165*e7b1675dSTing-Kang Chang int header_size, 166*e7b1675dSTing-Kang Chang int ct_offset) : 167*e7b1675dSTing-Kang Chang pt_segment_size_(pt_segment_size), 168*e7b1675dSTing-Kang Chang ct_offset_(ct_offset) { 169*e7b1675dSTing-Kang Chang // Fill the header with 'header_size' copies of letter 'h' 170*e7b1675dSTing-Kang Chang header_.resize(0); 171*e7b1675dSTing-Kang Chang header_.resize(header_size, static_cast<uint8_t>('h')); 172*e7b1675dSTing-Kang Chang generated_output_size_ = 0; 173*e7b1675dSTing-Kang Chang } 174*e7b1675dSTing-Kang Chang Init(const std::vector<uint8_t> & header)175*e7b1675dSTing-Kang Chang util::Status Init(const std::vector<uint8_t>& header) override { 176*e7b1675dSTing-Kang Chang if (header_.size() != header.size() || 177*e7b1675dSTing-Kang Chang memcmp(header_.data(), header.data(), header_.size()) != 0) { 178*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInvalidArgument, 179*e7b1675dSTing-Kang Chang "Invalid stream header"); 180*e7b1675dSTing-Kang Chang } 181*e7b1675dSTing-Kang Chang return util::OkStatus(); 182*e7b1675dSTing-Kang Chang } 183*e7b1675dSTing-Kang Chang get_header_size()184*e7b1675dSTing-Kang Chang int get_header_size() const override { 185*e7b1675dSTing-Kang Chang return header_.size(); 186*e7b1675dSTing-Kang Chang } 187*e7b1675dSTing-Kang Chang DecryptSegment(const std::vector<uint8_t> & ciphertext,int64_t segment_number,bool is_last_segment,std::vector<uint8_t> * plaintext_buffer)188*e7b1675dSTing-Kang Chang util::Status DecryptSegment( 189*e7b1675dSTing-Kang Chang const std::vector<uint8_t>& ciphertext, 190*e7b1675dSTing-Kang Chang int64_t segment_number, 191*e7b1675dSTing-Kang Chang bool is_last_segment, 192*e7b1675dSTing-Kang Chang std::vector<uint8_t>* plaintext_buffer) override { 193*e7b1675dSTing-Kang Chang if (ciphertext.size() < DummyStreamSegmentEncrypter::kSegmentTagSize) { 194*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInvalidArgument, 195*e7b1675dSTing-Kang Chang "Ciphertext segment too short"); 196*e7b1675dSTing-Kang Chang } 197*e7b1675dSTing-Kang Chang if (ciphertext.back() != 198*e7b1675dSTing-Kang Chang (is_last_segment ? DummyStreamSegmentEncrypter::kLastSegment : 199*e7b1675dSTing-Kang Chang DummyStreamSegmentEncrypter::kNotLastSegment)) { 200*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInvalidArgument, 201*e7b1675dSTing-Kang Chang "unexpected last-segment marker"); 202*e7b1675dSTing-Kang Chang } 203*e7b1675dSTing-Kang Chang int pt_size = 204*e7b1675dSTing-Kang Chang ciphertext.size() - DummyStreamSegmentEncrypter::kSegmentTagSize; 205*e7b1675dSTing-Kang Chang if (memcmp(ciphertext.data() + pt_size, 206*e7b1675dSTing-Kang Chang reinterpret_cast<const char*>(&segment_number), 207*e7b1675dSTing-Kang Chang sizeof(segment_number)) != 0) { 208*e7b1675dSTing-Kang Chang return util::Status(absl::StatusCode::kInvalidArgument, 209*e7b1675dSTing-Kang Chang "wrong segment number"); 210*e7b1675dSTing-Kang Chang } 211*e7b1675dSTing-Kang Chang plaintext_buffer->resize(pt_size); 212*e7b1675dSTing-Kang Chang memcpy(plaintext_buffer->data(), ciphertext.data(), pt_size); 213*e7b1675dSTing-Kang Chang generated_output_size_ += pt_size; 214*e7b1675dSTing-Kang Chang return util::OkStatus(); 215*e7b1675dSTing-Kang Chang } 216*e7b1675dSTing-Kang Chang 217*e7b1675dSTing-Kang Chang get_plaintext_segment_size()218*e7b1675dSTing-Kang Chang int get_plaintext_segment_size() const override { 219*e7b1675dSTing-Kang Chang return pt_segment_size_; 220*e7b1675dSTing-Kang Chang } 221*e7b1675dSTing-Kang Chang get_ciphertext_segment_size()222*e7b1675dSTing-Kang Chang int get_ciphertext_segment_size() const override { 223*e7b1675dSTing-Kang Chang return pt_segment_size_ + DummyStreamSegmentEncrypter::kSegmentTagSize; 224*e7b1675dSTing-Kang Chang } 225*e7b1675dSTing-Kang Chang get_ciphertext_offset()226*e7b1675dSTing-Kang Chang int get_ciphertext_offset() const override { 227*e7b1675dSTing-Kang Chang return ct_offset_; 228*e7b1675dSTing-Kang Chang } 229*e7b1675dSTing-Kang Chang 230*e7b1675dSTing-Kang Chang ~DummyStreamSegmentDecrypter() override = default; 231*e7b1675dSTing-Kang Chang get_generated_output_size()232*e7b1675dSTing-Kang Chang int get_generated_output_size() { 233*e7b1675dSTing-Kang Chang return generated_output_size_; 234*e7b1675dSTing-Kang Chang } 235*e7b1675dSTing-Kang Chang 236*e7b1675dSTing-Kang Chang private: 237*e7b1675dSTing-Kang Chang std::vector<uint8_t> header_; 238*e7b1675dSTing-Kang Chang int pt_segment_size_; 239*e7b1675dSTing-Kang Chang int ct_offset_; 240*e7b1675dSTing-Kang Chang int64_t generated_output_size_; 241*e7b1675dSTing-Kang Chang }; // class DummyStreamSegmentDecrypter 242*e7b1675dSTing-Kang Chang 243*e7b1675dSTing-Kang Chang class DummyStreamingAead : public NonceBasedStreamingAead { 244*e7b1675dSTing-Kang Chang public: DummyStreamingAead(int pt_segment_size,int header_size,int ct_offset)245*e7b1675dSTing-Kang Chang DummyStreamingAead(int pt_segment_size, int header_size, int ct_offset) 246*e7b1675dSTing-Kang Chang : pt_segment_size_(pt_segment_size), 247*e7b1675dSTing-Kang Chang header_size_(header_size), 248*e7b1675dSTing-Kang Chang ct_offset_(ct_offset) {} 249*e7b1675dSTing-Kang Chang 250*e7b1675dSTing-Kang Chang protected: NewSegmentEncrypter(absl::string_view associated_data)251*e7b1675dSTing-Kang Chang util::StatusOr<std::unique_ptr<StreamSegmentEncrypter>> NewSegmentEncrypter( 252*e7b1675dSTing-Kang Chang absl::string_view associated_data) const override { 253*e7b1675dSTing-Kang Chang return {absl::make_unique<DummyStreamSegmentEncrypter>( 254*e7b1675dSTing-Kang Chang pt_segment_size_, header_size_, ct_offset_)}; 255*e7b1675dSTing-Kang Chang } 256*e7b1675dSTing-Kang Chang NewSegmentDecrypter(absl::string_view associated_data)257*e7b1675dSTing-Kang Chang util::StatusOr<std::unique_ptr<StreamSegmentDecrypter>> NewSegmentDecrypter( 258*e7b1675dSTing-Kang Chang absl::string_view associated_data) const override { 259*e7b1675dSTing-Kang Chang return {absl::make_unique<DummyStreamSegmentDecrypter>( 260*e7b1675dSTing-Kang Chang pt_segment_size_, header_size_, ct_offset_)}; 261*e7b1675dSTing-Kang Chang } 262*e7b1675dSTing-Kang Chang 263*e7b1675dSTing-Kang Chang private: 264*e7b1675dSTing-Kang Chang int pt_segment_size_; 265*e7b1675dSTing-Kang Chang int header_size_; 266*e7b1675dSTing-Kang Chang int ct_offset_; 267*e7b1675dSTing-Kang Chang }; 268*e7b1675dSTing-Kang Chang 269*e7b1675dSTing-Kang Chang } // namespace test 270*e7b1675dSTing-Kang Chang } // namespace subtle 271*e7b1675dSTing-Kang Chang } // namespace tink 272*e7b1675dSTing-Kang Chang } // namespace crypto 273*e7b1675dSTing-Kang Chang 274*e7b1675dSTing-Kang Chang #endif // TINK_SUBTLE_TEST_UTIL_H_ 275