Home | History | Annotate | Download | only in crypto
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "net/quic/crypto/chacha20_poly1305_decrypter.h"
      6 
      7 #include "net/quic/test_tools/quic_test_utils.h"
      8 
      9 using base::StringPiece;
     10 
     11 namespace {
     12 
     13 // The test vectors come from draft-agl-tls-chacha20poly1305-04 Section 7.
     14 
     15 // Each test vector consists of six strings of lowercase hexadecimal digits.
     16 // The strings may be empty (zero length). A test vector with a NULL |key|
     17 // marks the end of an array of test vectors.
     18 struct TestVector {
     19   // Input:
     20   const char* key;
     21   const char* iv;
     22   const char* aad;
     23   const char* ct;
     24 
     25   // Expected output:
     26   const char* pt;  // An empty string "" means decryption succeeded and
     27                    // the plaintext is zero-length. NULL means decryption
     28                    // failed.
     29 };
     30 
     31 const TestVector test_vectors[] = {
     32   { "4290bcb154173531f314af57f3be3b5006da371ece272afa1b5dbdd110"
     33         "0a1007",
     34     "cd7cf67be39c794a",
     35     "87e229d4500845a079c0",
     36     "e3e446f7ede9a19b62a4677dabf4e3d24b876bb28475",  // "3896e1d6" truncated.
     37     "86d09974840bded2a5ca"
     38   },
     39   // Modify the ciphertext (ChaCha20 encryption output).
     40   { "4290bcb154173531f314af57f3be3b5006da371ece272afa1b5dbdd110"
     41         "0a1007",
     42     "cd7cf67be39c794a",
     43     "87e229d4500845a079c0",
     44     "f3e446f7ede9a19b62a4677dabf4e3d24b876bb28475",  // "3896e1d6" truncated.
     45     NULL  // FAIL
     46   },
     47   // Modify the ciphertext (Poly1305 authenticator).
     48   { "4290bcb154173531f314af57f3be3b5006da371ece272afa1b5dbdd110"
     49         "0a1007",
     50     "cd7cf67be39c794a",
     51     "87e229d4500845a079c0",
     52     "e3e446f7ede9a19b62a4677dabf4e3d24b876bb28476",  // "3896e1d6" truncated.
     53     NULL  // FAIL
     54   },
     55   // Modify the associated data.
     56   { "4290bcb154173531f314af57f3be3b5006da371ece272afa1b5dbdd110"
     57         "0a1007",
     58     "dd7cf67be39c794a",
     59     "87e229d4500845a079c0",
     60     "e3e446f7ede9a19b62a4677dabf4e3d24b876bb28475",  // "3896e1d6" truncated.
     61     NULL  // FAIL
     62   },
     63   { NULL }
     64 };
     65 
     66 }  // namespace
     67 
     68 namespace net {
     69 namespace test {
     70 
     71 // DecryptWithNonce wraps the |Decrypt| method of |decrypter| to allow passing
     72 // in an nonce and also to allocate the buffer needed for the plaintext.
     73 QuicData* DecryptWithNonce(ChaCha20Poly1305Decrypter* decrypter,
     74                            StringPiece nonce,
     75                            StringPiece associated_data,
     76                            StringPiece ciphertext) {
     77   size_t plaintext_size = ciphertext.length();
     78   scoped_ptr<char[]> plaintext(new char[plaintext_size]);
     79 
     80   if (!decrypter->Decrypt(nonce, associated_data, ciphertext,
     81                           reinterpret_cast<unsigned char*>(plaintext.get()),
     82                           &plaintext_size)) {
     83     return NULL;
     84   }
     85   return new QuicData(plaintext.release(), plaintext_size, true);
     86 }
     87 
     88 TEST(ChaCha20Poly1305DecrypterTest, Decrypt) {
     89   if (!ChaCha20Poly1305Decrypter::IsSupported()) {
     90     LOG(INFO) << "ChaCha20+Poly1305 not supported. Test skipped.";
     91     return;
     92   }
     93 
     94   for (size_t i = 0; test_vectors[i].key != NULL; i++) {
     95     // If not present then decryption is expected to fail.
     96     bool has_pt = test_vectors[i].pt;
     97 
     98     // Decode the test vector.
     99     string key;
    100     string iv;
    101     string aad;
    102     string ct;
    103     string pt;
    104     ASSERT_TRUE(DecodeHexString(test_vectors[i].key, &key));
    105     ASSERT_TRUE(DecodeHexString(test_vectors[i].iv, &iv));
    106     ASSERT_TRUE(DecodeHexString(test_vectors[i].aad, &aad));
    107     ASSERT_TRUE(DecodeHexString(test_vectors[i].ct, &ct));
    108     if (has_pt) {
    109       ASSERT_TRUE(DecodeHexString(test_vectors[i].pt, &pt));
    110     }
    111 
    112     ChaCha20Poly1305Decrypter decrypter;
    113     ASSERT_TRUE(decrypter.SetKey(key));
    114     scoped_ptr<QuicData> decrypted(DecryptWithNonce(
    115         &decrypter, iv,
    116         // This deliberately tests that the decrypter can handle an AAD that
    117         // is set to NULL, as opposed to a zero-length, non-NULL pointer.
    118         StringPiece(aad.length() ? aad.data() : NULL, aad.length()), ct));
    119     if (!decrypted.get()) {
    120       EXPECT_FALSE(has_pt);
    121       continue;
    122     }
    123     EXPECT_TRUE(has_pt);
    124 
    125     ASSERT_EQ(pt.length(), decrypted->length());
    126     test::CompareCharArraysWithHexError("plaintext", decrypted->data(),
    127                                         pt.length(), pt.data(), pt.length());
    128   }
    129 }
    130 
    131 }  // namespace test
    132 }  // namespace net
    133