• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_encrypter.h"
6 
7 #include <pk11pub.h>
8 
9 #include "base/memory/scoped_ptr.h"
10 #include "crypto/scoped_nss_types.h"
11 
12 using base::StringPiece;
13 
14 namespace net {
15 
AeadBaseEncrypter(CK_MECHANISM_TYPE aead_mechanism,PK11_EncryptFunction pk11_encrypt,size_t key_size,size_t auth_tag_size,size_t nonce_prefix_size)16 AeadBaseEncrypter::AeadBaseEncrypter(CK_MECHANISM_TYPE aead_mechanism,
17                                      PK11_EncryptFunction pk11_encrypt,
18                                      size_t key_size,
19                                      size_t auth_tag_size,
20                                      size_t nonce_prefix_size)
21     : aead_mechanism_(aead_mechanism),
22       pk11_encrypt_(pk11_encrypt),
23       key_size_(key_size),
24       auth_tag_size_(auth_tag_size),
25       nonce_prefix_size_(nonce_prefix_size) {
26   DCHECK_LE(key_size_, sizeof(key_));
27   DCHECK_LE(nonce_prefix_size_, sizeof(nonce_prefix_));
28 }
29 
~AeadBaseEncrypter()30 AeadBaseEncrypter::~AeadBaseEncrypter() {}
31 
SetKey(StringPiece key)32 bool AeadBaseEncrypter::SetKey(StringPiece key) {
33   DCHECK_EQ(key.size(), key_size_);
34   if (key.size() != key_size_) {
35     return false;
36   }
37   memcpy(key_, key.data(), key.size());
38   return true;
39 }
40 
SetNoncePrefix(StringPiece nonce_prefix)41 bool AeadBaseEncrypter::SetNoncePrefix(StringPiece nonce_prefix) {
42   DCHECK_EQ(nonce_prefix.size(), nonce_prefix_size_);
43   if (nonce_prefix.size() != nonce_prefix_size_) {
44     return false;
45   }
46   memcpy(nonce_prefix_, nonce_prefix.data(), nonce_prefix.size());
47   return true;
48 }
49 
Encrypt(StringPiece nonce,StringPiece associated_data,StringPiece plaintext,unsigned char * output)50 bool AeadBaseEncrypter::Encrypt(StringPiece nonce,
51                                 StringPiece associated_data,
52                                 StringPiece plaintext,
53                                 unsigned char* output) {
54   if (nonce.size() != nonce_prefix_size_ + sizeof(QuicPacketSequenceNumber)) {
55     return false;
56   }
57 
58   size_t ciphertext_size = GetCiphertextSize(plaintext.length());
59 
60   // Import key_ into NSS.
61   SECItem key_item;
62   key_item.type = siBuffer;
63   key_item.data = key_;
64   key_item.len = key_size_;
65   PK11SlotInfo* slot = PK11_GetInternalSlot();
66 
67   // TODO(wtc): For an AES-GCM key, the correct value for |key_mechanism| is
68   // CKM_AES_GCM, but because of NSS bug
69   // https://bugzilla.mozilla.org/show_bug.cgi?id=853285, use CKM_AES_ECB as a
70   // workaround. Remove this when we require NSS 3.15.
71   CK_MECHANISM_TYPE key_mechanism = aead_mechanism_;
72   if (key_mechanism == CKM_AES_GCM) {
73     key_mechanism = CKM_AES_ECB;
74   }
75 
76   // The exact value of the |origin| argument doesn't matter to NSS as long as
77   // it's not PK11_OriginFortezzaHack, so we pass PK11_OriginUnwrap as a
78   // placeholder.
79   crypto::ScopedPK11SymKey aead_key(PK11_ImportSymKey(
80       slot, key_mechanism, PK11_OriginUnwrap, CKA_ENCRYPT, &key_item, NULL));
81   PK11_FreeSlot(slot);
82   slot = NULL;
83   if (!aead_key) {
84     DVLOG(1) << "PK11_ImportSymKey failed";
85     return false;
86   }
87 
88   AeadParams aead_params = {0};
89   FillAeadParams(nonce, associated_data, auth_tag_size_, &aead_params);
90 
91   SECItem param;
92   param.type = siBuffer;
93   param.data = reinterpret_cast<unsigned char*>(&aead_params.data);
94   param.len = aead_params.len;
95 
96   unsigned int output_len;
97   if (pk11_encrypt_(aead_key.get(), aead_mechanism_, &param,
98                     output, &output_len, ciphertext_size,
99                     reinterpret_cast<const unsigned char*>(plaintext.data()),
100                     plaintext.size()) != SECSuccess) {
101     DVLOG(1) << "pk11_encrypt_ failed";
102     return false;
103   }
104 
105   if (output_len != ciphertext_size) {
106     DVLOG(1) << "Wrong output length";
107     return false;
108   }
109 
110   return true;
111 }
112 
EncryptPacket(QuicPacketSequenceNumber sequence_number,StringPiece associated_data,StringPiece plaintext)113 QuicData* AeadBaseEncrypter::EncryptPacket(
114     QuicPacketSequenceNumber sequence_number,
115     StringPiece associated_data,
116     StringPiece plaintext) {
117   size_t ciphertext_size = GetCiphertextSize(plaintext.length());
118   scoped_ptr<char[]> ciphertext(new char[ciphertext_size]);
119 
120   // TODO(ianswett): Introduce a check to ensure that we don't encrypt with the
121   // same sequence number twice.
122   uint8 nonce[sizeof(nonce_prefix_) + sizeof(sequence_number)];
123   const size_t nonce_size = nonce_prefix_size_ + sizeof(sequence_number);
124   DCHECK_LE(nonce_size, sizeof(nonce));
125   memcpy(nonce, nonce_prefix_, nonce_prefix_size_);
126   memcpy(nonce + nonce_prefix_size_, &sequence_number, sizeof(sequence_number));
127   if (!Encrypt(StringPiece(reinterpret_cast<char*>(nonce), nonce_size),
128                associated_data, plaintext,
129                reinterpret_cast<unsigned char*>(ciphertext.get()))) {
130     return NULL;
131   }
132 
133   return new QuicData(ciphertext.release(), ciphertext_size, true);
134 }
135 
GetKeySize() const136 size_t AeadBaseEncrypter::GetKeySize() const { return key_size_; }
137 
GetNoncePrefixSize() const138 size_t AeadBaseEncrypter::GetNoncePrefixSize() const {
139   return nonce_prefix_size_;
140 }
141 
GetMaxPlaintextSize(size_t ciphertext_size) const142 size_t AeadBaseEncrypter::GetMaxPlaintextSize(size_t ciphertext_size) const {
143   return ciphertext_size - auth_tag_size_;
144 }
145 
GetCiphertextSize(size_t plaintext_size) const146 size_t AeadBaseEncrypter::GetCiphertextSize(size_t plaintext_size) const {
147   return plaintext_size + auth_tag_size_;
148 }
149 
GetKey() const150 StringPiece AeadBaseEncrypter::GetKey() const {
151   return StringPiece(reinterpret_cast<const char*>(key_), key_size_);
152 }
153 
GetNoncePrefix() const154 StringPiece AeadBaseEncrypter::GetNoncePrefix() const {
155   if (nonce_prefix_size_ == 0) {
156     return StringPiece();
157   }
158   return StringPiece(reinterpret_cast<const char*>(nonce_prefix_),
159                      nonce_prefix_size_);
160 }
161 
162 }  // namespace net
163