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

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: Created 5 years, 1 month 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 NOTREACHED() << "Unable to save password in keychain: " << status;
63 if (status == errSecDuplicateItem || status == errSecDecode)
64 return ENCRYPTION_RESULT_ITEM_FAILURE;
65 else
66 return ENCRYPTION_RESULT_SERVICE_FAILURE;
67 }
68
69 *cipher_text = base::SysCFStringRefToUTF8(item_ref);
70 return ENCRYPTION_RESULT_SUCCESS;
71 }
72
73 LoginDatabase::EncryptionResult LoginDatabase::DecryptedString(
74 const std::string& cipher_text,
75 base::string16* plain_text) {
76 if (cipher_text.size() == 0) {
77 *plain_text = base::string16();
78 return ENCRYPTION_RESULT_SUCCESS;
79 }
80
81 ScopedCFTypeRef<CFStringRef> item_ref(
82 base::SysUTF8ToCFStringRef(cipher_text));
83 ScopedCFTypeRef<CFMutableDictionaryRef> query(
84 CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
85 &kCFTypeDictionaryValueCallBacks));
86 CFDictionarySetValue(query, kSecClass, kSecClassGenericPassword);
87
88 // We are using the account attribute to store item references.
89 CFDictionarySetValue(query, kSecAttrAccount, item_ref);
90 CFDictionarySetValue(query, kSecReturnData, kCFBooleanTrue);
91
92 CFDataRef data;
93 OSStatus status = SecItemCopyMatching(query, (CFTypeRef*)&data);
94 if (status != errSecSuccess) {
95 OSSTATUS_LOG(INFO, status) << "Failed to retrieve password from keychain";
96 if (status == errSecItemNotFound || status == errSecDecode)
97 return ENCRYPTION_RESULT_ITEM_FAILURE;
98 else
99 return ENCRYPTION_RESULT_SERVICE_FAILURE;
100 }
101
102 const size_t size = CFDataGetLength(data);
103 scoped_ptr<UInt8[]> buffer(new UInt8[size]);
104 CFDataGetBytes(data, CFRangeMake(0, size), buffer.get());
105 CFRelease(data);
106
107 *plain_text = base::UTF8ToUTF16(
108 std::string(static_cast<char*>(static_cast<void*>(buffer.get())),
109 static_cast<size_t>(size)));
110 return ENCRYPTION_RESULT_SUCCESS;
111 }
112
113 void LoginDatabase::DeleteEncryptedPassword(const PasswordForm& form) {
114 std::string cipher_text = GetEncryptedPassword(form);
115 if (cipher_text.size() == 0)
116 return;
117
118 ScopedCFTypeRef<CFStringRef> item_ref(
119 base::SysUTF8ToCFStringRef(cipher_text));
120 ScopedCFTypeRef<CFMutableDictionaryRef> query(
121 CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks,
122 &kCFTypeDictionaryValueCallBacks));
123 CFDictionarySetValue(query, kSecClass, kSecClassGenericPassword);
124
125 // We are using the account attribute to store item references.
126 CFDictionarySetValue(query, kSecAttrAccount, item_ref);
127
128 OSStatus status = SecItemDelete(query);
129 if (status != errSecSuccess && status != errSecItemNotFound) {
130 NOTREACHED() << "Unable to remove password from keychain: " << status;
131 }
132 }
133
134 } // namespace password_manager
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698