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

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

Issue 1453503002: [NOT FOR REVIEW] Ensure contributory behaviour for Web Push encryption. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@push-renames
Patch Set: Created 5 years, 1 month 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 <algorithm> 7 #include <algorithm>
8 #include <sstream>
8 9
9 #include "base/big_endian.h" 10 #include "base/big_endian.h"
10 #include "base/logging.h" 11 #include "base/logging.h"
11 #include "crypto/hkdf.h" 12 #include "crypto/hkdf.h"
12 13
13 namespace gcm { 14 namespace gcm {
14 namespace { 15 namespace {
15 16
16 // Size, in bytes, of the nonce for a record. This must be at least the size 17 // Size, in bytes, of the nonce for a record. This must be at least the size
17 // of a uint64_t, which is used to indicate the record sequence number. 18 // of a uint64_t, which is used to indicate the record sequence number.
18 const uint64_t kNonceSize = 12; 19 const uint64_t kNonceSize = 12;
19 20
20 // The default record size as defined by draft-thomson-http-encryption-01. 21 // The default record size as defined by draft-thomson-http-encryption-01.
21 const size_t kDefaultRecordSize = 4096; 22 const size_t kDefaultRecordSize = 4096;
22 23
23 // Key size, in bytes, of a valid AEAD_AES_128_GCM key. 24 // Key size, in bytes, of a valid AEAD_AES_128_GCM key.
24 const size_t kContentEncryptionKeySize = 16; 25 const size_t kContentEncryptionKeySize = 16;
25 26
27 // The label of the curve used by Web Push encryption, as mandated by the
28 // draft-ietf-webpush-encryption-01 draft.
29 const char kP256Label[] = "P-256";
30
26 } // namespace 31 } // namespace
27 32
28 const size_t GCMMessageCryptographer::kAuthenticationTagBytes = 16; 33 const size_t GCMMessageCryptographer::kAuthenticationTagBytes = 16;
29 const size_t GCMMessageCryptographer::kSaltSize = 16; 34 const size_t GCMMessageCryptographer::kSaltSize = 16;
30 35
31 GCMMessageCryptographer::GCMMessageCryptographer() {} 36 template <typename I> std::string n2hexstr(I w, size_t hex_len = sizeof(I)<<1) {
37 static const char* digits = "0123456789abcdef";
38 std::string rc(hex_len,'0');
39 for (size_t i=0, j=(hex_len-1)*4 ; i<hex_len; ++i,j-=4)
40 rc[i] = digits[(w>>j) & 0x0f];
41 return rc;
42 }
43
44 GCMMessageCryptographer::GCMMessageCryptographer(
45 const base::StringPiece& local_public_key,
46 const base::StringPiece& peer_public_key) {
47 std::stringstream context_stream;
48 context_stream << '\0' << kP256Label << '\0';
49 context_stream << '\0' << (char)local_public_key.size() << local_public_key;
50 context_stream << '\0' << (char)peer_public_key.size() << peer_public_key;
51
52 // TODO: \0 + size is necessary because the length must be written as a two-
53 // byte integer in big endian byte order.
54
55 // TODO: Without (char) the size is written as two ascii literals: '6' '5',
56 // rather than the binary representation of 0x41.
57
58 nonce_info_ =
59 "Content-Encoding: nonce" + context_stream.str();
60 content_encryption_key_info_ =
61 "Content-Encoding: aesgcm128" + context_stream.str();
62 }
32 63
33 GCMMessageCryptographer::~GCMMessageCryptographer() {} 64 GCMMessageCryptographer::~GCMMessageCryptographer() {}
34 65
35 bool GCMMessageCryptographer::Encrypt(const base::StringPiece& plaintext, 66 bool GCMMessageCryptographer::Encrypt(const base::StringPiece& plaintext,
36 const base::StringPiece& key, 67 const base::StringPiece& key,
37 const base::StringPiece& salt, 68 const base::StringPiece& salt,
38 size_t* record_size, 69 size_t* record_size,
39 std::string* ciphertext) const { 70 std::string* ciphertext) const {
40 DCHECK(ciphertext); 71 DCHECK(ciphertext);
41 DCHECK(record_size); 72 DCHECK(record_size);
(...skipping 28 matching lines...) Expand all
70 } 101 }
71 102
72 bool GCMMessageCryptographer::Decrypt( 103 bool GCMMessageCryptographer::Decrypt(
73 const base::StringPiece& ciphertext, 104 const base::StringPiece& ciphertext,
74 const base::StringPiece& key, 105 const base::StringPiece& key,
75 const base::StringPiece& salt, 106 const base::StringPiece& salt,
76 size_t record_size, 107 size_t record_size,
77 std::string* plaintext) const { 108 std::string* plaintext) const {
78 DCHECK(plaintext); 109 DCHECK(plaintext);
79 110
80 if (salt.size() != kSaltSize || record_size <= 1) 111 if (salt.size() != kSaltSize || record_size <= 1) {
112 LOG(INFO) << "--1";
81 return false; 113 return false;
114 }
82 115
83 // The |ciphertext| must be at least kAuthenticationTagBytes + 1 bytes, which 116 // The |ciphertext| must be at least kAuthenticationTagBytes + 1 bytes, which
84 // would be used for an empty message. Per 117 // would be used for an empty message. Per
85 // https://tools.ietf.org/html/draft-thomson-webpush-encryption-01#section-3, 118 // https://tools.ietf.org/html/draft-thomson-webpush-encryption-01#section-3,
86 // the |record_size| parameter must be large enough to use only one record. 119 // the |record_size| parameter must be large enough to use only one record.
87 if (ciphertext.size() < kAuthenticationTagBytes + 1 || 120 if (ciphertext.size() < kAuthenticationTagBytes + 1 ||
88 ciphertext.size() >= record_size + kAuthenticationTagBytes + 1) { 121 ciphertext.size() >= record_size + kAuthenticationTagBytes + 1) {
122 LOG(INFO) << "--2";
89 return false; 123 return false;
90 } 124 }
91 125
92 std::string content_encryption_key = DeriveContentEncryptionKey(key, salt); 126 std::string content_encryption_key = DeriveContentEncryptionKey(key, salt);
93 std::string nonce = DeriveNonce(key, salt); 127 std::string nonce = DeriveNonce(key, salt);
94 128
95 std::string decrypted_record; 129 std::string decrypted_record;
96 if (!EncryptDecryptRecordInternal(DECRYPT, ciphertext, content_encryption_key, 130 if (!EncryptDecryptRecordInternal(DECRYPT, ciphertext, content_encryption_key,
97 nonce, &decrypted_record)) { 131 nonce, &decrypted_record)) {
132 LOG(INFO) << "--3";
98 return false; 133 return false;
99 } 134 }
100 135
101 DCHECK(!decrypted_record.empty()); 136 DCHECK(!decrypted_record.empty());
102 137
103 // Records can contain between 0 and 255 octets of padding, indicated by the 138 // Records can contain between 0 and 255 octets of padding, indicated by the
104 // first octet of the decrypted message. Padding bytes that are not set to 139 // first octet of the decrypted message. Padding bytes that are not set to
105 // zero are considered a fatal decryption failure as well. Since AES-GCM 140 // zero are considered a fatal decryption failure as well. Since AES-GCM
106 // includes an authentication check, neither verification nor removing the 141 // includes an authentication check, neither verification nor removing the
107 // padding have to be done in constant time. 142 // padding have to be done in constant time.
108 size_t padding_length = static_cast<size_t>(decrypted_record[0]); 143 size_t padding_length = static_cast<size_t>(decrypted_record[0]);
109 if (padding_length >= decrypted_record.size()) 144 if (padding_length >= decrypted_record.size()) {
145 LOG(INFO) << "--4";
110 return false; 146 return false;
147 }
111 148
112 for (size_t i = 1; i <= padding_length; ++i) { 149 for (size_t i = 1; i <= padding_length; ++i) {
113 if (decrypted_record[i] != 0) 150 if (decrypted_record[i] != 0) {
151 LOG(INFO) << "--5";
114 return false; 152 return false;
153 }
115 } 154 }
116 155
117 base::StringPiece decoded_record_string_piece(decrypted_record); 156 base::StringPiece decoded_record_string_piece(decrypted_record);
118 decoded_record_string_piece.remove_prefix(1 + padding_length); 157 decoded_record_string_piece.remove_prefix(1 + padding_length);
119 decoded_record_string_piece.CopyToString(plaintext); 158 decoded_record_string_piece.CopyToString(plaintext);
120 159
121 return true; 160 return true;
122 } 161 }
123 162
124 std::string GCMMessageCryptographer::DeriveContentEncryptionKey( 163 std::string GCMMessageCryptographer::DeriveContentEncryptionKey(
125 const base::StringPiece& key, 164 const base::StringPiece& key,
126 const base::StringPiece& salt) const { 165 const base::StringPiece& salt) const {
127 crypto::HKDF hkdf(key, salt, 166 crypto::HKDF hkdf(key, salt,
128 "Content-Encoding: aesgcm128", 167 content_encryption_key_info_,
129 kContentEncryptionKeySize, 168 kContentEncryptionKeySize,
130 0, /* iv_bytes_to_generate */ 169 0, /* iv_bytes_to_generate */
131 0 /* subkey_secret_bytes_to_generate */); 170 0 /* subkey_secret_bytes_to_generate */);
132 171
133 return hkdf.client_write_key().as_string(); 172 return hkdf.client_write_key().as_string();
134 } 173 }
135 174
136 std::string GCMMessageCryptographer::DeriveNonce( 175 std::string GCMMessageCryptographer::DeriveNonce(
137 const base::StringPiece& key, 176 const base::StringPiece& key,
138 const base::StringPiece& salt) const { 177 const base::StringPiece& salt) const {
139 crypto::HKDF hkdf(key, salt, 178 crypto::HKDF hkdf(key, salt,
140 "Content-Encoding: nonce", 179 nonce_info_,
141 kNonceSize, 180 kNonceSize,
142 0, /* iv_bytes_to_generate */ 181 0, /* iv_bytes_to_generate */
143 0 /* subkey_secret_bytes_to_generate */); 182 0 /* subkey_secret_bytes_to_generate */);
144 183
145 // draft-thomson-http-encryption-01 defines that the result should be XOR'ed 184 // draft-thomson-http-encryption-01 defines that the result should be XOR'ed
146 // with the record's sequence number, but because Web Push encryption is 185 // with the record's sequence number, but because Web Push encryption is
147 // limited to a single record we do not have to do that. 186 // limited to a single record we do not have to do that.
148 187
149 return hkdf.client_write_key().as_string(); 188 return hkdf.client_write_key().as_string();
150 } 189 }
151 190
152 } // namespace gcm 191 } // namespace gcm
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698