Last active
December 21, 2015 08:58
-
-
Save hpique/6281461 to your computer and use it in GitHub Desktop.
A simple utility class to store/retrieve a password in/from the iOS Keychain.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// RMPasswordStore.m | |
// | |
// Created by Hermes Pique on 8/9/13. | |
// | |
// | |
#import <Foundation/Foundation.h> | |
#import <Security/Security.h> | |
@interface RMPasswordStore : NSObject | |
+ (RMPasswordStore*) defaultStore; | |
@property (nonatomic, copy) NSString *password; | |
@end | |
@implementation RMPasswordStore | |
+ (RMPasswordStore*) defaultStore | |
{ | |
static RMPasswordStore *sharedInstance = nil; | |
static dispatch_once_t onceToken; | |
dispatch_once(&onceToken, ^{ | |
sharedInstance = [[[self class] alloc] init]; | |
}); | |
return sharedInstance; | |
} | |
- (void)setPassword:(NSString *)password | |
{ | |
NSMutableDictionary *searchDictionary = [RMPasswordStore dictionaryForPasswordSearch]; | |
OSStatus status; | |
NSData *ignore; | |
if (SecItemCopyMatching((CFDictionaryRef)searchDictionary, (CFTypeRef *)&ignore) == errSecSuccess) | |
{ // Update | |
if (password == nil) | |
{ | |
status = SecItemDelete((CFDictionaryRef)searchDictionary); | |
} | |
else | |
{ | |
NSMutableDictionary *updateDictionary = [NSMutableDictionary dictionary]; | |
NSData *passwordData = [password dataUsingEncoding:NSUTF8StringEncoding]; | |
[updateDictionary setObject:passwordData forKey:(id)kSecValueData]; | |
status = SecItemUpdate((CFDictionaryRef)searchDictionary, (CFDictionaryRef)updateDictionary); | |
} | |
if (status != errSecSuccess) | |
{ | |
NSLog(@"RMPasswordStore: failed to update password with error %ld", status); | |
} | |
} | |
else if (password != nil) | |
{ // Add | |
NSData *passwordData = [password dataUsingEncoding:NSUTF8StringEncoding]; | |
[searchDictionary setObject:passwordData forKey:(id)kSecValueData]; | |
status = SecItemAdd((CFDictionaryRef)searchDictionary, NULL); | |
if (status != errSecSuccess) | |
{ | |
NSLog(@"RMPasswordStore: failed to add password with error %ld", status); | |
} | |
} | |
} | |
-(NSString*)password | |
{ | |
NSMutableDictionary *searchDictionary = [RMPasswordStore dictionaryForPasswordSearch]; | |
[searchDictionary setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit]; | |
[searchDictionary setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData]; | |
NSData *passwordData = nil; | |
OSStatus status = SecItemCopyMatching((CFDictionaryRef)searchDictionary, (CFTypeRef *)&passwordData); | |
if (status != errSecSuccess) | |
{ | |
NSLog(@"RMPasswordStore: failed to get password with error %ld", status); | |
return nil; | |
} | |
NSString *password = [[NSString alloc] initWithData:passwordData encoding:NSUTF8StringEncoding]; | |
return [password autorelease]; | |
} | |
#pragma mark - Private | |
+ (NSMutableDictionary *)dictionaryForPasswordSearch | |
{ | |
NSMutableDictionary *dictionary = [NSMutableDictionary dictionary]; | |
[dictionary setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass]; | |
static NSString *identifier = @"password"; | |
NSData *encodedIdentifier = [identifier dataUsingEncoding:NSUTF8StringEncoding]; | |
[dictionary setObject:encodedIdentifier forKey:(id)kSecAttrGeneric]; | |
[dictionary setObject:encodedIdentifier forKey:(id)kSecAttrAccount]; | |
NSString *serviceName = [NSBundle mainBundle].bundleIdentifier; | |
[dictionary setObject:serviceName forKey:(id)kSecAttrService]; | |
return dictionary; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I wanted to store a password securely in the simplest manner possible: