Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iCloud sync keychain

In my app, I want to be able to sync a configuration that gets created by the user. I wanted to use iCloud to sync that configuration so that it is always the same on all devices. But, I use the keychain to store the password.

Is there a way to also sync keychain data?

like image 912
Nic Hubbard Avatar asked Jul 15 '12 06:07

Nic Hubbard


People also ask

How do I sync my iPhone with iCloud Keychain?

On your iPhone, iPad, or iPod touch, tap Settings > [your name] > iCloud > Keychain > Advanced. On your Mac, choose Apple menu  > System Preferences, then click Apple ID. Click iCloud in the sidebar, then select Keychain. If you're using macOS Mojave or earlier, click iCloud, then click Options next to Keychain.

Does Apple Keychain sync across devices?

iCloud Keychain can also keep the accounts you use in Mail, Contacts, Calendar, and Messages up to date across all your iPhone and iPad devices and Mac computers.

Is Apple Keychain backed up to iCloud?

When a user backs up iPhone data, the keychain data is backed up but the secrets in the keychain remain encrypted in the backup. The keychain password is not included in the backup.


2 Answers

iCloud Keychain is a new feature in iOS 7.0.3 and OS X Mavericks 10.9. Specify the kSecAttrSynchronizable attribute when adding a keychain item using the SecItem API.

like image 98
jrc Avatar answered Oct 02 '22 13:10

jrc


These are the utility methods I've made for keychain. kSecAttrSynchronizable is what makes iCloud Sync work. Hope they help.

  • Keychain Query.
  • Remove item
  • Delete item
  • Save item
  • Load item

    + (NSMutableDictionary *)getKeychainQuery:(NSString *)service {
        return [NSMutableDictionary dictionaryWithObjectsAndKeys:
                (__bridge id)kSecClassGenericPassword, (__bridge id)kSecClass,
                service, (__bridge id)kSecAttrService,
                service, (__bridge id)kSecAttrAccount,
                service, (__bridge id)kSecAttrSynchronizable,
                (__bridge id)kSecAttrAccessibleAfterFirstUnlock, (__bridge id)kSecAttrAccessible,
                nil];
    }
    
    + (void)save:(NSString *)service data:(id)data {
        NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
        SecItemDelete((__bridge CFDictionaryRef)keychainQuery);
        [keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(__bridge id)kSecValueData];
        SecItemAdd((__bridge CFDictionaryRef)keychainQuery, NULL);
    }
    
    + (void)remove:(NSString *)service {
         NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
         SecItemDelete((__bridge CFDictionaryRef)keychainQuery);
    }
    
    +(NSString *)keychainItem:(NSString *)service{
        id data = [self load:service];
    
        if([data isKindOfClass:[NSString class]]){
            return data;
        }
        return @"";
    }
    
    + (id)load:(NSString *)service {
        id ret = nil;
        NSMutableDictionary *keychainQuery = [self getKeychainQuery:service];
        [keychainQuery setObject:(id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];
        [keychainQuery setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
        CFDataRef keyData = NULL;
        if (SecItemCopyMatching((__bridge CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) {
            @try {
                ret = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge NSData *)keyData];
            }
            @catch (NSException *e) {
                NSLog(@"Unarchive of %@ failed: %@", service, e);
             }
            @finally {}
        }
        if (keyData) CFRelease(keyData);
        return ret;
    }
    
like image 31
Gautam Jain Avatar answered Oct 02 '22 14:10

Gautam Jain