Chromium Code Reviews| Index: components/proximity_auth/cryptauth/fake_secure_message_delegate.cc |
| diff --git a/components/proximity_auth/cryptauth/fake_secure_message_delegate.cc b/components/proximity_auth/cryptauth/fake_secure_message_delegate.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..f497a58ebd359a368970b8441bec87a1401f65f3 |
| --- /dev/null |
| +++ b/components/proximity_auth/cryptauth/fake_secure_message_delegate.cc |
| @@ -0,0 +1,181 @@ |
| +// Copyright 2015 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "components/proximity_auth/cryptauth/fake_secure_message_delegate.h" |
| + |
| +#include <algorithm> |
| + |
| +#include "base/callback.h" |
| +#include "base/md5.h" |
| + |
| +namespace proximity_auth { |
| + |
| +namespace { |
| + |
| +const char kKeyPrefix[] = "fake_key_"; |
| +const char kPrivateKeyPrefix[] = "private_"; |
| + |
| +// Encrypts the |payload| with the |key| using the |encryption_scheme| and |
| +// returns the ciphertext. |
| +std::string Encrypt(const std::string& payload, |
| + const std::string& key, |
| + const securemessage::EncScheme& encryption_scheme) { |
| + if (encryption_scheme == securemessage::NONE) |
| + return payload; |
| + |
| + // Encrypt with a Vigenere cipher. |
| + std::string ciphertext; |
| + ciphertext.resize(payload.size()); |
| + for (size_t i = 0; i < payload.size(); ++i) { |
| + char c = key[i % key.size()]; |
| + ciphertext[i] = (payload[i] + c) % sizeof(char); |
| + } |
| + return payload; |
| +} |
| + |
| +// Decrypts the |payload| with the |key| using the |encryption_scheme| and |
| +// returns the plaintext. |
| +std::string Decrypt(const std::string& ciphertext, |
| + const std::string& key, |
| + const securemessage::EncScheme& encryption_scheme) { |
| + if (encryption_scheme == securemessage::NONE) |
| + return ciphertext; |
| + |
| + // Decrypt with a Vigenere cipher. |
| + std::string plaintext; |
| + plaintext.resize(ciphertext.size()); |
| + for (size_t i = 0; i < ciphertext.size(); ++i) { |
| + unsigned char ciphertext_char = ciphertext[i]; |
| + unsigned char key_char = key[i % key.size()]; |
| + plaintext[i] = ciphertext_char - key_char; |
| + } |
| + return plaintext; |
| +} |
| + |
| +// Signs the |payload| and |associated_data| with the |key| using the |
| +// |signature_scheme| and returns the signature. |
| +std::string Sign(const std::string& payload, |
| + const std::string& associated_data, |
| + const std::string& key, |
| + const securemessage::SigScheme& signature_scheme) { |
|
Ilya Sherman
2015/04/03 02:13:05
The signature_scheme is ignored here, but used in
Tim Song
2015/04/03 02:46:34
Anything signed by the private key can be verified
|
| + return base::MD5String(payload + "|" + associated_data + "|" + key); |
| +} |
| + |
| +// Verifies that the |signature| for the the |payload| and |associated_data| is |
| +// valid for the given the |key| and |signature_scheme|. |
| +bool Verify(const std::string& signature, |
| + const std::string& payload, |
| + const std::string& associated_data, |
| + const std::string& key, |
| + const securemessage::SigScheme& signature_scheme) { |
| + // Verify signatures created using symmetric keys. |
| + if (signature_scheme == securemessage::HMAC_SHA256) { |
| + std::string expected_signature = |
| + Sign(payload, associated_data, key, signature_scheme); |
| + return signature == expected_signature; |
| + } |
| + |
| + // Verify signatures created using asymmetric keys. |
| + std::string prefix = kPrivateKeyPrefix; |
| + bool is_private_key = key.substr(0, prefix.size()) == prefix; |
| + std::string signing_key = |
| + is_private_key ? key.substr(prefix.size()) : prefix + key; |
| + |
| + std::string expected_signature = |
| + Sign(payload, associated_data, signing_key, signature_scheme); |
| + return signature == expected_signature; |
| +} |
| +} |
| + |
| +FakeSecureMessageDelegate::FakeSecureMessageDelegate() |
| + : next_public_key_(std::string(kKeyPrefix) + "0") { |
| +} |
| + |
| +FakeSecureMessageDelegate::~FakeSecureMessageDelegate() { |
| +} |
| + |
| +void FakeSecureMessageDelegate::GenerateKeyPair( |
| + const GenerateKeyPairCallback& callback) { |
| + std::string public_key = next_public_key_; |
| + |
| + // The private key is simply the public key prepended with "private_". |
| + std::string private_key(std::string(kPrivateKeyPrefix + public_key)); |
| + |
| + next_public_key_ = std::string(kKeyPrefix) + base::MD5String(public_key); |
| + |
| + callback.Run(public_key, private_key); |
| +} |
| + |
| +void FakeSecureMessageDelegate::DeriveKey(const std::string& private_key, |
| + const std::string& public_key, |
| + const DeriveKeyCallback& callback) { |
| + callback.Run(base::MD5String(private_key + "|" + public_key)); |
| +} |
| + |
| +void FakeSecureMessageDelegate::CreateSecureMessage( |
| + const std::string& payload, |
| + const std::string& key, |
| + const CreateOptions& create_options, |
| + const CreateSecureMessageCallback& callback) { |
| + securemessage::Header header; |
| + header.set_signature_scheme(create_options.signature_scheme); |
| + header.set_encryption_scheme(create_options.encryption_scheme); |
| + if (!create_options.public_metadata.empty()) |
| + header.set_public_metadata(create_options.public_metadata); |
| + if (!create_options.verification_key_id.empty()) |
| + header.set_verification_key_id(create_options.verification_key_id); |
| + if (!create_options.decryption_key_id.empty()) |
| + header.set_decryption_key_id(create_options.decryption_key_id); |
| + |
| + securemessage::HeaderAndBody header_and_body; |
| + header_and_body.mutable_header()->CopyFrom(header); |
| + header_and_body.set_body( |
| + Encrypt(payload, key, create_options.encryption_scheme)); |
| + std::string serialized_header_and_body; |
| + header_and_body.SerializeToString(&serialized_header_and_body); |
| + |
| + securemessage::SecureMessage secure_message; |
| + secure_message.set_header_and_body(serialized_header_and_body); |
| + secure_message.set_signature(Sign(payload, create_options.associated_data, |
| + key, create_options.signature_scheme)); |
| + |
| + std::string serialized_secure_message; |
| + secure_message.SerializeToString(&serialized_secure_message); |
| + callback.Run(serialized_secure_message); |
| +} |
| + |
| +void FakeSecureMessageDelegate::UnwrapSecureMessage( |
| + const std::string& serialized_message, |
| + const std::string& key, |
| + const UnwrapOptions& unwrap_options, |
| + const UnwrapSecureMessageCallback& callback) { |
| + securemessage::SecureMessage secure_message; |
| + if (!secure_message.ParseFromString(serialized_message)) { |
| + LOG(ERROR) << "Failed to parse SecureMessage."; |
| + callback.Run(false, std::string(), securemessage::Header()); |
| + return; |
| + } |
| + |
| + securemessage::HeaderAndBody header_and_body; |
| + if (!header_and_body.ParseFromString(secure_message.header_and_body())) { |
| + LOG(ERROR) << "Failed to parse secure message HeaderAndBody."; |
| + callback.Run(false, std::string(), securemessage::Header()); |
| + return; |
| + } |
| + |
| + const securemessage::Header& header = header_and_body.header(); |
| + std::string payload = |
| + Decrypt(header_and_body.body(), key, unwrap_options.encryption_scheme); |
| + |
| + bool verified = Verify(secure_message.signature(), payload, |
| + unwrap_options.associated_data, key, |
| + unwrap_options.signature_scheme); |
| + if (verified) { |
| + callback.Run(true, payload, header); |
| + } else { |
| + callback.Run(false, std::string(), securemessage::Header()); |
| + } |
| +} |
| + |
| +} // namespace proximity_auth |