Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(248)

Side by Side Diff: components/os_crypt/os_crypt_linux.cc

Issue 1973483002: OSCrypt for POSIX uses libsecret to store a randomised encryption key. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Fixed lsan failure Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698