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.
5 #include "components/proximity_auth/cryptauth/fake_secure_message_delegate.h"
9 #include "base/callback.h"
11 #include "base/strings/string_util.h"
13 namespace proximity_auth
{
17 const char kKeyPrefix
[] = "fake_key_";
18 const char kPrivateKeyPrefix
[] = "private_";
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
)
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
;
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
)
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
;
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
);
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
;
75 if (signature_scheme
== securemessage::HMAC_SHA256
) {
78 std::string prefix
= kPrivateKeyPrefix
;
80 base::StartsWith(key
, prefix
, base::CompareCase::SENSITIVE
);
81 signing_key
= is_private_key
? key
.substr(prefix
.size()) : prefix
+ key
;
84 std::string expected_signature
= Sign(payload
, associated_data
, signing_key
);
85 return signature
== expected_signature
;
90 FakeSecureMessageDelegate::FakeSecureMessageDelegate()
91 : next_public_key_(std::string(kKeyPrefix
) + "0") {
94 FakeSecureMessageDelegate::~FakeSecureMessageDelegate() {
97 void FakeSecureMessageDelegate::GenerateKeyPair(
98 const GenerateKeyPairCallback
& callback
) {
99 std::string public_key
= next_public_key_
;
101 // The private key is simply the public key prepended with "private_".
102 std::string
private_key(kPrivateKeyPrefix
+ public_key
);
104 next_public_key_
= std::string(kKeyPrefix
) + base::MD5String(public_key
);
106 callback
.Run(public_key
, private_key
);
109 void FakeSecureMessageDelegate::DeriveKey(const std::string
& private_key
,
110 const std::string
& public_key
,
111 const DeriveKeyCallback
& callback
) {
112 // To ensure that the same symmetric key is derived for DeriveKey(private1,
113 // public2) and DeriveKey(private2, public1), we remove the prefix from the
114 // private key so it is equal to its corresponding public key.
115 std::string
prefix(kPrivateKeyPrefix
);
116 std::string normalized_private_key
=
117 base::StartsWith(private_key
, prefix
, base::CompareCase::SENSITIVE
)
118 ? private_key
.substr(prefix
.size())
121 std::vector
<std::string
> keys
;
122 keys
.push_back(normalized_private_key
);
123 keys
.push_back(public_key
);
124 std::sort(keys
.begin(), keys
.end());
125 callback
.Run(base::MD5String(keys
[0] + "|" + keys
[1]));
128 void FakeSecureMessageDelegate::CreateSecureMessage(
129 const std::string
& payload
,
130 const std::string
& key
,
131 const CreateOptions
& create_options
,
132 const CreateSecureMessageCallback
& callback
) {
133 securemessage::Header header
;
134 header
.set_signature_scheme(create_options
.signature_scheme
);
135 header
.set_encryption_scheme(create_options
.encryption_scheme
);
136 if (!create_options
.public_metadata
.empty())
137 header
.set_public_metadata(create_options
.public_metadata
);
138 if (!create_options
.verification_key_id
.empty())
139 header
.set_verification_key_id(create_options
.verification_key_id
);
140 if (!create_options
.decryption_key_id
.empty())
141 header
.set_decryption_key_id(create_options
.decryption_key_id
);
143 securemessage::HeaderAndBody header_and_body
;
144 header_and_body
.mutable_header()->CopyFrom(header
);
145 header_and_body
.set_body(
146 Encrypt(payload
, key
, create_options
.encryption_scheme
));
147 std::string serialized_header_and_body
;
148 header_and_body
.SerializeToString(&serialized_header_and_body
);
150 securemessage::SecureMessage secure_message
;
151 secure_message
.set_header_and_body(serialized_header_and_body
);
152 secure_message
.set_signature(
153 Sign(payload
, create_options
.associated_data
, key
));
155 std::string serialized_secure_message
;
156 secure_message
.SerializeToString(&serialized_secure_message
);
157 callback
.Run(serialized_secure_message
);
160 void FakeSecureMessageDelegate::UnwrapSecureMessage(
161 const std::string
& serialized_message
,
162 const std::string
& key
,
163 const UnwrapOptions
& unwrap_options
,
164 const UnwrapSecureMessageCallback
& callback
) {
165 securemessage::SecureMessage secure_message
;
166 if (!secure_message
.ParseFromString(serialized_message
)) {
167 LOG(ERROR
) << "Failed to parse SecureMessage.";
168 callback
.Run(false, std::string(), securemessage::Header());
172 securemessage::HeaderAndBody header_and_body
;
173 if (!header_and_body
.ParseFromString(secure_message
.header_and_body())) {
174 LOG(ERROR
) << "Failed to parse secure message HeaderAndBody.";
175 callback
.Run(false, std::string(), securemessage::Header());
179 const securemessage::Header
& header
= header_and_body
.header();
180 std::string payload
=
181 Decrypt(header_and_body
.body(), key
, unwrap_options
.encryption_scheme
);
183 bool verified
= Verify(secure_message
.signature(), payload
,
184 unwrap_options
.associated_data
, key
,
185 unwrap_options
.signature_scheme
);
187 callback
.Run(true, payload
, header
);
189 callback
.Run(false, std::string(), securemessage::Header());
193 std::string
FakeSecureMessageDelegate::GetPrivateKeyForPublicKey(
194 const std::string
& public_key
) {
195 return kPrivateKeyPrefix
+ public_key
;
198 } // namespace proximity_auth