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