OLD | NEW |
(Empty) | |
| 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 |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include "components/proximity_auth/cryptauth/fake_secure_message_delegate.h" |
| 6 |
| 7 #include <algorithm> |
| 8 |
| 9 #include "base/callback.h" |
| 10 #include "base/md5.h" |
| 11 #include "base/strings/string_util.h" |
| 12 |
| 13 namespace proximity_auth { |
| 14 |
| 15 namespace { |
| 16 |
| 17 const char kKeyPrefix[] = "fake_key_"; |
| 18 const char kPrivateKeyPrefix[] = "private_"; |
| 19 |
| 20 // Encrypts the |plaintext| with the |key| using the |encryption_scheme| and |
| 21 // returns the ciphertext. |
| 22 std::string Encrypt(const std::string& plaintext, |
| 23 const std::string& key, |
| 24 const securemessage::EncScheme& encryption_scheme) { |
| 25 if (encryption_scheme == securemessage::NONE) |
| 26 return plaintext; |
| 27 |
| 28 // Encrypt with a Vigenere cipher. |
| 29 std::string ciphertext; |
| 30 ciphertext.resize(plaintext.size()); |
| 31 for (size_t i = 0; i < plaintext.size(); ++i) { |
| 32 unsigned char plaintext_char = plaintext[i]; |
| 33 unsigned char key_char = key[i % key.size()]; |
| 34 ciphertext[i] = plaintext_char + key_char; |
| 35 } |
| 36 return ciphertext; |
| 37 } |
| 38 |
| 39 // Decrypts the |ciphertext| with the |key| using the |encryption_scheme| and |
| 40 // returns the plaintext. |
| 41 std::string Decrypt(const std::string& ciphertext, |
| 42 const std::string& key, |
| 43 const securemessage::EncScheme& encryption_scheme) { |
| 44 if (encryption_scheme == securemessage::NONE) |
| 45 return ciphertext; |
| 46 |
| 47 // Decrypt with a Vigenere cipher. |
| 48 std::string plaintext; |
| 49 plaintext.resize(ciphertext.size()); |
| 50 for (size_t i = 0; i < ciphertext.size(); ++i) { |
| 51 unsigned char ciphertext_char = ciphertext[i]; |
| 52 unsigned char key_char = key[i % key.size()]; |
| 53 plaintext[i] = ciphertext_char - key_char; |
| 54 } |
| 55 return plaintext; |
| 56 } |
| 57 |
| 58 // Signs the |payload| and |associated_data| with the |key| using the |
| 59 // |signature_scheme| and returns the signature. |
| 60 std::string Sign(const std::string& payload, |
| 61 const std::string& associated_data, |
| 62 const std::string& key) { |
| 63 return base::MD5String(payload + "|" + associated_data + "|" + key); |
| 64 } |
| 65 |
| 66 // Verifies that the |signature| for the the |payload| and |associated_data| is |
| 67 // valid for the given the |key| and |signature_scheme|. |
| 68 bool Verify(const std::string& signature, |
| 69 const std::string& payload, |
| 70 const std::string& associated_data, |
| 71 const std::string& key, |
| 72 const securemessage::SigScheme& signature_scheme) { |
| 73 std::string signing_key; |
| 74 |
| 75 if (signature_scheme == securemessage::HMAC_SHA256) { |
| 76 signing_key = key; |
| 77 } else { |
| 78 std::string prefix = kPrivateKeyPrefix; |
| 79 bool is_private_key = StartsWithASCII(key, prefix, true); |
| 80 signing_key = is_private_key ? key.substr(prefix.size()) : prefix + key; |
| 81 } |
| 82 |
| 83 std::string expected_signature = Sign(payload, associated_data, signing_key); |
| 84 return signature == expected_signature; |
| 85 } |
| 86 |
| 87 } // namespace |
| 88 |
| 89 FakeSecureMessageDelegate::FakeSecureMessageDelegate() |
| 90 : next_public_key_(std::string(kKeyPrefix) + "0") { |
| 91 } |
| 92 |
| 93 FakeSecureMessageDelegate::~FakeSecureMessageDelegate() { |
| 94 } |
| 95 |
| 96 void FakeSecureMessageDelegate::GenerateKeyPair( |
| 97 const GenerateKeyPairCallback& callback) { |
| 98 std::string public_key = next_public_key_; |
| 99 |
| 100 // The private key is simply the public key prepended with "private_". |
| 101 std::string private_key(kPrivateKeyPrefix + public_key); |
| 102 |
| 103 next_public_key_ = std::string(kKeyPrefix) + base::MD5String(public_key); |
| 104 |
| 105 callback.Run(public_key, private_key); |
| 106 } |
| 107 |
| 108 void FakeSecureMessageDelegate::DeriveKey(const std::string& private_key, |
| 109 const std::string& public_key, |
| 110 const DeriveKeyCallback& callback) { |
| 111 // To ensure that the same symmetric key is derived for DeriveKey(private1, |
| 112 // public2) and DeriveKey(private2, public1), we remove the prefix from the |
| 113 // private key so it is equal to its corresponding public key. |
| 114 std::string prefix(kPrivateKeyPrefix); |
| 115 std::string normalized_private_key = |
| 116 StartsWithASCII(private_key, prefix, true) |
| 117 ? private_key.substr(prefix.size()) |
| 118 : private_key; |
| 119 |
| 120 std::vector<std::string> keys; |
| 121 keys.push_back(normalized_private_key); |
| 122 keys.push_back(public_key); |
| 123 std::sort(keys.begin(), keys.end()); |
| 124 callback.Run(base::MD5String(keys[0] + "|" + keys[1])); |
| 125 } |
| 126 |
| 127 void FakeSecureMessageDelegate::CreateSecureMessage( |
| 128 const std::string& payload, |
| 129 const std::string& key, |
| 130 const CreateOptions& create_options, |
| 131 const CreateSecureMessageCallback& callback) { |
| 132 securemessage::Header header; |
| 133 header.set_signature_scheme(create_options.signature_scheme); |
| 134 header.set_encryption_scheme(create_options.encryption_scheme); |
| 135 if (!create_options.public_metadata.empty()) |
| 136 header.set_public_metadata(create_options.public_metadata); |
| 137 if (!create_options.verification_key_id.empty()) |
| 138 header.set_verification_key_id(create_options.verification_key_id); |
| 139 if (!create_options.decryption_key_id.empty()) |
| 140 header.set_decryption_key_id(create_options.decryption_key_id); |
| 141 |
| 142 securemessage::HeaderAndBody header_and_body; |
| 143 header_and_body.mutable_header()->CopyFrom(header); |
| 144 header_and_body.set_body( |
| 145 Encrypt(payload, key, create_options.encryption_scheme)); |
| 146 std::string serialized_header_and_body; |
| 147 header_and_body.SerializeToString(&serialized_header_and_body); |
| 148 |
| 149 securemessage::SecureMessage secure_message; |
| 150 secure_message.set_header_and_body(serialized_header_and_body); |
| 151 secure_message.set_signature( |
| 152 Sign(payload, create_options.associated_data, key)); |
| 153 |
| 154 std::string serialized_secure_message; |
| 155 secure_message.SerializeToString(&serialized_secure_message); |
| 156 callback.Run(serialized_secure_message); |
| 157 } |
| 158 |
| 159 void FakeSecureMessageDelegate::UnwrapSecureMessage( |
| 160 const std::string& serialized_message, |
| 161 const std::string& key, |
| 162 const UnwrapOptions& unwrap_options, |
| 163 const UnwrapSecureMessageCallback& callback) { |
| 164 securemessage::SecureMessage secure_message; |
| 165 if (!secure_message.ParseFromString(serialized_message)) { |
| 166 LOG(ERROR) << "Failed to parse SecureMessage."; |
| 167 callback.Run(false, std::string(), securemessage::Header()); |
| 168 return; |
| 169 } |
| 170 |
| 171 securemessage::HeaderAndBody header_and_body; |
| 172 if (!header_and_body.ParseFromString(secure_message.header_and_body())) { |
| 173 LOG(ERROR) << "Failed to parse secure message HeaderAndBody."; |
| 174 callback.Run(false, std::string(), securemessage::Header()); |
| 175 return; |
| 176 } |
| 177 |
| 178 const securemessage::Header& header = header_and_body.header(); |
| 179 std::string payload = |
| 180 Decrypt(header_and_body.body(), key, unwrap_options.encryption_scheme); |
| 181 |
| 182 bool verified = Verify(secure_message.signature(), payload, |
| 183 unwrap_options.associated_data, key, |
| 184 unwrap_options.signature_scheme); |
| 185 if (verified) { |
| 186 callback.Run(true, payload, header); |
| 187 } else { |
| 188 callback.Run(false, std::string(), securemessage::Header()); |
| 189 } |
| 190 } |
| 191 |
| 192 } // namespace proximity_auth |
OLD | NEW |