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_encryption_provider.h" | 5 #include "components/gcm_driver/crypto/gcm_encryption_provider.h" |
6 | 6 |
7 #include <vector> | 7 #include <vector> |
8 | 8 |
9 #include "base/base64.h" | 9 #include "base/base64.h" |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 11 matching lines...) Expand all Loading... |
22 | 22 |
23 const char kEncryptionProperty[] = "encryption"; | 23 const char kEncryptionProperty[] = "encryption"; |
24 const char kCryptoKeyProperty[] = "crypto-key"; | 24 const char kCryptoKeyProperty[] = "crypto-key"; |
25 | 25 |
26 // Directory in the GCM Store in which the encryption database will be stored. | 26 // Directory in the GCM Store in which the encryption database will be stored. |
27 const base::FilePath::CharType kEncryptionDirectoryName[] = | 27 const base::FilePath::CharType kEncryptionDirectoryName[] = |
28 FILE_PATH_LITERAL("Encryption"); | 28 FILE_PATH_LITERAL("Encryption"); |
29 | 29 |
30 } // namespace | 30 } // namespace |
31 | 31 |
32 std::string GCMEncryptionProvider::ToDecryptionFailureDetailsString( | 32 std::string GCMEncryptionProvider::ToDecryptionResultDetailsString( |
33 DecryptionFailure reason) { | 33 DecryptionResult result) { |
34 switch(reason) { | 34 switch(result) { |
35 case DECRYPTION_FAILURE_UNKNOWN: | 35 case DECRYPTION_RESULT_UNENCRYPTED: |
36 return "Unknown failure"; | 36 return "Message was not encrypted"; |
37 case DECRYPTION_FAILURE_INVALID_ENCRYPTION_HEADER: | 37 case DECRYPTION_RESULT_DECRYPTED: |
| 38 return "Message decrypted"; |
| 39 case DECRYPTION_RESULT_INVALID_ENCRYPTION_HEADER: |
38 return "Invalid format for the Encryption header"; | 40 return "Invalid format for the Encryption header"; |
39 case DECRYPTION_FAILURE_INVALID_CRYPTO_KEY_HEADER: | 41 case DECRYPTION_RESULT_INVALID_CRYPTO_KEY_HEADER: |
40 return "Invalid format for the Crypto-Key header"; | 42 return "Invalid format for the Crypto-Key header"; |
41 case DECRYPTION_FAILURE_NO_KEYS: | 43 case DECRYPTION_RESULT_NO_KEYS: |
42 return "There are no associated keys with the subscription"; | 44 return "There are no associated keys with the subscription"; |
43 case DECRYPTION_FAILURE_INVALID_PUBLIC_KEY: | 45 case DECRYPTION_RESULT_INVALID_SHARED_SECRET: |
44 return "The public key in the Crypto-Key header is invalid"; | 46 return "The shared secret cannot be derived from the keying material"; |
45 case DECRYPTION_FAILURE_INVALID_PAYLOAD: | 47 case DECRYPTION_RESULT_INVALID_PAYLOAD: |
46 return "AES-GCM decryption failed"; | 48 return "AES-GCM decryption failed"; |
47 } | 49 } |
48 | 50 |
49 NOTREACHED(); | 51 NOTREACHED(); |
50 return "(invalid reason)"; | 52 return "(invalid result)"; |
51 } | 53 } |
52 | 54 |
53 GCMEncryptionProvider::GCMEncryptionProvider() | 55 GCMEncryptionProvider::GCMEncryptionProvider() |
54 : weak_ptr_factory_(this) { | 56 : weak_ptr_factory_(this) { |
55 } | 57 } |
56 | 58 |
57 GCMEncryptionProvider::~GCMEncryptionProvider() { | 59 GCMEncryptionProvider::~GCMEncryptionProvider() { |
58 } | 60 } |
59 | 61 |
60 void GCMEncryptionProvider::Init( | 62 void GCMEncryptionProvider::Init( |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
96 if (message.data.find(kEncryptionProperty) == message.data.end() || | 98 if (message.data.find(kEncryptionProperty) == message.data.end() || |
97 message.data.find(kCryptoKeyProperty) == message.data.end()) | 99 message.data.find(kCryptoKeyProperty) == message.data.end()) |
98 return false; | 100 return false; |
99 | 101 |
100 return message.raw_data.size() > 0; | 102 return message.raw_data.size() > 0; |
101 } | 103 } |
102 | 104 |
103 void GCMEncryptionProvider::DecryptMessage( | 105 void GCMEncryptionProvider::DecryptMessage( |
104 const std::string& app_id, | 106 const std::string& app_id, |
105 const IncomingMessage& message, | 107 const IncomingMessage& message, |
106 const MessageDecryptedCallback& success_callback, | 108 const MessageCallback& callback) { |
107 const DecryptionFailedCallback& failure_callback) { | |
108 DCHECK(key_store_); | 109 DCHECK(key_store_); |
| 110 if (!IsEncryptedMessage(message)) { |
| 111 callback.Run(DECRYPTION_RESULT_UNENCRYPTED, message); |
| 112 return; |
| 113 } |
109 | 114 |
| 115 // IsEncryptedMessage() verifies that both the Encryption and Crypto-Key HTTP |
| 116 // headers have been provided for the |message|. |
110 const auto& encryption_header = message.data.find(kEncryptionProperty); | 117 const auto& encryption_header = message.data.find(kEncryptionProperty); |
111 const auto& crypto_key_header = message.data.find(kCryptoKeyProperty); | 118 const auto& crypto_key_header = message.data.find(kCryptoKeyProperty); |
112 | 119 |
113 // Callers are expected to call IsEncryptedMessage() prior to this method. | |
114 DCHECK(encryption_header != message.data.end()); | 120 DCHECK(encryption_header != message.data.end()); |
115 DCHECK(crypto_key_header != message.data.end()); | 121 DCHECK(crypto_key_header != message.data.end()); |
116 | 122 |
117 std::vector<EncryptionHeaderValues> encryption_header_values; | 123 std::vector<EncryptionHeaderValues> encryption_header_values; |
118 if (!ParseEncryptionHeader(encryption_header->second, | 124 if (!ParseEncryptionHeader(encryption_header->second, |
119 &encryption_header_values)) { | 125 &encryption_header_values)) { |
120 DLOG(ERROR) << "Unable to parse the value of the Encryption header"; | 126 DLOG(ERROR) << "Unable to parse the value of the Encryption header"; |
121 failure_callback.Run(DECRYPTION_FAILURE_INVALID_ENCRYPTION_HEADER); | 127 callback.Run(DECRYPTION_RESULT_INVALID_ENCRYPTION_HEADER, |
| 128 IncomingMessage()); |
122 return; | 129 return; |
123 } | 130 } |
124 | 131 |
125 if (encryption_header_values.size() != 1u || | 132 if (encryption_header_values.size() != 1u || |
126 encryption_header_values[0].salt.size() != | 133 encryption_header_values[0].salt.size() != |
127 GCMMessageCryptographer::kSaltSize) { | 134 GCMMessageCryptographer::kSaltSize) { |
128 DLOG(ERROR) << "Invalid values supplied in the Encryption header"; | 135 DLOG(ERROR) << "Invalid values supplied in the Encryption header"; |
129 failure_callback.Run(DECRYPTION_FAILURE_INVALID_ENCRYPTION_HEADER); | 136 callback.Run(DECRYPTION_RESULT_INVALID_ENCRYPTION_HEADER, |
| 137 IncomingMessage()); |
130 return; | 138 return; |
131 } | 139 } |
132 | 140 |
133 std::vector<CryptoKeyHeaderValues> crypto_key_header_values; | 141 std::vector<CryptoKeyHeaderValues> crypto_key_header_values; |
134 if (!ParseCryptoKeyHeader(crypto_key_header->second, | 142 if (!ParseCryptoKeyHeader(crypto_key_header->second, |
135 &crypto_key_header_values)) { | 143 &crypto_key_header_values)) { |
136 DLOG(ERROR) << "Unable to parse the value of the Crypto-Key header"; | 144 DLOG(ERROR) << "Unable to parse the value of the Crypto-Key header"; |
137 failure_callback.Run(DECRYPTION_FAILURE_INVALID_CRYPTO_KEY_HEADER); | 145 callback.Run(DECRYPTION_RESULT_INVALID_CRYPTO_KEY_HEADER, |
| 146 IncomingMessage()); |
138 return; | 147 return; |
139 } | 148 } |
140 | 149 |
141 if (crypto_key_header_values.size() != 1u || | 150 if (crypto_key_header_values.size() != 1u || |
142 !crypto_key_header_values[0].dh.size()) { | 151 !crypto_key_header_values[0].dh.size()) { |
143 DLOG(ERROR) << "Invalid values supplied in the Crypto-Key header"; | 152 DLOG(ERROR) << "Invalid values supplied in the Crypto-Key header"; |
144 failure_callback.Run(DECRYPTION_FAILURE_INVALID_CRYPTO_KEY_HEADER); | 153 callback.Run(DECRYPTION_RESULT_INVALID_CRYPTO_KEY_HEADER, |
| 154 IncomingMessage()); |
145 return; | 155 return; |
146 } | 156 } |
147 | 157 |
148 key_store_->GetKeys( | 158 key_store_->GetKeys( |
149 app_id, base::Bind(&GCMEncryptionProvider::DecryptMessageWithKey, | 159 app_id, base::Bind(&GCMEncryptionProvider::DecryptMessageWithKey, |
150 weak_ptr_factory_.GetWeakPtr(), message, | 160 weak_ptr_factory_.GetWeakPtr(), message, |
151 success_callback, failure_callback, | 161 callback, encryption_header_values[0].salt, |
152 encryption_header_values[0].salt, | |
153 crypto_key_header_values[0].dh, | 162 crypto_key_header_values[0].dh, |
154 encryption_header_values[0].rs)); | 163 encryption_header_values[0].rs)); |
155 } | 164 } |
156 | 165 |
157 void GCMEncryptionProvider::DidGetEncryptionInfo( | 166 void GCMEncryptionProvider::DidGetEncryptionInfo( |
158 const std::string& app_id, | 167 const std::string& app_id, |
159 const EncryptionInfoCallback& callback, | 168 const EncryptionInfoCallback& callback, |
160 const KeyPair& pair, | 169 const KeyPair& pair, |
161 const std::string& auth_secret) { | 170 const std::string& auth_secret) { |
162 if (!pair.IsInitialized()) { | 171 if (!pair.IsInitialized()) { |
(...skipping 16 matching lines...) Expand all Loading... |
179 std::string() /* auth_secret */); | 188 std::string() /* auth_secret */); |
180 return; | 189 return; |
181 } | 190 } |
182 | 191 |
183 DCHECK_EQ(KeyPair::ECDH_P256, pair.type()); | 192 DCHECK_EQ(KeyPair::ECDH_P256, pair.type()); |
184 callback.Run(pair.public_key(), auth_secret); | 193 callback.Run(pair.public_key(), auth_secret); |
185 } | 194 } |
186 | 195 |
187 void GCMEncryptionProvider::DecryptMessageWithKey( | 196 void GCMEncryptionProvider::DecryptMessageWithKey( |
188 const IncomingMessage& message, | 197 const IncomingMessage& message, |
189 const MessageDecryptedCallback& success_callback, | 198 const MessageCallback& callback, |
190 const DecryptionFailedCallback& failure_callback, | |
191 const std::string& salt, | 199 const std::string& salt, |
192 const std::string& dh, | 200 const std::string& dh, |
193 uint64_t rs, | 201 uint64_t rs, |
194 const KeyPair& pair, | 202 const KeyPair& pair, |
195 const std::string& auth_secret) { | 203 const std::string& auth_secret) { |
196 if (!pair.IsInitialized()) { | 204 if (!pair.IsInitialized()) { |
197 DLOG(ERROR) << "Unable to retrieve the keys for the incoming message."; | 205 DLOG(ERROR) << "Unable to retrieve the keys for the incoming message."; |
198 failure_callback.Run(DECRYPTION_FAILURE_NO_KEYS); | 206 callback.Run(DECRYPTION_RESULT_NO_KEYS, IncomingMessage()); |
199 return; | 207 return; |
200 } | 208 } |
201 | 209 |
202 DCHECK_EQ(KeyPair::ECDH_P256, pair.type()); | 210 DCHECK_EQ(KeyPair::ECDH_P256, pair.type()); |
203 | 211 |
204 std::string shared_secret; | 212 std::string shared_secret; |
205 if (!ComputeSharedP256Secret(pair.private_key(), pair.public_key_x509(), dh, | 213 if (!ComputeSharedP256Secret(pair.private_key(), pair.public_key_x509(), dh, |
206 &shared_secret)) { | 214 &shared_secret)) { |
207 DLOG(ERROR) << "Unable to calculate the shared secret."; | 215 DLOG(ERROR) << "Unable to calculate the shared secret."; |
208 failure_callback.Run(DECRYPTION_FAILURE_INVALID_PUBLIC_KEY); | 216 callback.Run(DECRYPTION_RESULT_INVALID_SHARED_SECRET, IncomingMessage()); |
209 return; | 217 return; |
210 } | 218 } |
211 | 219 |
212 std::string plaintext; | 220 std::string plaintext; |
213 | 221 |
214 GCMMessageCryptographer cryptographer(GCMMessageCryptographer::Label::P256, | 222 GCMMessageCryptographer cryptographer(GCMMessageCryptographer::Label::P256, |
215 pair.public_key(), dh, auth_secret); | 223 pair.public_key(), dh, auth_secret); |
216 if (!cryptographer.Decrypt(message.raw_data, shared_secret, salt, rs, | 224 if (!cryptographer.Decrypt(message.raw_data, shared_secret, salt, rs, |
217 &plaintext)) { | 225 &plaintext)) { |
218 DLOG(ERROR) << "Unable to decrypt the incoming data."; | 226 DLOG(ERROR) << "Unable to decrypt the incoming data."; |
219 failure_callback.Run(DECRYPTION_FAILURE_INVALID_PAYLOAD); | 227 callback.Run(DECRYPTION_RESULT_INVALID_PAYLOAD, IncomingMessage()); |
220 return; | 228 return; |
221 } | 229 } |
222 | 230 |
223 IncomingMessage decrypted_message; | 231 IncomingMessage decrypted_message; |
224 decrypted_message.collapse_key = message.collapse_key; | 232 decrypted_message.collapse_key = message.collapse_key; |
225 decrypted_message.sender_id = message.sender_id; | 233 decrypted_message.sender_id = message.sender_id; |
226 decrypted_message.raw_data.swap(plaintext); | 234 decrypted_message.raw_data.swap(plaintext); |
227 decrypted_message.decrypted = true; | 235 decrypted_message.decrypted = true; |
228 | 236 |
229 // There must be no data associated with the decrypted message at this point, | 237 // There must be no data associated with the decrypted message at this point, |
230 // to make sure that we don't end up in an infinite decryption loop. | 238 // to make sure that we don't end up in an infinite decryption loop. |
231 DCHECK_EQ(0u, decrypted_message.data.size()); | 239 DCHECK_EQ(0u, decrypted_message.data.size()); |
232 | 240 |
233 success_callback.Run(decrypted_message); | 241 callback.Run(DECRYPTION_RESULT_DECRYPTED, decrypted_message); |
234 } | 242 } |
235 | 243 |
236 } // namespace gcm | 244 } // namespace gcm |
OLD | NEW |