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( |
| 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 |