| 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..195c24b0f85d37e61aa0886e429de55ce9d20e87
|
| --- /dev/null
|
| +++ b/components/proximity_auth/cryptauth/fake_secure_message_delegate.cc
|
| @@ -0,0 +1,192 @@
|
| +// 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"
|
| +#include "base/strings/string_util.h"
|
| +
|
| +namespace proximity_auth {
|
| +
|
| +namespace {
|
| +
|
| +const char kKeyPrefix[] = "fake_key_";
|
| +const char kPrivateKeyPrefix[] = "private_";
|
| +
|
| +// Encrypts the |plaintext| with the |key| using the |encryption_scheme| and
|
| +// returns the ciphertext.
|
| +std::string Encrypt(const std::string& plaintext,
|
| + const std::string& key,
|
| + const securemessage::EncScheme& encryption_scheme) {
|
| + if (encryption_scheme == securemessage::NONE)
|
| + return plaintext;
|
| +
|
| + // Encrypt with a Vigenere cipher.
|
| + std::string ciphertext;
|
| + ciphertext.resize(plaintext.size());
|
| + for (size_t i = 0; i < plaintext.size(); ++i) {
|
| + unsigned char plaintext_char = plaintext[i];
|
| + unsigned char key_char = key[i % key.size()];
|
| + ciphertext[i] = plaintext_char + key_char;
|
| + }
|
| + return ciphertext;
|
| +}
|
| +
|
| +// Decrypts the |ciphertext| 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) {
|
| + 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) {
|
| + std::string signing_key;
|
| +
|
| + if (signature_scheme == securemessage::HMAC_SHA256) {
|
| + signing_key = key;
|
| + } else {
|
| + std::string prefix = kPrivateKeyPrefix;
|
| + bool is_private_key = StartsWithASCII(key, prefix, true);
|
| + signing_key = is_private_key ? key.substr(prefix.size()) : prefix + key;
|
| + }
|
| +
|
| + std::string expected_signature = Sign(payload, associated_data, signing_key);
|
| + return signature == expected_signature;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +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(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) {
|
| + // To ensure that the same symmetric key is derived for DeriveKey(private1,
|
| + // public2) and DeriveKey(private2, public1), we remove the prefix from the
|
| + // private key so it is equal to its corresponding public key.
|
| + std::string prefix(kPrivateKeyPrefix);
|
| + std::string normalized_private_key =
|
| + StartsWithASCII(private_key, prefix, true)
|
| + ? private_key.substr(prefix.size())
|
| + : private_key;
|
| +
|
| + std::vector<std::string> keys;
|
| + keys.push_back(normalized_private_key);
|
| + keys.push_back(public_key);
|
| + std::sort(keys.begin(), keys.end());
|
| + callback.Run(base::MD5String(keys[0] + "|" + keys[1]));
|
| +}
|
| +
|
| +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));
|
| +
|
| + 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
|
|
|