OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/gcm_driver/crypto/gcm_message_cryptographer.h" | 5 #include "components/gcm_driver/crypto/gcm_message_cryptographer.h" |
6 | 6 |
7 #include <openssl/aead.h> | |
8 #include <stddef.h> | |
9 #include <stdint.h> | |
10 | |
7 #include <algorithm> | 11 #include <algorithm> |
8 #include <sstream> | 12 #include <sstream> |
9 | 13 |
10 #include "base/logging.h" | 14 #include "base/logging.h" |
15 #include "base/numerics/safe_math.h" | |
16 #include "base/strings/string_util.h" | |
11 #include "base/sys_byteorder.h" | 17 #include "base/sys_byteorder.h" |
12 #include "crypto/hkdf.h" | 18 #include "crypto/hkdf.h" |
13 | 19 |
14 namespace gcm { | 20 namespace gcm { |
15 namespace { | 21 namespace { |
16 | 22 |
17 // Size, in bytes, of the nonce for a record. This must be at least the size | 23 // Size, in bytes, of the nonce for a record. This must be at least the size |
18 // of a uint64_t, which is used to indicate the record sequence number. | 24 // of a uint64_t, which is used to indicate the record sequence number. |
19 const uint64_t kNonceSize = 12; | 25 const uint64_t kNonceSize = 12; |
20 | 26 |
21 // The default record size as defined by draft-thomson-http-encryption. | 27 // The default record size as defined by draft-thomson-http-encryption. |
22 const size_t kDefaultRecordSize = 4096; | 28 const size_t kDefaultRecordSize = 4096; |
23 | 29 |
24 // Key size, in bytes, of a valid AEAD_AES_128_GCM key. | 30 // Key size, in bytes, of a valid AEAD_AES_128_GCM key. |
25 const size_t kContentEncryptionKeySize = 16; | 31 const size_t kContentEncryptionKeySize = 16; |
26 | 32 |
33 // The BoringSSL functions used to seal (encrypt) and open (decrypt) a payload | |
34 // follow the same prototype, declared as follows. | |
35 using EVP_AEAD_CTX_TransformFunction = | |
36 int(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len, | |
37 size_t max_out_len, const uint8_t *nonce, size_t nonce_len, | |
38 const uint8_t *in, size_t in_len, const uint8_t *ad, size_t ad_len); | |
39 | |
27 // Creates the info parameter for an HKDF value for the given |content_encoding| | 40 // Creates the info parameter for an HKDF value for the given |content_encoding| |
28 // in accordance with draft-thomson-http-encryption. | 41 // in accordance with draft-thomson-http-encryption. |
29 // | 42 // |
30 // cek_info = "Content-Encoding: aesgcm" || 0x00 || context | 43 // cek_info = "Content-Encoding: aesgcm" || 0x00 || context |
31 // nonce_info = "Content-Encoding: nonce" || 0x00 || context | 44 // nonce_info = "Content-Encoding: nonce" || 0x00 || context |
32 // | 45 // |
33 // context = label || 0x00 || | 46 // context = label || 0x00 || |
34 // length(recipient_public) || recipient_public || | 47 // length(recipient_public) || recipient_public || |
35 // length(sender_public) || sender_public | 48 // length(sender_public) || sender_public |
36 // | 49 // |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
183 for (size_t i = 0; i < padding_length; ++i) { | 196 for (size_t i = 0; i < padding_length; ++i) { |
184 if (decrypted_record[i] != 0) | 197 if (decrypted_record[i] != 0) |
185 return false; | 198 return false; |
186 } | 199 } |
187 | 200 |
188 decrypted_record.remove_prefix(padding_length); | 201 decrypted_record.remove_prefix(padding_length); |
189 decrypted_record.CopyToString(plaintext); | 202 decrypted_record.CopyToString(plaintext); |
190 return true; | 203 return true; |
191 } | 204 } |
192 | 205 |
206 bool GCMMessageCryptographer::EncryptDecryptRecordInternal( | |
Peter Beverloo
2016/04/22 15:08:35
Would you mind updating the comment for EncryptDec
| |
207 Mode mode, | |
208 const base::StringPiece& input, | |
209 const base::StringPiece& key, | |
210 const base::StringPiece& nonce, | |
211 std::string* output) const { | |
212 DCHECK(output); | |
213 | |
214 const EVP_AEAD* aead = EVP_aead_aes_128_gcm(); | |
215 | |
216 EVP_AEAD_CTX context; | |
217 if (!EVP_AEAD_CTX_init(&context, aead, | |
218 reinterpret_cast<const uint8_t*>(key.data()), | |
219 key.size(), EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr)) { | |
220 return false; | |
221 } | |
222 | |
223 base::CheckedNumeric<size_t> maximum_output_length(input.size()); | |
224 if (mode == ENCRYPT) | |
225 maximum_output_length += kAuthenticationTagBytes; | |
226 | |
227 // WriteInto requires the buffer to finish with a NULL-byte. | |
228 maximum_output_length += 1; | |
229 | |
230 size_t output_length = 0; | |
231 uint8_t* raw_output = reinterpret_cast<uint8_t*>( | |
232 base::WriteInto(output, maximum_output_length.ValueOrDie())); | |
233 | |
234 EVP_AEAD_CTX_TransformFunction* transform_function = | |
235 mode == ENCRYPT ? EVP_AEAD_CTX_seal : EVP_AEAD_CTX_open; | |
236 | |
237 if (!transform_function( | |
238 &context, raw_output, &output_length, output->size(), | |
239 reinterpret_cast<const uint8_t*>(nonce.data()), nonce.size(), | |
240 reinterpret_cast<const uint8_t*>(input.data()), input.size(), | |
241 nullptr, 0)) { | |
242 EVP_AEAD_CTX_cleanup(&context); | |
243 return false; | |
244 } | |
245 | |
246 EVP_AEAD_CTX_cleanup(&context); | |
247 | |
248 base::CheckedNumeric<size_t> expected_output_length(input.size()); | |
249 if (mode == ENCRYPT) | |
250 expected_output_length += kAuthenticationTagBytes; | |
251 else | |
252 expected_output_length -= kAuthenticationTagBytes; | |
253 | |
254 DCHECK_EQ(expected_output_length.ValueOrDie(), output_length); | |
255 | |
256 output->resize(output_length); | |
257 return true; | |
258 } | |
259 | |
193 std::string GCMMessageCryptographer::DerivePseudoRandomKey( | 260 std::string GCMMessageCryptographer::DerivePseudoRandomKey( |
194 const base::StringPiece& ikm) const { | 261 const base::StringPiece& ikm) const { |
195 if (allow_empty_auth_secret_for_tests_ && auth_secret_.empty()) | 262 if (allow_empty_auth_secret_for_tests_ && auth_secret_.empty()) |
196 return ikm.as_string(); | 263 return ikm.as_string(); |
197 | 264 |
198 CHECK(!auth_secret_.empty()); | 265 CHECK(!auth_secret_.empty()); |
199 | 266 |
200 std::stringstream info_stream; | 267 std::stringstream info_stream; |
201 info_stream << "Content-Encoding: auth" << '\x00'; | 268 info_stream << "Content-Encoding: auth" << '\x00'; |
202 | 269 |
(...skipping 28 matching lines...) Expand all Loading... | |
231 0 /* subkey_secret_bytes_to_generate */); | 298 0 /* subkey_secret_bytes_to_generate */); |
232 | 299 |
233 // draft-thomson-http-encryption defines that the result should be XOR'ed with | 300 // draft-thomson-http-encryption defines that the result should be XOR'ed with |
234 // the record's sequence number, however, Web Push encryption is limited to a | 301 // the record's sequence number, however, Web Push encryption is limited to a |
235 // single record per draft-ietf-webpush-encryption. | 302 // single record per draft-ietf-webpush-encryption. |
236 | 303 |
237 return hkdf.client_write_key().as_string(); | 304 return hkdf.client_write_key().as_string(); |
238 } | 305 } |
239 | 306 |
240 } // namespace gcm | 307 } // namespace gcm |
OLD | NEW |