Home | History | Annotate | Download | only in crypto
      1 // Copyright (c) 2013 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/aes_128_gcm_12_decrypter.h"
      6 
      7 #include <openssl/evp.h>
      8 
      9 #include "base/memory/scoped_ptr.h"
     10 
     11 using base::StringPiece;
     12 
     13 namespace net {
     14 
     15 namespace {
     16 
     17 const size_t kKeySize = 16;
     18 const size_t kNoncePrefixSize = 4;
     19 const size_t kAESNonceSize = 12;
     20 
     21 }  // namespace
     22 
     23 Aes128Gcm12Decrypter::Aes128Gcm12Decrypter() {}
     24 
     25 Aes128Gcm12Decrypter::~Aes128Gcm12Decrypter() {}
     26 
     27 // static
     28 bool Aes128Gcm12Decrypter::IsSupported() { return true; }
     29 
     30 bool Aes128Gcm12Decrypter::SetKey(StringPiece key) {
     31   DCHECK_EQ(key.size(), sizeof(key_));
     32   if (key.size() != sizeof(key_)) {
     33     return false;
     34   }
     35   memcpy(key_, key.data(), key.size());
     36 
     37   // Set the cipher type and the key.
     38   if (EVP_EncryptInit_ex(ctx_.get(), EVP_aes_128_gcm(), NULL, key_,
     39                          NULL) == 0) {
     40     return false;
     41   }
     42 
     43   // Set the IV (nonce) length.
     44   if (EVP_CIPHER_CTX_ctrl(ctx_.get(), EVP_CTRL_GCM_SET_IVLEN, kAESNonceSize,
     45                           NULL) == 0) {
     46     return false;
     47   }
     48 
     49   return true;
     50 }
     51 
     52 bool Aes128Gcm12Decrypter::SetNoncePrefix(StringPiece nonce_prefix) {
     53   DCHECK_EQ(nonce_prefix.size(), kNoncePrefixSize);
     54   if (nonce_prefix.size() != kNoncePrefixSize) {
     55     return false;
     56   }
     57   COMPILE_ASSERT(sizeof(nonce_prefix_) == kNoncePrefixSize, bad_nonce_length);
     58   memcpy(nonce_prefix_, nonce_prefix.data(), nonce_prefix.size());
     59   return true;
     60 }
     61 
     62 bool Aes128Gcm12Decrypter::Decrypt(StringPiece nonce,
     63                                    StringPiece associated_data,
     64                                    StringPiece ciphertext,
     65                                    uint8* output,
     66                                    size_t* output_length) {
     67   if (ciphertext.length() < kAuthTagSize ||
     68       nonce.size() != kNoncePrefixSize + sizeof(QuicPacketSequenceNumber)) {
     69     return false;
     70   }
     71   const size_t plaintext_size = ciphertext.length() - kAuthTagSize;
     72 
     73   // Set the IV (nonce).
     74   if (EVP_DecryptInit_ex(
     75           ctx_.get(), NULL, NULL, NULL,
     76           reinterpret_cast<const uint8*>(nonce.data())) == 0) {
     77     return false;
     78   }
     79 
     80   // Set the authentication tag.
     81   if (EVP_CIPHER_CTX_ctrl(
     82           ctx_.get(), EVP_CTRL_GCM_SET_TAG, kAuthTagSize,
     83           const_cast<char*>(ciphertext.data()) + plaintext_size) == 0) {
     84     return false;
     85   }
     86 
     87   // If we pass a NULL, zero-length associated data to OpenSSL then it breaks.
     88   // Thus we only set non-empty associated data.
     89   if (!associated_data.empty()) {
     90     // Set the associated data. The second argument (output buffer) must be
     91     // NULL.
     92     int unused_len;
     93     if (EVP_DecryptUpdate(
     94             ctx_.get(), NULL, &unused_len,
     95             reinterpret_cast<const uint8*>(associated_data.data()),
     96             associated_data.size()) == 0) {
     97       return false;
     98     }
     99   }
    100 
    101   int len;
    102   if (EVP_DecryptUpdate(
    103           ctx_.get(), output, &len,
    104           reinterpret_cast<const uint8*>(ciphertext.data()),
    105           plaintext_size) == 0) {
    106     return false;
    107   }
    108   output += len;
    109 
    110   if (EVP_DecryptFinal_ex(ctx_.get(), output, &len) == 0) {
    111     return false;
    112   }
    113   output += len;
    114 
    115   *output_length = plaintext_size;
    116 
    117   return true;
    118 }
    119 
    120 QuicData* Aes128Gcm12Decrypter::DecryptPacket(
    121     QuicPacketSequenceNumber sequence_number,
    122     StringPiece associated_data,
    123     StringPiece ciphertext) {
    124   if (ciphertext.length() < kAuthTagSize) {
    125     return NULL;
    126   }
    127   size_t plaintext_size;
    128   scoped_ptr<char[]> plaintext(new char[ciphertext.length()]);
    129 
    130   uint8 nonce[kNoncePrefixSize + sizeof(sequence_number)];
    131   COMPILE_ASSERT(sizeof(nonce) == kAESNonceSize, bad_sequence_number_size);
    132   memcpy(nonce, nonce_prefix_, kNoncePrefixSize);
    133   memcpy(nonce + kNoncePrefixSize, &sequence_number, sizeof(sequence_number));
    134   if (!Decrypt(StringPiece(reinterpret_cast<char*>(nonce), sizeof(nonce)),
    135                associated_data, ciphertext,
    136                reinterpret_cast<uint8*>(plaintext.get()),
    137                &plaintext_size)) {
    138     return NULL;
    139   }
    140   return new QuicData(plaintext.release(), plaintext_size, true);
    141 }
    142 
    143 StringPiece Aes128Gcm12Decrypter::GetKey() const {
    144   return StringPiece(reinterpret_cast<const char*>(key_), sizeof(key_));
    145 }
    146 
    147 StringPiece Aes128Gcm12Decrypter::GetNoncePrefix() const {
    148   return StringPiece(reinterpret_cast<const char*>(nonce_prefix_),
    149                      kNoncePrefixSize);
    150 }
    151 
    152 }  // namespace net
    153