aead_base_decrypter_openssl.cc revision e5d81f57cb97b3b6b7fccc9c5610d21eb81db09d
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/aead_base_decrypter.h"
6
7#include <openssl/err.h>
8#include <openssl/evp.h>
9
10#include "base/memory/scoped_ptr.h"
11
12using base::StringPiece;
13
14namespace net {
15
16namespace {
17
18// Clear OpenSSL error stack.
19void ClearOpenSslErrors() {
20  while (ERR_get_error()) {}
21}
22
23// In debug builds only, log OpenSSL error stack. Then clear OpenSSL error
24// stack.
25void DLogOpenSslErrors() {
26#ifdef NDEBUG
27  ClearOpenSslErrors();
28#else
29  while (unsigned long error = ERR_get_error()) {
30    char buf[120];
31    ERR_error_string_n(error, buf, arraysize(buf));
32    DLOG(ERROR) << "OpenSSL error: " << buf;
33  }
34#endif
35}
36
37}  // namespace
38
39AeadBaseDecrypter::AeadBaseDecrypter(const EVP_AEAD* aead_alg,
40                                     size_t key_size,
41                                     size_t auth_tag_size,
42                                     size_t nonce_prefix_size)
43    : aead_alg_(aead_alg),
44      key_size_(key_size),
45      auth_tag_size_(auth_tag_size),
46      nonce_prefix_size_(nonce_prefix_size) {
47  DCHECK_LE(key_size_, sizeof(key_));
48  DCHECK_LE(nonce_prefix_size_, sizeof(nonce_prefix_));
49}
50
51AeadBaseDecrypter::~AeadBaseDecrypter() {}
52
53bool AeadBaseDecrypter::SetKey(StringPiece key) {
54  DCHECK_EQ(key.size(), key_size_);
55  if (key.size() != key_size_) {
56    return false;
57  }
58  memcpy(key_, key.data(), key.size());
59
60  EVP_AEAD_CTX_cleanup(ctx_.get());
61  if (!EVP_AEAD_CTX_init(ctx_.get(), aead_alg_, key_, key_size_,
62                         auth_tag_size_, NULL)) {
63    DLogOpenSslErrors();
64    return false;
65  }
66
67  return true;
68}
69
70bool AeadBaseDecrypter::SetNoncePrefix(StringPiece nonce_prefix) {
71  DCHECK_EQ(nonce_prefix.size(), nonce_prefix_size_);
72  if (nonce_prefix.size() != nonce_prefix_size_) {
73    return false;
74  }
75  memcpy(nonce_prefix_, nonce_prefix.data(), nonce_prefix.size());
76  return true;
77}
78
79bool AeadBaseDecrypter::Decrypt(StringPiece nonce,
80                                StringPiece associated_data,
81                                StringPiece ciphertext,
82                                uint8* output,
83                                size_t* output_length) {
84  if (ciphertext.length() < auth_tag_size_ ||
85      nonce.size() != nonce_prefix_size_ + sizeof(QuicPacketSequenceNumber)) {
86    return false;
87  }
88
89  ssize_t len = EVP_AEAD_CTX_open(
90      ctx_.get(), output, ciphertext.size(),
91      reinterpret_cast<const uint8_t*>(nonce.data()), nonce.size(),
92      reinterpret_cast<const uint8_t*>(ciphertext.data()), ciphertext.size(),
93      reinterpret_cast<const uint8_t*>(associated_data.data()),
94      associated_data.size());
95
96  if (len < 0) {
97    // Because QuicFramer does trial decryption, decryption errors are expected
98    // when encryption level changes. So we don't log decryption errors.
99    ClearOpenSslErrors();
100    return false;
101  }
102
103  *output_length = len;
104  return true;
105}
106
107QuicData* AeadBaseDecrypter::DecryptPacket(
108    QuicPacketSequenceNumber sequence_number,
109    StringPiece associated_data,
110    StringPiece ciphertext) {
111  if (ciphertext.length() < auth_tag_size_) {
112    return NULL;
113  }
114  size_t plaintext_size = ciphertext.length();
115  scoped_ptr<char[]> plaintext(new char[plaintext_size]);
116
117  uint8 nonce[sizeof(nonce_prefix_) + sizeof(sequence_number)];
118  const size_t nonce_size = nonce_prefix_size_ + sizeof(sequence_number);
119  DCHECK_LE(nonce_size, sizeof(nonce));
120  memcpy(nonce, nonce_prefix_, nonce_prefix_size_);
121  memcpy(nonce + nonce_prefix_size_, &sequence_number, sizeof(sequence_number));
122  if (!Decrypt(StringPiece(reinterpret_cast<char*>(nonce), nonce_size),
123               associated_data, ciphertext,
124               reinterpret_cast<uint8*>(plaintext.get()),
125               &plaintext_size)) {
126    return NULL;
127  }
128  return new QuicData(plaintext.release(), plaintext_size, true);
129}
130
131StringPiece AeadBaseDecrypter::GetKey() const {
132  return StringPiece(reinterpret_cast<const char*>(key_), key_size_);
133}
134
135StringPiece AeadBaseDecrypter::GetNoncePrefix() const {
136  if (nonce_prefix_size_ == 0) {
137    return StringPiece();
138  }
139  return StringPiece(reinterpret_cast<const char*>(nonce_prefix_),
140                     nonce_prefix_size_);
141}
142
143}  // namespace net
144