Skip to content

Instantly share code, notes, and snippets.

@adil-hussain-84
Last active May 25, 2017 10:55
Show Gist options
  • Save adil-hussain-84/ce3d60a03adfab001399b76c6908e97c to your computer and use it in GitHub Desktop.
Save adil-hussain-84/ce3d60a03adfab001399b76c6908e97c to your computer and use it in GitHub Desktop.
Helper class which adds/gets/deletes entries in the iOS Keychain
//
// Class modified from this GitHub repository:
// https://github.com/jeremangnr/JNKeychain
//
#import <Foundation/Foundation.h>
@interface MJRKeychainStorage : NSObject
/**
@abstract Saves the given key-value pair to the Keychain.
@param value The value to save.
@param key The key identifying the value to save.
@return YES iff the key-value pair was saved successfully.
*/
- (BOOL)saveValue:(id)value forKey:(NSString *)key;
/**
@abstract Loads the value from the Keychain which matches the given key.
@param key The key identifying the value to load.
@return The value identified by key, or nil in case of error.
*/
- (id)getValueForKey:(NSString *)key;
/**
@abstract Deletes the given key from the Keychain.
@param key The key identifying the key-value pair to delete.
@return YES iff either there is no such key in the Keychain or deletion was successful.
*/
- (BOOL)deleteKey:(NSString *)key;
@end
//
// Class modified from this GitHub repository:
// https://github.com/jeremangnr/JNKeychain
//
#import "MJRKeychainStorage.h"
@implementation MJRKeychainStorage
- (BOOL)saveValue:(id)value forKey:(NSString *)key {
[self deleteKey:key];
NSMutableDictionary *query = [self getQueryForKey:key];
query[(__bridge id) kSecValueData] = [NSKeyedArchiver archivedDataWithRootObject:value];
OSStatus status = SecItemAdd((__bridge CFDictionaryRef) query, NULL);
return status == errSecSuccess;
}
- (id)getValueForKey:(NSString *)key {
NSMutableDictionary *query = [self getQueryForKey:key];
query[(__bridge id) kSecReturnData] = (__bridge id) kCFBooleanTrue;
query[(__bridge id) kSecMatchLimit] = (__bridge id) kSecMatchLimitOne;
CFDataRef keyData = NULL;
id value = nil;
if (SecItemCopyMatching((__bridge CFDictionaryRef) query, (CFTypeRef *) &keyData) == noErr) {
@try {
value = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge NSData *) keyData];
}
@catch (NSException *e) {
value = nil;
}
@finally {
//nothing to do
}
}
if (keyData) {
CFRelease(keyData);
}
return value;
}
- (BOOL)deleteKey:(NSString *)key {
NSMutableDictionary *query = [self getQueryForKey:key];
OSStatus status = SecItemDelete((__bridge CFDictionaryRef) query);
return (status == errSecSuccess) || (status == errSecItemNotFound);
}
#pragma mark - Private methods
- (NSMutableDictionary *)getQueryForKey:(NSString *)key {
NSMutableDictionary *query = [NSMutableDictionary dictionary];
query[(__bridge id) kSecClass] = (__bridge id) kSecClassGenericPassword;
query[(__bridge id) kSecAttrService] = key;
query[(__bridge id) kSecAttrAccount] = key;
query[(__bridge id) kSecAttrAccessible] = (__bridge id) kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly;
return query;
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment