-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathKeychainWrapper.m
133 lines (107 loc) · 5.27 KB
/
KeychainWrapper.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
//
// KeychainWrapper.m
//
// Created by Mylene Bayan on 9/4/14.
//
#import "KeychainWrapper.h"
#define APPNAME [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleIdentifier"]
@implementation KeychainWrapper
+ (NSMutableDictionary *)setupSearchDirectoryForIdentifier:(NSString *)identifier {
// Setup dictionary to access keychain
NSMutableDictionary *searchDictionary = [[NSMutableDictionary alloc] init];
// Specify we are using a Password (vs Certificate, Internet Password, etc)
[searchDictionary setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
// Uniquely identify this keychain accesser
[searchDictionary setObject:APPNAME forKey:(__bridge id)kSecAttrService];
// Uniquely identify the account who will be accessing the keychain
NSData *encodedIdentifier = [identifier dataUsingEncoding:NSUTF8StringEncoding];
[searchDictionary setObject:encodedIdentifier forKey:(__bridge id)kSecAttrGeneric];
[searchDictionary setObject:encodedIdentifier forKey:(__bridge id)kSecAttrAccount];
return searchDictionary;
}
+ (NSData *)searchKeychainCopyMatchingIdentifier:(NSString *)identifier {
NSMutableDictionary *searchDictionary = [self setupSearchDirectoryForIdentifier:identifier];
// Limit search results to one
[searchDictionary setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
// Specify we want NSData/CFData returned
[searchDictionary setObject:(__bridge id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];
// Search
NSData *result = nil;
CFTypeRef foundDict = NULL;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)searchDictionary, &foundDict);
if (status == noErr) {
result = (__bridge_transfer NSData *)foundDict;
} else {
result = nil;
}
return result;
}
+ (NSString *)keychainStringFromMatchingIdentifier:(NSString *)identifier {
NSData *valueData = [self searchKeychainCopyMatchingIdentifier:identifier];
if (valueData) {
DDLogInfo(@"Success fetching item for identifier: %@",identifier);
NSString *value = [[NSString alloc] initWithData:valueData
encoding:NSUTF8StringEncoding];
return value;
}
else {
DDLogError(@"Error fetching item for identifier: %@",identifier);
return nil;
}
}
+ (BOOL)createKeychainValue:(NSString *)value forIdentifier:(NSString *)identifier {
NSMutableDictionary *dictionary = [self setupSearchDirectoryForIdentifier:identifier];
NSData *valueData = [value dataUsingEncoding:NSUTF8StringEncoding];
[dictionary setObject:valueData forKey:(__bridge id)kSecValueData];
// Protect the keychain entry so its only valid when the device is unlocked
[dictionary setObject:(__bridge id)kSecAttrAccessibleWhenUnlocked forKey:(__bridge id)kSecAttrAccessible];
// Add
OSStatus status = SecItemAdd((__bridge CFDictionaryRef)dictionary, NULL);
// If the Addition was successful, return. Otherwise, attempt to update existing key or quit (return NO)
if (status == errSecSuccess) {
DDLogInfo(@"Success adding value for identifier: %@",identifier);
return YES;
} else if (status == errSecDuplicateItem){
DDLogInfo(@"Duplicate item, updating... %@",identifier);
return [self updateKeychainValue:value forIdentifier:identifier];
} else {
DDLogError(@"Error adding keychain item for identifier: %@",identifier);
return NO;
}
}
+ (BOOL)updateKeychainValue:(NSString *)value forIdentifier:(NSString *)identifier {
NSMutableDictionary *searchDictionary = [self setupSearchDirectoryForIdentifier:identifier];
NSMutableDictionary *updateDictionary = [[NSMutableDictionary alloc] init];
NSData *valueData = [value dataUsingEncoding:NSUTF8StringEncoding];
[updateDictionary setObject:valueData forKey:(__bridge id)kSecValueData];
// Update
OSStatus status = SecItemUpdate((__bridge CFDictionaryRef)searchDictionary,
(__bridge CFDictionaryRef)updateDictionary);
if (status == errSecSuccess) {
DDLogInfo(@"Success updating item for identifier: %@",identifier);
return YES;
} else {
DDLogError(@"Error updating item for identifier: %@",identifier);
return NO;
}
}
+ (void)deleteItemFromKeychainWithIdentifier:(NSString *)identifier {
NSMutableDictionary *searchDictionary = [self setupSearchDirectoryForIdentifier:identifier];
CFDictionaryRef dictionary = (__bridge CFDictionaryRef)searchDictionary;
//Delete
SecItemDelete(dictionary);
DDLogInfo(@"Deleted keychain item for key: %@",identifier);
}
+ (void)resetKeychain{
NSArray *secItemClasses = @[(__bridge id)kSecClassGenericPassword,
(__bridge id)kSecClassInternetPassword,
(__bridge id)kSecClassCertificate,
(__bridge id)kSecClassKey,
(__bridge id)kSecClassIdentity];
for (id secItemClass in secItemClasses) {
NSDictionary *spec = @{(__bridge id)kSecClass: secItemClass};
SecItemDelete((__bridge CFDictionaryRef)spec);
}
DDLogInfo(@"All Items has been deleted");
}
@end