Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1331)

Side by Side Diff: components/gcm_driver/crypto/gcm_message_cryptographer.cc

Issue 2713673002: Separate out the scheme from the GCMMessageCryptographer (Closed)
Patch Set: Separate out the scheme from the GCMMessageCryptographer Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 <stddef.h> 7 #include <stddef.h>
8 #include <stdint.h> 8 #include <stdint.h>
9 9
10 #include <algorithm> 10 #include <algorithm>
11 #include <sstream> 11 #include <sstream>
12 12
13 #include "base/logging.h" 13 #include "base/logging.h"
14 #include "base/macros.h"
15 #include "base/memory/ptr_util.h"
14 #include "base/numerics/safe_math.h" 16 #include "base/numerics/safe_math.h"
15 #include "base/strings/string_util.h" 17 #include "base/strings/string_util.h"
16 #include "base/sys_byteorder.h" 18 #include "base/sys_byteorder.h"
17 #include "crypto/hkdf.h" 19 #include "crypto/hkdf.h"
18 #include "third_party/boringssl/src/include/openssl/aead.h" 20 #include "third_party/boringssl/src/include/openssl/aead.h"
19 21
20 namespace gcm { 22 namespace gcm {
23
21 namespace { 24 namespace {
22 25
23 // Size, in bytes, of the nonce for a record. This must be at least the size 26 // Size, in bytes, of the nonce for a record. This must be at least the size
24 // of a uint64_t, which is used to indicate the record sequence number. 27 // of a uint64_t, which is used to indicate the record sequence number.
25 const uint64_t kNonceSize = 12; 28 const uint64_t kNonceSize = 12;
26 29
27 // The default record size as defined by httpbis-encryption-encoding-06. 30 // The default record size as defined by httpbis-encryption-encoding-06.
28 const size_t kDefaultRecordSize = 4096; 31 const size_t kDefaultRecordSize = 4096;
29 32
30 // Key size, in bytes, of a valid AEAD_AES_128_GCM key. 33 // Key size, in bytes, of a valid AEAD_AES_128_GCM key.
31 const size_t kContentEncryptionKeySize = 16; 34 const size_t kContentEncryptionKeySize = 16;
32 35
33 // The BoringSSL functions used to seal (encrypt) and open (decrypt) a payload 36 // The BoringSSL functions used to seal (encrypt) and open (decrypt) a payload
34 // follow the same prototype, declared as follows. 37 // follow the same prototype, declared as follows.
35 using EVP_AEAD_CTX_TransformFunction = 38 using EVP_AEAD_CTX_TransformFunction =
36 int(const EVP_AEAD_CTX *ctx, uint8_t *out, size_t *out_len, 39 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, 40 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); 41 const uint8_t *in, size_t in_len, const uint8_t *ad, size_t ad_len);
39 42
40 // Creates the info parameter for an HKDF value for the given |content_encoding| 43 // Implementation of draft 03 of the Web Push Encryption standard:
41 // in accordance with draft-thomson-http-encryption. 44 // https://tools.ietf.org/html/draft-ietf-webpush-encryption-03
42 // 45 // https://tools.ietf.org/html/draft-ietf-httpbis-encryption-encoding-02
43 // cek_info = "Content-Encoding: aesgcm" || 0x00 || context 46 class WebPushEncryptionDraft03
44 // nonce_info = "Content-Encoding: nonce" || 0x00 || context 47 : public GCMMessageCryptographer::EncryptionScheme {
45 // 48 public:
46 // context = "P-256" || 0x00 || 49 WebPushEncryptionDraft03() = default;
47 // length(recipient_public) || recipient_public || 50 ~WebPushEncryptionDraft03() override = default;
48 // length(sender_public) || sender_public
49 //
50 // The length of the public keys must be written as a two octet unsigned integer
51 // in network byte order (big endian).
52 std::string InfoForContentEncoding(
53 const char* content_encoding,
54 const base::StringPiece& recipient_public_key,
55 const base::StringPiece& sender_public_key) {
56 DCHECK_EQ(recipient_public_key.size(), 65u);
57 DCHECK_EQ(sender_public_key.size(), 65u);
58 51
59 std::stringstream info_stream; 52 // GCMMessageCryptographer::EncryptionScheme implementation.
60 info_stream << "Content-Encoding: " << content_encoding << '\x00'; 53 std::string DerivePseudoRandomKey(
61 info_stream << "P-256" << '\x00'; 54 const base::StringPiece& ecdh_shared_secret,
55 const base::StringPiece& auth_secret) override {
56 std::stringstream info_stream;
57 info_stream << "Content-Encoding: auth" << '\x00';
62 58
63 uint16_t local_len = 59 crypto::HKDF hkdf(ecdh_shared_secret, auth_secret, info_stream.str(),
64 base::HostToNet16(static_cast<uint16_t>(recipient_public_key.size())); 60 32, /* key_bytes_to_generate */
65 info_stream.write(reinterpret_cast<char*>(&local_len), sizeof(local_len)); 61 0, /* iv_bytes_to_generate */
66 info_stream << recipient_public_key; 62 0 /* subkey_secret_bytes_to_generate */);
67 63
68 uint16_t peer_len = 64 return hkdf.client_write_key().as_string();
69 base::HostToNet16(static_cast<uint16_t>(sender_public_key.size())); 65 }
70 info_stream.write(reinterpret_cast<char*>(&peer_len), sizeof(peer_len));
71 info_stream << sender_public_key;
72 66
73 return info_stream.str(); 67 // Creates the info parameter for an HKDF value for the given
74 } 68 // |content_encoding| in accordance with draft-ietf-webpush-encryption-03.
69 //
70 // cek_info = "Content-Encoding: aesgcm" || 0x00 || context
71 // nonce_info = "Content-Encoding: nonce" || 0x00 || context
72 //
73 // context = "P-256" || 0x00 ||
74 // length(recipient_public) || recipient_public ||
75 // length(sender_public) || sender_public
76 //
77 // The length of the public keys must be written as a two octet unsigned
78 // integer in network byte order (big endian).
79 std::string GenerateInfoForContentEncoding(
80 EncodingType type,
81 const base::StringPiece& recipient_public_key,
82 const base::StringPiece& sender_public_key) override {
83 std::stringstream info_stream;
84 info_stream << "Content-Encoding: ";
85
86 switch (type) {
87 case EncodingType::CONTENT_ENCRYPTION_KEY:
88 info_stream << "aesgcm";
89 break;
90 case EncodingType::NONCE:
91 info_stream << "nonce";
92 break;
93 }
94
95 info_stream << '\x00' << "P-256" << '\x00';
96
97 uint16_t local_len =
98 base::HostToNet16(static_cast<uint16_t>(recipient_public_key.size()));
99 info_stream.write(reinterpret_cast<char*>(&local_len), sizeof(local_len));
100 info_stream << recipient_public_key;
101
102 uint16_t peer_len =
103 base::HostToNet16(static_cast<uint16_t>(sender_public_key.size()));
104 info_stream.write(reinterpret_cast<char*>(&peer_len), sizeof(peer_len));
105 info_stream << sender_public_key;
106
107 return info_stream.str();
108 }
109
110 // draft-ietf-webpush-encryption-03 defines that the padding is included at
111 // the beginning of the message. The first two bytes, in network byte order,
112 // contain the length of the included padding. Then that exact number of bytes
113 // must follow as padding, all of which must have a zero value.
114 //
115 // TODO(peter): Add support for message padding if the GCMMessageCryptographer
116 // starts encrypting payloads for reasons other than testing.
117 std::string CreateRecord(const base::StringPiece& plaintext) override {
118 std::string record;
119 record.reserve(sizeof(uint16_t) + plaintext.size());
120 record.append(sizeof(uint16_t), '\x00');
121
122 plaintext.AppendToString(&record);
123 return record;
124 }
125
126 // The record padding in draft-ietf-webpush-encryption-03 is included at the
127 // beginning of the record. The first two bytes indicate the length of the
128 // padding. All padding bytes immediately follow, and must be set to zero.
129 bool ValidateAndRemovePadding(base::StringPiece& record) override {
130 // Records must be at least two octets in size (to hold the padding).
131 // Records that are smaller, i.e. a single octet, are invalid.
132 if (record.size() < sizeof(uint16_t))
133 return false;
134
135 // Records contain a two-byte, big-endian padding length followed by zero to
136 // 65535 bytes of padding. Padding bytes must be zero but, since AES-GCM
137 // authenticates the plaintext, checking and removing padding need not be
138 // done in constant-time.
139 uint16_t padding_length = (static_cast<uint8_t>(record[0]) << 8) |
140 static_cast<uint8_t>(record[1]);
141 record.remove_prefix(sizeof(uint16_t));
142
143 if (padding_length > record.size()) {
144 return false;
145 }
146
147 for (size_t i = 0; i < padding_length; ++i) {
148 if (record[i] != 0)
149 return false;
150 }
151
152 record.remove_prefix(padding_length);
153 return true;
154 }
155
156 private:
157 DISALLOW_COPY_AND_ASSIGN(WebPushEncryptionDraft03);
158 };
75 159
76 } // namespace 160 } // namespace
77 161
78 const size_t GCMMessageCryptographer::kAuthenticationTagBytes = 16; 162 const size_t GCMMessageCryptographer::kAuthenticationTagBytes = 16;
79 const size_t GCMMessageCryptographer::kSaltSize = 16; 163 const size_t GCMMessageCryptographer::kSaltSize = 16;
80 164
81 GCMMessageCryptographer::GCMMessageCryptographer( 165 GCMMessageCryptographer::GCMMessageCryptographer(Version version) {
166 switch (version) {
martijnc 2017/03/28 16:26:36 nit: I think switch (version) { case Version::D
Peter Beverloo 2017/04/07 17:48:21 Not having a `default` clause gives us compile-tim
167 case Version::DRAFT_03:
168 encryption_scheme_ = base::MakeUnique<WebPushEncryptionDraft03>();
169 return;
170 }
171
172 NOTREACHED();
173 }
174
175 GCMMessageCryptographer::~GCMMessageCryptographer() = default;
176
177 bool GCMMessageCryptographer::Encrypt(
82 const base::StringPiece& recipient_public_key, 178 const base::StringPiece& recipient_public_key,
83 const base::StringPiece& sender_public_key, 179 const base::StringPiece& sender_public_key,
84 const std::string& auth_secret) 180 const base::StringPiece& ecdh_shared_secret,
85 : content_encryption_key_info_( 181 const base::StringPiece& auth_secret,
86 InfoForContentEncoding("aesgcm", recipient_public_key, 182 const base::StringPiece& salt,
87 sender_public_key)), 183 const base::StringPiece& plaintext,
88 nonce_info_( 184 size_t* record_size,
89 InfoForContentEncoding("nonce", recipient_public_key, 185 std::string* ciphertext) const {
90 sender_public_key)), 186 DCHECK_EQ(recipient_public_key.size(), 65u);
91 auth_secret_(auth_secret) { 187 DCHECK_EQ(sender_public_key.size(), 65u);
92 } 188 DCHECK(record_size);
189 DCHECK(ciphertext);
93 190
94 GCMMessageCryptographer::~GCMMessageCryptographer() {} 191 // TODO(peter): DCHECK the lengths of |ecdh_shared_secret|, |auth_secret| and
95 192 // |salt|.
96 bool GCMMessageCryptographer::Encrypt(const base::StringPiece& plaintext,
97 const base::StringPiece& ikm,
98 const base::StringPiece& salt,
99 size_t* record_size,
100 std::string* ciphertext) const {
101 DCHECK(ciphertext);
102 DCHECK(record_size);
103 193
104 if (salt.size() != kSaltSize) 194 if (salt.size() != kSaltSize)
105 return false; 195 return false;
106 196
107 std::string prk = DerivePseudoRandomKey(ikm); 197 std::string prk = encryption_scheme_->DerivePseudoRandomKey(
198 ecdh_shared_secret, auth_secret);
108 199
109 std::string content_encryption_key = DeriveContentEncryptionKey(prk, salt); 200 std::string content_encryption_key = DeriveContentEncryptionKey(
110 std::string nonce = DeriveNonce(prk, salt); 201 recipient_public_key, sender_public_key, prk, salt);
202 std::string nonce =
203 DeriveNonce(recipient_public_key, sender_public_key, prk, salt);
111 204
112 // Prior to the plaintext, draft-thomson-http-encryption has a two-byte 205 std::string record = encryption_scheme_->CreateRecord(plaintext);
113 // padding length followed by zero to 65535 bytes of padding. There is no need 206 std::string encrypted_record;
114 // for payloads created by Chrome to be padded so the padding length is set to
115 // zero.
116 std::string record;
117 record.reserve(sizeof(uint16_t) + plaintext.size());
118 record.append(sizeof(uint16_t), '\0');
119 207
120 plaintext.AppendToString(&record); 208 if (!TransformRecord(Direction::ENCRYPT, record, content_encryption_key,
121 209 nonce, &encrypted_record)) {
122 std::string encrypted_record;
123 if (!EncryptDecryptRecordInternal(ENCRYPT, record, content_encryption_key,
124 nonce, &encrypted_record)) {
125 return false; 210 return false;
126 } 211 }
127 212
128 // The advertised record size must be at least one more than the padded 213 // The advertised record size must be at least one more than the padded
129 // plaintext to ensure only one record. 214 // plaintext to ensure only one record.
130 *record_size = std::max(kDefaultRecordSize, record.size() + 1); 215 *record_size = std::max(kDefaultRecordSize, record.size() + 1);
131 216
132 ciphertext->swap(encrypted_record); 217 ciphertext->swap(encrypted_record);
133 return true; 218 return true;
134 } 219 }
135 220
136 bool GCMMessageCryptographer::Decrypt(const base::StringPiece& ciphertext, 221 bool GCMMessageCryptographer::Decrypt(
137 const base::StringPiece& ikm, 222 const base::StringPiece& recipient_public_key,
138 const base::StringPiece& salt, 223 const base::StringPiece& sender_public_key,
139 size_t record_size, 224 const base::StringPiece& ecdh_shared_secret,
140 std::string* plaintext) const { 225 const base::StringPiece& auth_secret,
226 const base::StringPiece& salt,
227 const base::StringPiece& ciphertext,
228 size_t record_size,
229 std::string* plaintext) const {
230 DCHECK_EQ(recipient_public_key.size(), 65u);
231 DCHECK_EQ(sender_public_key.size(), 65u);
141 DCHECK(plaintext); 232 DCHECK(plaintext);
142 233
143 if (salt.size() != kSaltSize || record_size <= 1) 234 // TODO(peter): DCHECK the lengths of |ecdh_shared_secret|, |auth_secret| and
235 // |salt|.
236
237 if (record_size <= 1)
144 return false; 238 return false;
145 239
146 // The |ciphertext| must be at least of size kAuthenticationTagBytes plus 240 std::string prk = encryption_scheme_->DerivePseudoRandomKey(
147 // len(uint16) to hold the message's padding length, which is the case when an 241 ecdh_shared_secret, auth_secret);
148 // empty message with a zero padding length has been received. Per 242
149 // https://tools.ietf.org/html/draft-thomson-http-encryption-02#section-3, the 243 std::string content_encryption_key = DeriveContentEncryptionKey(
150 // |record_size| parameter must be large enough to use only one record. 244 recipient_public_key, sender_public_key, prk, salt);
151 if (ciphertext.size() < sizeof(uint16_t) + kAuthenticationTagBytes || 245
246 std::string nonce =
247 DeriveNonce(recipient_public_key, sender_public_key, prk, salt);
248
249 // The |ciphertext| must be at least of size kAuthenticationTagBytes, which
250 // is the case when an empty message with a zero padding length has been
251 // received. The |record_size| must be large enough to use only one record.
252 // https://tools.ietf.org/html/draft-ietf-httpbis-encryption-encoding-03#secti on-2
253 if (ciphertext.size() < kAuthenticationTagBytes ||
152 ciphertext.size() > record_size + kAuthenticationTagBytes) { 254 ciphertext.size() > record_size + kAuthenticationTagBytes) {
153 return false; 255 return false;
154 } 256 }
155 257
156 std::string prk = DerivePseudoRandomKey(ikm);
157
158 std::string content_encryption_key = DeriveContentEncryptionKey(prk, salt);
159 std::string nonce = DeriveNonce(prk, salt);
160
161 std::string decrypted_record_string; 258 std::string decrypted_record_string;
162 if (!EncryptDecryptRecordInternal(DECRYPT, ciphertext, content_encryption_key, 259 if (!TransformRecord(Direction::DECRYPT, ciphertext, content_encryption_key,
163 nonce, &decrypted_record_string)) { 260 nonce, &decrypted_record_string)) {
164 return false; 261 return false;
165 } 262 }
166 263
167 DCHECK(!decrypted_record_string.empty()); 264 DCHECK(!decrypted_record_string.empty());
168 265
169 base::StringPiece decrypted_record(decrypted_record_string); 266 base::StringPiece decrypted_record(decrypted_record_string);
170 267 if (!encryption_scheme_->ValidateAndRemovePadding(decrypted_record))
171 // Records must be at least two octets in size (to hold the padding). Records
172 // that are smaller, i.e. a single octet, are invalid.
173 if (decrypted_record.size() < sizeof(uint16_t))
174 return false; 268 return false;
175 269
176 // Records contain a two-byte, big-endian padding length followed by zero to
177 // 65535 bytes of padding. Padding bytes must be zero but, since AES-GCM
178 // authenticates the plaintext, checking and removing padding need not be done
179 // in constant-time.
180 uint16_t padding_length = (static_cast<uint8_t>(decrypted_record[0]) << 8) |
181 static_cast<uint8_t>(decrypted_record[1]);
182 decrypted_record.remove_prefix(sizeof(uint16_t));
183
184 if (padding_length > decrypted_record.size()) {
185 return false;
186 }
187
188 for (size_t i = 0; i < padding_length; ++i) {
189 if (decrypted_record[i] != 0)
190 return false;
191 }
192
193 decrypted_record.remove_prefix(padding_length);
194 decrypted_record.CopyToString(plaintext); 270 decrypted_record.CopyToString(plaintext);
195 return true; 271 return true;
196 } 272 }
197 273
198 bool GCMMessageCryptographer::EncryptDecryptRecordInternal( 274 bool GCMMessageCryptographer::TransformRecord(Direction direction,
199 Mode mode, 275 const base::StringPiece& input,
200 const base::StringPiece& input, 276 const base::StringPiece& key,
201 const base::StringPiece& key, 277 const base::StringPiece& nonce,
202 const base::StringPiece& nonce, 278 std::string* output) const {
203 std::string* output) const {
204 DCHECK(output); 279 DCHECK(output);
205 280
206 const EVP_AEAD* aead = EVP_aead_aes_128_gcm(); 281 const EVP_AEAD* aead = EVP_aead_aes_128_gcm();
207 282
208 EVP_AEAD_CTX context; 283 EVP_AEAD_CTX context;
209 if (!EVP_AEAD_CTX_init(&context, aead, 284 if (!EVP_AEAD_CTX_init(&context, aead,
210 reinterpret_cast<const uint8_t*>(key.data()), 285 reinterpret_cast<const uint8_t*>(key.data()),
211 key.size(), EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr)) { 286 key.size(), EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr)) {
212 return false; 287 return false;
213 } 288 }
214 289
215 base::CheckedNumeric<size_t> maximum_output_length(input.size()); 290 base::CheckedNumeric<size_t> maximum_output_length(input.size());
216 if (mode == ENCRYPT) 291 if (direction == Direction::ENCRYPT)
217 maximum_output_length += kAuthenticationTagBytes; 292 maximum_output_length += kAuthenticationTagBytes;
218 293
219 // WriteInto requires the buffer to finish with a NULL-byte. 294 // WriteInto requires the buffer to finish with a NULL-byte.
220 maximum_output_length += 1; 295 maximum_output_length += 1;
221 296
222 size_t output_length = 0; 297 size_t output_length = 0;
223 uint8_t* raw_output = reinterpret_cast<uint8_t*>( 298 uint8_t* raw_output = reinterpret_cast<uint8_t*>(
224 base::WriteInto(output, maximum_output_length.ValueOrDie())); 299 base::WriteInto(output, maximum_output_length.ValueOrDie()));
225 300
226 EVP_AEAD_CTX_TransformFunction* transform_function = 301 EVP_AEAD_CTX_TransformFunction* transform_function =
227 mode == ENCRYPT ? EVP_AEAD_CTX_seal : EVP_AEAD_CTX_open; 302 direction == Direction::ENCRYPT ? EVP_AEAD_CTX_seal : EVP_AEAD_CTX_open;
228 303
229 if (!transform_function( 304 if (!transform_function(
230 &context, raw_output, &output_length, output->size(), 305 &context, raw_output, &output_length, output->size(),
231 reinterpret_cast<const uint8_t*>(nonce.data()), nonce.size(), 306 reinterpret_cast<const uint8_t*>(nonce.data()), nonce.size(),
232 reinterpret_cast<const uint8_t*>(input.data()), input.size(), 307 reinterpret_cast<const uint8_t*>(input.data()), input.size(),
233 nullptr, 0)) { 308 nullptr, 0)) {
234 EVP_AEAD_CTX_cleanup(&context); 309 EVP_AEAD_CTX_cleanup(&context);
235 return false; 310 return false;
236 } 311 }
237 312
238 EVP_AEAD_CTX_cleanup(&context); 313 EVP_AEAD_CTX_cleanup(&context);
239 314
240 base::CheckedNumeric<size_t> expected_output_length(input.size()); 315 base::CheckedNumeric<size_t> expected_output_length(input.size());
241 if (mode == ENCRYPT) 316 if (direction == Direction::ENCRYPT)
242 expected_output_length += kAuthenticationTagBytes; 317 expected_output_length += kAuthenticationTagBytes;
243 else 318 else
244 expected_output_length -= kAuthenticationTagBytes; 319 expected_output_length -= kAuthenticationTagBytes;
245 320
246 DCHECK_EQ(expected_output_length.ValueOrDie(), output_length); 321 DCHECK_EQ(expected_output_length.ValueOrDie(), output_length);
247 322
248 output->resize(output_length); 323 output->resize(output_length);
249 return true; 324 return true;
250 } 325 }
251 326
252 std::string GCMMessageCryptographer::DerivePseudoRandomKey( 327 std::string GCMMessageCryptographer::DeriveContentEncryptionKey(
253 const base::StringPiece& ikm) const { 328 const base::StringPiece& recipient_public_key,
254 if (allow_empty_auth_secret_for_tests_ && auth_secret_.empty()) 329 const base::StringPiece& sender_public_key,
255 return ikm.as_string(); 330 const base::StringPiece& ecdh_shared_secret,
331 const base::StringPiece& salt) const {
332 std::string content_encryption_key_info =
333 encryption_scheme_->GenerateInfoForContentEncoding(
334 EncryptionScheme::EncodingType::CONTENT_ENCRYPTION_KEY,
335 recipient_public_key, sender_public_key);
256 336
257 CHECK(!auth_secret_.empty()); 337 crypto::HKDF hkdf(ecdh_shared_secret, salt, content_encryption_key_info,
258 338 kContentEncryptionKeySize, 0, /* iv_bytes_to_generate */
259 std::stringstream info_stream; 339 0 /* subkey_secret_bytes_to_generate */);
260 info_stream << "Content-Encoding: auth" << '\x00';
261
262 crypto::HKDF hkdf(ikm, auth_secret_,
263 info_stream.str(),
264 32, /* key_bytes_to_generate */
265 0, /* iv_bytes_to_generate */
266 0 /* subkey_secret_bytes_to_generate */);
267
268 return hkdf.client_write_key().as_string();
269 }
270
271 std::string GCMMessageCryptographer::DeriveContentEncryptionKey(
272 const base::StringPiece& prk,
273 const base::StringPiece& salt) const {
274 crypto::HKDF hkdf(prk, salt,
275 content_encryption_key_info_,
276 kContentEncryptionKeySize,
277 0, /* iv_bytes_to_generate */
278 0 /* subkey_secret_bytes_to_generate */);
279 340
280 return hkdf.client_write_key().as_string(); 341 return hkdf.client_write_key().as_string();
281 } 342 }
282 343
283 std::string GCMMessageCryptographer::DeriveNonce( 344 std::string GCMMessageCryptographer::DeriveNonce(
284 const base::StringPiece& prk, 345 const base::StringPiece& recipient_public_key,
346 const base::StringPiece& sender_public_key,
347 const base::StringPiece& ecdh_shared_secret,
285 const base::StringPiece& salt) const { 348 const base::StringPiece& salt) const {
286 crypto::HKDF hkdf(prk, salt, 349 std::string nonce_info = encryption_scheme_->GenerateInfoForContentEncoding(
287 nonce_info_, 350 EncryptionScheme::EncodingType::NONCE, recipient_public_key,
288 kNonceSize, 351 sender_public_key);
289 0, /* iv_bytes_to_generate */
290 0 /* subkey_secret_bytes_to_generate */);
291 352
292 // draft-thomson-http-encryption defines that the result should be XOR'ed with 353 crypto::HKDF hkdf(ecdh_shared_secret, salt, nonce_info, kNonceSize,
293 // the record's sequence number, however, Web Push encryption is limited to a 354 0, /* iv_bytes_to_generate */
294 // single record per draft-ietf-webpush-encryption. 355 0 /* subkey_secret_bytes_to_generate */);
356
357 // draft-ietf-httpbis-encryption-encoding defines that the result should
358 // be XOR'ed with the record's sequence number, however, Web Push encryption
359 // is limited to a single record per draft-ietf-webpush-encryption.
295 360
296 return hkdf.client_write_key().as_string(); 361 return hkdf.client_write_key().as_string();
297 } 362 }
298 363
299 } // namespace gcm 364 } // namespace gcm
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698