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

Side by Side Diff: components/password_manager/core/browser/login_database_ios.cc

Issue 1237403003: [Password manager IOS upsteaming] Upstreaming login database (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Histograms Created 5 years, 5 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 (c) 2012 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/password_manager/core/browser/login_database.h"
6
7 #import <Security/Security.h>
8
9 #include "base/base64.h"
10 #include "base/logging.h"
11 #include "base/mac/mac_logging.h"
12 #include "base/mac/scoped_cftyperef.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/metrics/sparse_histogram.h"
15 #include "base/strings/sys_string_conversions.h"
16 #include "base/strings/utf_string_conversions.h"
17
18 using base::ScopedCFTypeRef;
19 using autofill::PasswordForm;
20
21 namespace password_manager {
22
23 // On iOS, the LoginDatabase uses Keychain API to store passwords. The
24 // "encrypted" version of the password is a unique ID (UUID) that is
25 // stored as an attribute along with the password in the keychain.
26 // A side effect of this approach is that the same password saved multiple
27 // times will have different "encrypted" values.
28
29 // TODO(ios): Use |Encryptor| to encrypt the login database. b/6976257
30
31 LoginDatabase::EncryptionResult LoginDatabase::EncryptedString(
32 const base::string16& plain_text,
33 std::string* cipher_text) {
34 if (plain_text.size() == 0) {
35 *cipher_text = std::string();
36 return ENCRYPTION_RESULT_SUCCESS;
37 }
38
39 ScopedCFTypeRef<CFUUIDRef> uuid(CFUUIDCreate(NULL));
40 ScopedCFTypeRef<CFStringRef> item_ref(CFUUIDCreateString(NULL, uuid));
41 ScopedCFTypeRef<CFMutableDictionaryRef> attributes(
42 CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
43 &kCFTypeDictionaryValueCallBacks));
44 CFDictionarySetValue(attributes, kSecClass, kSecClassGenericPassword);
45
46 // It does not matter which attribute we use to identify the keychain
47 // item as long as it uniquely identifies it. We are arbitrarily choosing the
48 // |kSecAttrAccount| attribute for this purpose.
49 CFDictionarySetValue(attributes, kSecAttrAccount, item_ref);
50 std::string plain_text_utf8 = UTF16ToUTF8(plain_text);
51 ScopedCFTypeRef<CFDataRef> data(
52 CFDataCreate(NULL, reinterpret_cast<const UInt8*>(plain_text_utf8.data()),
53 plain_text_utf8.size()));
54 CFDictionarySetValue(attributes, kSecValueData, data);
55
56 // Only allow access when the device has been unlocked.
57 CFDictionarySetValue(attributes, kSecAttrAccessible,
58 kSecAttrAccessibleWhenUnlocked);
59
60 OSStatus status = SecItemAdd(attributes, NULL);
61 if (status != errSecSuccess) {
62 UMA_HISTOGRAM_SPARSE_SLOWLY("LoginDatabase.EncryptFailure", -status);
63 NOTREACHED() << "Unable to save password in keychain: " << status;
64 if (status == errSecDuplicateItem || status == errSecDecode)
65 return ENCRYPTION_RESULT_ITEM_FAILURE;
66 else
67 return ENCRYPTION_RESULT_SERVICE_FAILURE;
68 }
69
70 *cipher_text = base::SysCFStringRefToUTF8(item_ref);
71 return ENCRYPTION_RESULT_SUCCESS;
72 }
73
74 LoginDatabase::EncryptionResult LoginDatabase::DecryptedString(
75 const std::string& cipher_text,
76 base::string16* plain_text) {
77 if (cipher_text.size() == 0) {
78 *plain_text = base::string16();
79 return ENCRYPTION_RESULT_SUCCESS;
80 }
81
82 ScopedCFTypeRef<CFStringRef> item_ref(
83 base::SysUTF8ToCFStringRef(cipher_text));
84 ScopedCFTypeRef<CFMutableDictionaryRef> query(
85 CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
86 &kCFTypeDictionaryValueCallBacks));
87 CFDictionarySetValue(query, kSecClass, kSecClassGenericPassword);
88
89 // We are using the account attribute to store item references.
90 CFDictionarySetValue(query, kSecAttrAccount, item_ref);
91 CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue);
92
93 CFDataRef data;
94 OSStatus status = SecItemCopyMatching(query, (CFTypeRef*)&data);
95 if (status != errSecSuccess) {
96 UMA_HISTOGRAM_SPARSE_SLOWLY("LoginDatabase.DecryptFailure", -status);
97 OSSTATUS_LOG(INFO, status) << "Failed to retrieve password from keychain";
98 if (status == errSecItemNotFound || status == errSecDecode)
99 return ENCRYPTION_RESULT_ITEM_FAILURE;
100 else
101 return ENCRYPTION_RESULT_SERVICE_FAILURE;
102 }
103
104 const size_t size = CFDataGetLength(data);
105 scoped_ptr<UInt8[]> buffer(new UInt8[size]);
106 CFDataGetBytes(data, CFRangeMake(0, size), buffer.get());
107 CFRelease(data);
108
109 *plain_text = base::UTF8ToUTF16(
110 std::string(static_cast<char*>(static_cast<void*>(buffer.get())),
111 static_cast<size_t>(size)));
112 return ENCRYPTION_RESULT_SUCCESS;
113 }
114
115 void LoginDatabase::DeleteEncryptedPassword(const PasswordForm& form) {
116 std::string cipher_text = GetEncryptedPassword(form);
117 if (cipher_text.size() == 0)
118 return;
119
120 ScopedCFTypeRef<CFStringRef> item_ref(
121 base::SysUTF8ToCFStringRef(cipher_text));
122 ScopedCFTypeRef<CFMutableDictionaryRef> query(
123 CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
124 &kCFTypeDictionaryValueCallBacks));
125 CFDictionarySetValue(query, kSecClass, kSecClassGenericPassword);
126
127 // We are using the account attribute to store item references.
128 CFDictionarySetValue(query, kSecAttrAccount, item_ref);
129
130 OSStatus status = SecItemDelete(query);
131 if (status != errSecSuccess && status != errSecItemNotFound) {
132 NOTREACHED() << "Unable to remove password from keychain: " << status;
133 }
134 }
135
136 } // namespace password_manager
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698