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
;
79 bool is_private_key
= base::StartsWithASCII(key
, prefix
, true);
80 signing_key
= is_private_key
? key
.substr(prefix
.size()) : prefix
+ key
;
83 std::string expected_signature
= Sign(payload
, associated_data
, signing_key
);
84 return signature
== expected_signature
;
89 FakeSecureMessageDelegate::FakeSecureMessageDelegate()
90 : next_public_key_(std::string(kKeyPrefix
) + "0") {
93 FakeSecureMessageDelegate::~FakeSecureMessageDelegate() {
96 void FakeSecureMessageDelegate::GenerateKeyPair(
97 const GenerateKeyPairCallback
& callback
) {
98 std::string public_key
= next_public_key_
;
100 // The private key is simply the public key prepended with "private_".
101 std::string
private_key(kPrivateKeyPrefix
+ public_key
);
103 next_public_key_
= std::string(kKeyPrefix
) + base::MD5String(public_key
);
105 callback
.Run(public_key
, private_key
);
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 base::StartsWithASCII(private_key
, prefix
, true)
117 ? private_key
.substr(prefix
.size())
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]));
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
);
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
);
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
));
154 std::string serialized_secure_message
;
155 secure_message
.SerializeToString(&serialized_secure_message
);
156 callback
.Run(serialized_secure_message
);
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());
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());
178 const securemessage::Header
& header
= header_and_body
.header();
179 std::string payload
=
180 Decrypt(header_and_body
.body(), key
, unwrap_options
.encryption_scheme
);
182 bool verified
= Verify(secure_message
.signature(), payload
,
183 unwrap_options
.associated_data
, key
,
184 unwrap_options
.signature_scheme
);
186 callback
.Run(true, payload
, header
);
188 callback
.Run(false, std::string(), securemessage::Header());
192 std::string
FakeSecureMessageDelegate::GetPrivateKeyForPublicKey(
193 const std::string
& public_key
) {
194 return kPrivateKeyPrefix
+ public_key
;
197 } // namespace proximity_auth