30#import "SFHFKeychainUtils.h" 
   31#import <Security/Security.h> 
   33static 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];