|
OLD | NEW |
---|---|
(Empty) | |
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_decrypter.h" | |
6 | |
7 #include <openssl/evp.h> | |
8 | |
9 #include "base/memory/scoped_ptr.h" | |
10 #include "net/quic/crypto/scoped_evp_cipher_ctx.h" | |
11 | |
12 using base::StringPiece; | |
13 | |
14 namespace net { | |
15 | |
16 namespace { | |
17 | |
18 const size_t kKeySize = 16; | |
19 const size_t kNoncePrefixSize = 4; | |
20 const size_t kAuthTagSize = 16; | |
21 | |
22 } // namespace | |
23 | |
24 bool Aes128GcmDecrypter::SetKey(StringPiece key) { | |
25 if (key.size() != sizeof(key_)) { | |
Ryan Hamilton
2013/03/13 03:28:17
Should this be a DCHECK?
wtc
2013/03/13 19:08:07
This function returns bool, so we can do real erro
Ryan Hamilton
2013/03/13 22:06:10
I guess my real question is "under what circumstan
wtc
2013/03/13 22:59:16
It can be a programmer error. But you can also ima
| |
26 return false; | |
27 } | |
28 memcpy(key_, key.data(), key.size()); | |
29 return true; | |
30 } | |
31 | |
32 bool Aes128GcmDecrypter::SetNoncePrefix(StringPiece nonce_prefix) { | |
33 if (nonce_prefix.size() != kNoncePrefixSize) { | |
Ryan Hamilton
2013/03/13 03:28:17
ditto.
| |
34 return false; | |
35 } | |
36 memcpy(nonce_, nonce_prefix.data(), nonce_prefix.size()); | |
37 return true; | |
38 } | |
39 | |
40 QuicData* Aes128GcmDecrypter::Decrypt(QuicPacketSequenceNumber sequence_number, | |
41 StringPiece associated_data, | |
42 StringPiece ciphertext) { | |
43 COMPILE_ASSERT(sizeof(nonce_) == kNoncePrefixSize + sizeof(sequence_number), | |
44 incorrect_nonce_size); | |
45 memcpy(nonce_ + kNoncePrefixSize, &sequence_number, sizeof(sequence_number)); | |
46 return DecryptWithNonce(StringPiece(reinterpret_cast<char*>(nonce_), | |
47 sizeof(nonce_)), | |
48 associated_data, ciphertext); | |
49 } | |
50 | |
51 QuicData* Aes128GcmDecrypter::DecryptWithNonce(StringPiece nonce, | |
52 StringPiece associated_data, | |
53 StringPiece ciphertext) { | |
54 if (ciphertext.length() < kAuthTagSize) { | |
55 return NULL; | |
56 } | |
57 size_t plaintext_size = ciphertext.length() - kAuthTagSize; | |
58 scoped_ptr<char[]> plaintext(new char[plaintext_size]); | |
59 | |
60 // |output| points to the position in the |plaintext| buffer to receive | |
61 // the next output. | |
62 unsigned char* output = reinterpret_cast<unsigned char*>(plaintext.get()); | |
63 // |output_len| is passed to an OpenSSL function to receive the output | |
64 // length. | |
65 int output_len; | |
66 | |
67 ScopedEVPCipherCtx ctx; | |
68 | |
69 // Set the cipher type and the key. The IV (nonce) is set below. | |
70 if (EVP_DecryptInit_ex(ctx.get(), EVP_aes_128_gcm(), NULL, key_, | |
71 NULL) == 0) { | |
72 return NULL; | |
73 } | |
74 | |
75 // Set the IV (nonce) length. | |
76 if (EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_IVLEN, nonce.size(), | |
77 NULL) == 0) { | |
78 return NULL; | |
79 } | |
80 // Set the IV (nonce). | |
81 if (EVP_DecryptInit_ex(ctx.get(), NULL, NULL, NULL, | |
82 reinterpret_cast<const unsigned char*>( | |
83 nonce.data())) == 0) { | |
84 return NULL; | |
85 } | |
86 | |
87 // Set the authentication tag. | |
88 if (EVP_CIPHER_CTX_ctrl(ctx.get(), EVP_CTRL_GCM_SET_TAG, kAuthTagSize, | |
89 const_cast<char*>(ciphertext.data()) + | |
90 plaintext_size) == 0) { | |
91 return NULL; | |
92 } | |
93 | |
94 // Set the associated data. The second argument (output buffer) must be | |
95 // NULL. | |
96 if (EVP_DecryptUpdate(ctx.get(), NULL, &output_len, | |
97 reinterpret_cast<const unsigned char*>( | |
98 associated_data.data()), | |
99 associated_data.size()) == 0) { | |
100 return NULL; | |
101 } | |
102 | |
103 if (EVP_DecryptUpdate(ctx.get(), output, &output_len, | |
104 reinterpret_cast<const unsigned char*>( | |
105 ciphertext.data()), | |
106 plaintext_size) == 0) { | |
107 return NULL; | |
108 } | |
109 output += output_len; | |
110 | |
111 if (EVP_DecryptFinal_ex(ctx.get(), output, &output_len) == 0) { | |
112 return NULL; | |
113 } | |
114 output += output_len; | |
115 | |
116 return new QuicData(plaintext.release(), plaintext_size, true); | |
117 } | |
118 | |
119 } // namespace net | |
OLD | NEW |