OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2016 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/os_crypt/os_crypt.h" | |
6 | |
7 #include <stddef.h> | |
8 | |
9 #include <functional> | |
Lei Zhang
2016/05/18 22:38:16
What's this used for?
cfroussios
2016/05/19 21:18:18
Done.
| |
10 #include <memory> | |
11 | |
12 #include "base/lazy_instance.h" | |
13 #include "base/logging.h" | |
14 #include "base/strings/string_util.h" | |
15 #include "base/strings/utf_string_conversions.h" | |
16 #include "components/os_crypt/key_storage_linux.h" | |
17 #include "crypto/encryptor.h" | |
18 #include "crypto/symmetric_key.h" | |
19 | |
20 namespace { | |
21 | |
22 // Salt for Symmetric key derivation. | |
23 const char kSalt[] = "saltysalt"; | |
24 | |
25 // Key size required for 128 bit AES. | |
26 const size_t kDerivedKeySizeInBits = 128; | |
27 | |
28 // Constant for Symmetic key derivation. | |
29 const size_t kEncryptionIterations = 1; | |
30 | |
31 // Size of initialization vector for AES 128-bit. | |
32 const size_t kIVBlockSizeAES128 = 16; | |
33 | |
34 // Used for array indexing | |
35 enum Version { | |
36 V10 = 0, | |
37 V11 = 1, | |
38 }; | |
39 | |
40 // Prefix for cypher text returned by obfuscation version. We prefix the | |
41 // cyphertext with this string so that future data migration can detect | |
42 // this and migrate to full encryption without data loss. | |
43 const char* kObfuscationPrefix[] = { | |
Lei Zhang
2016/05/18 22:38:16
const char kObfuscationPrefix[][4]
cfroussios
2016/05/19 21:18:18
Done.
| |
44 "v10", "v11", | |
45 }; | |
46 | |
47 struct Cache { | |
48 std::unique_ptr<KeyStorage> key_storage_cache; | |
49 std::unique_ptr<std::string> password_v10_cache; | |
50 std::unique_ptr<std::string> password_v11_cache; | |
51 bool is_key_storage_cached; | |
52 bool is_password_v11_cached; | |
53 }; | |
54 | |
55 base::LazyInstance<Cache>::Leaky g_cache = LAZY_INSTANCE_INITIALIZER; | |
56 | |
57 // Lazy acquisition and caching of a KeyStorage. Will be null if no service is | |
58 // found. | |
59 KeyStorage* GetKeyStorage() { | |
60 if (!g_cache.Get().is_key_storage_cached) { | |
61 g_cache.Get().is_key_storage_cached = true; | |
62 g_cache.Get().key_storage_cache.reset( | |
63 KeyStorage::CreateService().release()); | |
Lei Zhang
2016/05/18 22:38:16
foo.reset(bar.release()) -> foo = bar?
cfroussios
2016/05/19 21:18:18
Done.
| |
64 } | |
65 return g_cache.Get().key_storage_cache.get(); | |
66 } | |
67 | |
68 // Returns a cached string of "peanuts" | |
69 std::string* GetPasswordV10() { | |
70 if (!g_cache.Get().password_v10_cache.get()) | |
71 g_cache.Get().password_v10_cache.reset(new std::string("peanuts")); | |
72 return g_cache.Get().password_v10_cache.get(); | |
73 } | |
74 | |
75 // Caches and returns the password from the KeyStorage or null if there is no | |
76 // service. | |
77 std::string* GetPasswordV11() { | |
78 if (!g_cache.Get().is_password_v11_cached) { | |
79 g_cache.Get().is_password_v11_cached = true; | |
80 g_cache.Get().password_v11_cache.reset( | |
81 GetKeyStorage() ? new std::string(GetKeyStorage()->GetKey()) : nullptr); | |
82 } | |
83 return g_cache.Get().password_v11_cache.get(); | |
84 } | |
85 | |
86 KeyStorage* (*g_key_storage_provider)() = &GetKeyStorage; | |
87 | |
88 std::string* (*get_password[])() = { | |
89 &GetPasswordV10, &GetPasswordV11, | |
90 }; | |
91 | |
92 // Generates a newly allocated SymmetricKey object based a hard-coded password. | |
93 // Ownership of the key is passed to the caller. Returns NULL key if a key | |
94 // generation error occurs. | |
95 std::unique_ptr<crypto::SymmetricKey> GetEncryptionKey(Version version) { | |
96 std::string salt(kSalt); | |
97 | |
98 std::string* password = get_password[version](); | |
99 if (password == nullptr) | |
Lei Zhang
2016/05/18 22:38:16
!password
cfroussios
2016/05/19 21:18:19
Done.
| |
100 return nullptr; | |
101 | |
102 // Create an encryption key from our password and salt. | |
103 std::unique_ptr<crypto::SymmetricKey> encryption_key( | |
104 crypto::SymmetricKey::DeriveKeyFromPassword( | |
105 crypto::SymmetricKey::AES, *password, salt, kEncryptionIterations, | |
106 kDerivedKeySizeInBits)); | |
107 DCHECK(encryption_key.get()); | |
108 | |
109 return encryption_key; | |
110 } | |
111 | |
112 } // namespace | |
113 | |
114 // static | |
115 bool OSCrypt::EncryptString16(const base::string16& plaintext, | |
116 std::string* ciphertext) { | |
117 return EncryptString(base::UTF16ToUTF8(plaintext), ciphertext); | |
118 } | |
119 | |
120 // static | |
121 bool OSCrypt::DecryptString16(const std::string& ciphertext, | |
122 base::string16* plaintext) { | |
123 std::string utf8; | |
124 if (!DecryptString(ciphertext, &utf8)) | |
125 return false; | |
126 | |
127 *plaintext = base::UTF8ToUTF16(utf8); | |
128 return true; | |
129 } | |
130 | |
131 // static | |
132 bool OSCrypt::EncryptString(const std::string& plaintext, | |
133 std::string* ciphertext) { | |
134 if (plaintext.empty()) { | |
135 *ciphertext = std::string(); | |
136 return true; | |
137 } | |
138 | |
139 // If a |KeyStorage| is available, use a password backed by the |KeyStorage|. | |
140 // Otherwise use the hardcoded password. | |
141 Version version = g_key_storage_provider() ? Version::V11 : Version::V10; | |
142 | |
143 std::unique_ptr<crypto::SymmetricKey> encryption_key( | |
144 GetEncryptionKey(version)); | |
145 if (!encryption_key.get()) | |
146 return false; | |
147 | |
148 std::string iv(kIVBlockSizeAES128, ' '); | |
149 crypto::Encryptor encryptor; | |
150 if (!encryptor.Init(encryption_key.get(), crypto::Encryptor::CBC, iv)) | |
151 return false; | |
152 | |
153 if (!encryptor.Encrypt(plaintext, ciphertext)) | |
154 return false; | |
155 | |
156 // Prefix the cypher text with version information. | |
157 ciphertext->insert(0, kObfuscationPrefix[version]); | |
158 return true; | |
159 } | |
160 | |
161 // static | |
162 bool OSCrypt::DecryptString(const std::string& ciphertext, | |
163 std::string* plaintext) { | |
164 if (ciphertext.empty()) { | |
165 *plaintext = std::string(); | |
166 return true; | |
167 } | |
168 | |
169 // Check that the incoming cyphertext was encrypted and with what version. | |
170 // Credit card numbers are current legacy unencrypted data, so false match | |
171 // with prefix won't happen. | |
172 Version version; | |
173 if (ciphertext.find(kObfuscationPrefix[Version::V10]) == 0) { | |
Lei Zhang
2016/05/18 22:38:16
Use base::StartsWith() for readability?
cfroussios
2016/05/19 21:18:18
Done.
| |
174 version = Version::V10; | |
175 } else if (ciphertext.find(kObfuscationPrefix[Version::V11]) == 0) { | |
176 version = Version::V11; | |
177 } else { | |
178 // If the prefix is not found then we'll assume we're dealing with | |
179 // old data saved as clear text and we'll return it directly. | |
180 *plaintext = ciphertext; | |
181 return true; | |
182 } | |
183 | |
184 // Strip off the versioning prefix before decrypting. | |
185 std::string raw_ciphertext = | |
Lei Zhang
2016/05/18 22:38:16
Can you defer this until you use it?
cfroussios
2016/05/19 21:18:18
Done.
| |
186 ciphertext.substr(strlen(kObfuscationPrefix[version])); | |
187 | |
188 std::unique_ptr<crypto::SymmetricKey> encryption_key( | |
189 GetEncryptionKey(version)); | |
190 if (!encryption_key.get()) | |
191 return false; | |
192 | |
193 std::string iv(kIVBlockSizeAES128, ' '); | |
194 crypto::Encryptor encryptor; | |
195 if (!encryptor.Init(encryption_key.get(), crypto::Encryptor::CBC, iv)) | |
196 return false; | |
197 | |
198 if (!encryptor.Decrypt(raw_ciphertext, plaintext)) | |
199 return false; | |
200 | |
201 return true; | |
202 } | |
203 | |
204 namespace { | |
205 | |
206 base::LazyInstance<KeyStorageMock>::Leaky key_storage_mock = | |
Lei Zhang
2016/05/18 22:38:16
g_var_name_for_globals
cfroussios
2016/05/19 21:18:19
Done.
| |
207 LAZY_INSTANCE_INITIALIZER; | |
208 | |
209 std::string* get_password_v11_mock() { | |
210 return key_storage_mock.Get().GetKeyPtr(); | |
211 } | |
212 | |
213 KeyStorage* get_key_storage_mock() { | |
214 return key_storage_mock.Pointer(); | |
215 } | |
216 | |
217 } // namespace | |
218 | |
219 // static | |
220 KeyStorageMock* OSCrypt::UseMockKeyStorage(bool use) { | |
221 if (use) { | |
222 // Bypass loading a |KeyStorage| and caching of the key for V11 | |
223 get_password[Version::V11] = &get_password_v11_mock; | |
224 // OSCrypt will determine the encryption version by checking if a | |
225 // |KeyStorage| can be found. Enable V11 by returning the mock. | |
226 g_key_storage_provider = &get_key_storage_mock; | |
227 } else { | |
228 get_password[Version::V11] = &GetPasswordV11; | |
229 g_key_storage_provider = &GetKeyStorage; | |
230 } | |
231 | |
232 return key_storage_mock.Pointer(); | |
233 } | |
OLD | NEW |