summaryrefslogtreecommitdiffstats
path: root/net/quic/crypto/crypto_secret_boxer.cc
blob: 08a431745fd5512d94ef312406a28db9eb8c3659 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/quic/crypto/crypto_secret_boxer.h"

#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "net/quic/crypto/aes_128_gcm_12_decrypter.h"
#include "net/quic/crypto/aes_128_gcm_12_encrypter.h"
#include "net/quic/crypto/crypto_protocol.h"
#include "net/quic/crypto/quic_decrypter.h"
#include "net/quic/crypto/quic_encrypter.h"
#include "net/quic/crypto/quic_random.h"

using base::StringPiece;
using std::string;
using std::vector;

namespace net {

// Defined kKeySize for GetKeySize() and SetKey().
static const size_t kKeySize = 16;

// kBoxNonceSize contains the number of bytes of nonce that we use in each box.
// TODO(rtenneti): Add support for kBoxNonceSize to be 16 bytes.
//
// From agl@:
//   96-bit nonces are on the edge. An attacker who can collect 2^41
//   source-address tokens has a 1% chance of finding a duplicate.
//
//   The "average" DDoS is now 32.4M PPS. That's 2^25 source-address tokens
//   per second. So one day of that DDoS botnot would reach the 1% mark.
//
//   It's not terrible, but it's not a "forget about it" margin.
static const size_t kBoxNonceSize = 12;

CryptoSecretBoxer::CryptoSecretBoxer() {}

CryptoSecretBoxer::~CryptoSecretBoxer() {}

// static
size_t CryptoSecretBoxer::GetKeySize() {
  return kKeySize;
}

void CryptoSecretBoxer::SetKeys(const vector<string>& keys) {
  DCHECK(!keys.empty());
  vector<string> copy = keys;
  for (const string& key : keys) {
    DCHECK_EQ(kKeySize, key.size());
  }
  base::AutoLock l(lock_);
  keys_.swap(copy);
}

string CryptoSecretBoxer::Box(QuicRandom* rand, StringPiece plaintext) const {
  scoped_ptr<Aes128Gcm12Encrypter> encrypter(new Aes128Gcm12Encrypter());
  {
    base::AutoLock l(lock_);
    DCHECK_EQ(kKeySize, keys_[0].size());
    if (!encrypter->SetKey(keys_[0])) {
      DLOG(DFATAL) << "CryptoSecretBoxer's encrypter->SetKey failed.";
      return string();
    }
  }
  size_t ciphertext_size = encrypter->GetCiphertextSize(plaintext.length());

  string ret;
  const size_t len = kBoxNonceSize + ciphertext_size;
  ret.resize(len);
  char* data = &ret[0];

  // Generate nonce.
  rand->RandBytes(data, kBoxNonceSize);
  memcpy(data + kBoxNonceSize, plaintext.data(), plaintext.size());

  if (!encrypter->Encrypt(
          StringPiece(data, kBoxNonceSize), StringPiece(), plaintext,
          reinterpret_cast<unsigned char*>(data + kBoxNonceSize))) {
    DLOG(DFATAL) << "CryptoSecretBoxer's Encrypt failed.";
    return string();
  }

  return ret;
}

bool CryptoSecretBoxer::Unbox(StringPiece ciphertext,
                              string* out_storage,
                              StringPiece* out) const {
  if (ciphertext.size() < kBoxNonceSize) {
    return false;
  }

  StringPiece nonce(ciphertext.data(), kBoxNonceSize);
  ciphertext.remove_prefix(kBoxNonceSize);
  QuicPacketNumber packet_number;
  StringPiece nonce_prefix(nonce.data(), nonce.size() - sizeof(packet_number));
  memcpy(&packet_number, nonce.data() + nonce_prefix.size(),
         sizeof(packet_number));

  scoped_ptr<Aes128Gcm12Decrypter> decrypter(new Aes128Gcm12Decrypter());
  char plaintext[kMaxPacketSize];
  size_t plaintext_length = 0;
  bool ok = false;
  {
    base::AutoLock l(lock_);
    for (const string& key : keys_) {
      if (decrypter->SetKey(key)) {
        decrypter->SetNoncePrefix(nonce_prefix);
        if (decrypter->DecryptPacket(
                /*path_id=*/0u, packet_number,
                /*associated data=*/StringPiece(), ciphertext, plaintext,
                &plaintext_length, kMaxPacketSize)) {
          ok = true;
          break;
        }
      }
    }
  }
  if (!ok) {
    return false;
  }

  out_storage->resize(plaintext_length);
  out_storage->assign(plaintext, plaintext_length);
  out->set(out_storage->data(), plaintext_length);
  return true;
}

}  // namespace net