30 #import "SFHFKeychainUtils.h"
31 #import <Security/Security.h>
33 static NSString *SFHFKeychainUtilsErrorDomain =
@"SFHFKeychainUtilsErrorDomain";
35 #if __IPHONE_OS_VERSION_MIN_REQUIRED < 30000 && TARGET_IPHONE_SIMULATOR
36 @interface SFHFKeychainUtils (PrivateMethods)
37 + (SecKeychainItemRef)getKeychainItemReferenceForUsername:(NSString *)username
38 andServerName:(NSString *)serverName
39 error:(NSError **)error;
45 #if __IPHONE_OS_VERSION_MIN_REQUIRED < 30000 && TARGET_IPHONE_SIMULATOR
47 + (NSString *)getPasswordForUsername:(NSString *)username
48 andServerName:(NSString *)serverName
49 error:(NSError **)error
51 if (!username || !serviceName)
53 *error = [NSError errorWithDomain:SFHFKeychainUtilsErrorDomain code:-2000 userInfo:nil];
57 SecKeychainItemRef item = [
SFHFKeychainUtils getKeychainItemReferenceForUsername:username
58 andServerName:serverName
69 SecKeychainAttribute attributes[8];
70 SecKeychainAttributeList list;
72 attributes[0].tag = kSecAccountItemAttr;
73 attributes[1].tag = kSecDescriptionItemAttr;
74 attributes[2].tag = kSecLabelItemAttr;
75 attributes[3].tag = kSecModDateItemAttr;
78 list.attr = attributes;
80 OSStatus status = SecKeychainItemCopyContent(item, NULL, &list, &length, (
void **)&password);
84 *error = [NSError errorWithDomain:SFHFKeychainUtilsErrorDomain code:status userInfo:nil];
88 NSString *passwordString = nil;
92 char passwordBuffer[1024];
98 strncpy(passwordBuffer, password, length);
100 passwordBuffer[length] =
'\0';
101 passwordString = [NSString stringWithCString:passwordBuffer encoding:NSUTF8StringEncoding];
104 SecKeychainItemFreeContent(&list, password);
108 return passwordString;
111 + (void)storeUsername:(NSString *)username
112 andPassword:(NSString *)password
113 forServerName:(NSString *)serverName
114 updateExisting:(BOOL)updateExisting
115 error:(NSError **)error
117 if (!username || !password || !serverName)
119 *error = [NSError errorWithDomain:SFHFKeychainUtilsErrorDomain code:-2000 userInfo:nil];
123 OSStatus status = noErr;
125 SecKeychainItemRef item = [
SFHFKeychainUtils getKeychainItemReferenceForUsername:username
126 andServerName:serverName
129 if (*error && [*error code] != noErr)
138 status = SecKeychainItemModifyAttributesAndData(item, NULL, strlen([password UTF8String]),
139 [password UTF8String]);
145 status = SecKeychainAddGenericPassword(
146 NULL, strlen([serverName UTF8String]), [serverName UTF8String],
147 strlen([username UTF8String]), [username UTF8String], strlen([password UTF8String]),
148 [password UTF8String], NULL);
153 *error = [NSError errorWithDomain:SFHFKeychainUtilsErrorDomain code:status userInfo:nil];
157 + (void)deleteItemForUsername:(NSString *)username
158 andServerName:(NSString *)serverName
159 error:(NSError **)error
161 if (!username || !serverName)
163 *error = [NSError errorWithDomain:SFHFKeychainUtilsErrorDomain code:2000 userInfo:nil];
169 SecKeychainItemRef item = [
SFHFKeychainUtils getKeychainItemReferenceForUsername:username
170 andServerName:serverName
173 if (*error && [*error code] != noErr)
182 status = SecKeychainItemDelete(item);
189 *error = [NSError errorWithDomain:SFHFKeychainUtilsErrorDomain code:status userInfo:nil];
193 + (SecKeychainItemRef)getKeychainItemReferenceForUsername:(NSString *)username
194 andServerName:(NSString *)serverName
195 error:(NSError **)error
197 if (!username || !serverName)
199 *error = [NSError errorWithDomain:SFHFKeychainUtilsErrorDomain code:-2000 userInfo:nil];
205 SecKeychainItemRef item;
207 OSStatus status = SecKeychainFindGenericPassword(
208 NULL, strlen([serverName UTF8String]), [serverName UTF8String],
209 strlen([username UTF8String]), [username UTF8String], NULL, NULL, &item);
213 if (status != errSecItemNotFound)
215 *error = [NSError errorWithDomain:SFHFKeychainUtilsErrorDomain
228 + (NSString *)getPasswordForUsername:(NSString *)username
229 andServerName:(NSString *)serverName
230 error:(NSError **)error
232 if (!username || !serverName)
236 *error = [NSError errorWithDomain:SFHFKeychainUtilsErrorDomain code:-2000 userInfo:nil];
249 NSArray *keys = [[[NSArray alloc]
250 initWithObjects:(NSString *)kSecClass, kSecAttrAccount, kSecAttrService, nil] autorelease];
251 NSArray *objects = [[[NSArray alloc] initWithObjects:(NSString *)kSecClassGenericPassword,
252 username, serverName, nil] autorelease];
254 NSMutableDictionary *query = [[[NSMutableDictionary alloc] initWithObjects:objects
255 forKeys:keys] autorelease];
262 NSDictionary *attributeResult = NULL;
263 NSMutableDictionary *attributeQuery = [query mutableCopy];
264 [attributeQuery setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnAttributes];
266 SecItemCopyMatching((CFDictionaryRef)attributeQuery, (CFTypeRef *)&attributeResult);
268 [attributeResult release];
269 [attributeQuery release];
274 if (error != nil && status != errSecItemNotFound)
277 *error = [NSError errorWithDomain:SFHFKeychainUtilsErrorDomain
287 NSData *resultData = nil;
288 NSMutableDictionary *passwordQuery = [query mutableCopy];
289 [passwordQuery setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData];
291 status = SecItemCopyMatching((CFDictionaryRef)passwordQuery, (CFTypeRef *)&resultData);
293 [resultData autorelease];
294 [passwordQuery release];
298 if (status == errSecItemNotFound)
308 *error = [NSError errorWithDomain:SFHFKeychainUtilsErrorDomain
318 *error = [NSError errorWithDomain:SFHFKeychainUtilsErrorDomain
327 NSString *password = nil;
331 password = [[NSString alloc] initWithData:resultData encoding:NSUTF8StringEncoding];
340 *error = [NSError errorWithDomain:SFHFKeychainUtilsErrorDomain code:-1999 userInfo:nil];
344 return [password autorelease];
347 + (BOOL)storeUsername:(NSString *)username
348 andPassword:(NSString *)password
349 forServerName:(NSString *)serverName
350 updateExisting:(BOOL)updateExisting
351 error:(NSError **)error
353 if (!username || !password || !serverName)
357 *error = [NSError errorWithDomain:SFHFKeychainUtilsErrorDomain code:-2000 userInfo:nil];
363 NSError *getError = nil;
365 andServerName:serverName
368 if ([getError code] == -1999)
376 [
self deleteItemForUsername:username andServerName:serverName error:&getError];
378 if ([getError code] != noErr)
387 else if ([getError code] != noErr)
401 OSStatus status = noErr;
403 if (existingPassword)
408 if (![existingPassword isEqualToString:password] && updateExisting)
413 [[[NSArray alloc] initWithObjects:(NSString *)kSecClass, kSecAttrService,
414 kSecAttrLabel, kSecAttrAccount, nil] autorelease];
417 [[[NSArray alloc] initWithObjects:(NSString *)kSecClassGenericPassword, serverName,
418 serverName, username, nil] autorelease];
420 NSDictionary *query = [[[NSDictionary alloc] initWithObjects:objects
421 forKeys:keys] autorelease];
423 status = SecItemUpdate(
424 (CFDictionaryRef)query,
425 (CFDictionaryRef)[NSDictionary
426 dictionaryWithObject:[password dataUsingEncoding:NSUTF8StringEncoding]
427 forKey:(NSString *)kSecValueData]);
436 [[[NSArray alloc] initWithObjects:(NSString *)kSecClass, kSecAttrService, kSecAttrLabel,
437 kSecAttrAccount, kSecValueData, nil] autorelease];
439 NSArray *objects = [[[NSArray alloc]
440 initWithObjects:(NSString *)kSecClassGenericPassword, serverName, serverName, username,
441 [password dataUsingEncoding:NSUTF8StringEncoding], nil] autorelease];
443 NSDictionary *query = [[[NSDictionary alloc] initWithObjects:objects
444 forKeys:keys] autorelease];
446 status = SecItemAdd((CFDictionaryRef)query, NULL);
449 if (error != nil && status != noErr)
452 *error = [NSError errorWithDomain:SFHFKeychainUtilsErrorDomain code:status userInfo:nil];
460 + (BOOL)deleteItemForUsername:(NSString *)username
461 andServerName:(NSString *)serverName
462 error:(NSError **)error
464 if (!username || !serverName)
468 *error = [NSError errorWithDomain:SFHFKeychainUtilsErrorDomain code:-2000 userInfo:nil];
479 [[[NSArray alloc] initWithObjects:(NSString *)kSecClass, kSecAttrAccount, kSecAttrService,
480 kSecReturnAttributes, nil] autorelease];
482 [[[NSArray alloc] initWithObjects:(NSString *)kSecClassGenericPassword, username,
483 serverName, kCFBooleanTrue, nil] autorelease];
485 NSDictionary *query = [[[NSDictionary alloc] initWithObjects:objects forKeys:keys] autorelease];
487 OSStatus status = SecItemDelete((CFDictionaryRef)query);
489 if (error != nil && status != noErr)
491 *error = [NSError errorWithDomain:SFHFKeychainUtilsErrorDomain code:status userInfo:nil];