Skip to content

Instantly share code, notes, and snippets.

@Raztor0
Created February 21, 2017 19:25
  • Star 5 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save Raztor0/34ad0e23a410c33526c9fa1b6e8d281c to your computer and use it in GitHub Desktop.
iOS10.3 beta2 Keychain Autodelete Workaround
- (BOOL)saveToKeychain {
NSData *passwordData = [@"myPassword" dataUsingEncoding:NSUTF8StringEncoding];
/* Try to save to the keychain */
NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:3];
[dictionary setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
[dictionary setObject:@"myService" forKey:(__bridge id)kSecAttrService];
[dictionary setObject:@"myAccount" forKey:(__bridge id)kSecAttrAccount];
/* Use the kSecAttrAccessGroupToken access group constant*/
[dictionary setObject:(__bridge NSString * _Nullable)(kSecAttrAccessGroupToken) forKey:(__bridge id)kSecAttrAccessGroup];
[dictionary setObject:passwordData forKey:(__bridge id)kSecValueData];
OSStatus status = SecItemAdd((__bridge CFDictionaryRef)dictionary, NULL);
if (status != errSecSuccess) {
NSLog(@"Failed to save to keychain");
return NO;
} else {
NSLog(@"Successfully saved password to keychain");
return YES;
}
}
- (NSString *)fetchFromKeychain {
/* Try to fetch from the keychain */
NSMutableDictionary *dictionary = [NSMutableDictionary dictionaryWithCapacity:3];
[dictionary setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
[dictionary setObject:@"myService" forKey:(__bridge id)kSecAttrService];
[dictionary setObject:@"myAccount" forKey:(__bridge id)kSecAttrAccount];
/* Use the kSecAttrAccessGroupToken access group constant*/
[dictionary setObject:(__bridge NSString * _Nullable)(kSecAttrAccessGroupToken) forKey:(__bridge id)kSecAttrAccessGroup];
[dictionary setObject:@YES forKey:(__bridge id)kSecReturnData];
[dictionary setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
NSString *password;
CFTypeRef result = NULL;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)dictionary, &result);
if (status != errSecSuccess) {
NSLog(@"Error fetching from keychain");
} else {
NSData *passwordData = (__bridge_transfer NSData *)result;
password = [[NSString alloc] initWithData:passwordData encoding:NSUTF8StringEncoding];
NSLog(@"Got password from keychain: %@", password);
}
return password;
}
@Raztor0
Copy link
Author

Raztor0 commented Feb 21, 2017

Execute -saveToKeychain, delete the app, re-install the app, and then execute -fetchFromKeychain

Keychain data will still be there.

Requires >= iOS 10

@laoyur
Copy link

laoyur commented Apr 4, 2017

Can you confirm keychain will be deleted after app uninstalled in iOS 10.3(14E277) ?

@Raztor0
Copy link
Author

Raztor0 commented Dec 26, 2017

@laoyur It seems as though keychain entries continue to persist after app uninstall.

The behaviour experienced in the iOS 10.3 beta does not seem to have made it into the public releases.

Also, according to this reply: https://forums.developer.apple.com/thread/72271#224455 it seems as though the kSecAttrAccessGroup access group identifier was never meant to be written to from normal apps, only read from. So, this code should no longer be relied on.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment