Skip to content

Instantly share code, notes, and snippets.

@lukaskukacka
Last active September 18, 2023 17:22
Show Gist options
  • Save lukaskukacka/79994d0dff966b5733a80b49af9a8bca to your computer and use it in GitHub Desktop.
Save lukaskukacka/79994d0dff966b5733a80b49af9a8bca to your computer and use it in GitHub Desktop.
Keychain dumper (Obj-C). Prints all values from iOS Keychain.
@interface KeychainDumper: NSObject
- (void)dumpVerbose:(BOOL)verbose;
@end
@implementation KeychainDumper
- (void)dumpVerbose:(BOOL)verbose {
[self printString:@"##################################################################"];
[self printString:@"### KEYCHAIN DUMP ################################################"];
[self printString:@"##################################################################"];
NSMutableDictionary *query = [NSMutableDictionary new];
query[(__bridge id)kSecReturnAttributes] = (__bridge id)kCFBooleanTrue;
query[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitAll;
NSArray *allSecItemClasses = [NSArray arrayWithObjects:
(__bridge id)kSecClassGenericPassword,
(__bridge id)kSecClassInternetPassword,
(__bridge id)kSecClassCertificate,
(__bridge id)kSecClassKey,
(__bridge id)kSecClassIdentity,
nil];
for (id secItemClass in allSecItemClasses) {
[self printString:@"### Item class: %@", secItemClass];
[query setObject:secItemClass forKey:(__bridge id)kSecClass];
CFTypeRef result = NULL;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result);
if (status == errSecItemNotFound) {
[self printString:@" No items for the class."];
continue;
}
if (status != errSecSuccess) {
[self printString:@" Failed to read from keychain"];
continue;
}
if (result == NULL) {
[self printString:@" No data the class"];
continue;
}
NSArray *resultsArray = (__bridge NSArray *)result;
for (NSDictionary *itemDictionary in resultsArray) {
[self dumpData:itemDictionary verbose:verbose];
}
if (result != NULL) {
CFRelease(result);
}
}
[self printString:@"##################################################################"];
}
- (void)dumpData:(NSDictionary *)data verbose:(BOOL)verbose {
if (verbose) {
[self printString:[data description]];
return;
}
NSString *key = data[@"svce"];
if (key.length > 0) {
NSString *value = [self readKeychainValueForKey:key];
[self printString:@" %@: '%@'", key, value];
} else {
[self printString:@" <no non-verbose description, value with %ld keys in dictionary>", (unsigned long)data.count];
}
}
- (void)printString:(NSString *)format, ... {
va_list args;
va_start(args, format);
NSString *string = [[NSString alloc] initWithFormat:format arguments:args];
va_end(args);
printf("%s\n", [string UTF8String]);
}
- (nullable NSString *)readKeychainValueForKey:(NSString *)key {
NSParameterAssert(key);
NSMutableDictionary *query = [NSMutableDictionary new];
query[(__bridge id)kSecClass] = (__bridge id)kSecClassGenericPassword;
query[(__bridge id)kSecReturnData] = @YES;
query[(__bridge id)kSecAttrService] = key;
CFTypeRef result = NULL;
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result);
if (status == errSecItemNotFound) {
return nil;
}
if (status != errSecSuccess) {
NSLog(@"Failed reading value for key: '%@'", key);
return nil;
}
NSData *resultData = (__bridge_transfer NSData *)result;
return [[NSString alloc] initWithData:resultData encoding:NSUTF8StringEncoding];
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment