Keychain的使用
iOS的keychain服务提供了一种安全的保存私密信息(密码,序列号,证书等)的方式,每个ios程序都有一个独立的keychain存储。
用于储存一些私密信息,比如密码、证书等等,Keychain里保存的信息不会因App被删除而丢失,在用户重新安装App后依然有效。
同样也适用于应用之间数据共享。我们可以把KeyChain理解为一个Dictionary,所有数据都以key-value的形式存储,可以对这个Dictionary进行add、update、get、delete这四个操作。
使用苹果官方发布的KeychainItemWrapper或者SFHFKeychainUtils很方便。
或使用第三方Keychain框架:https://github.com/samsoffes/sskeychain。
使用
1、需要导入框架Security.framework
2、需要添加头文件 #import<Security/Security.h>
3、iOS中Security.framework框架提供了四个主要的方法来操作KeyChain:
查询:OSStatus SecItemCopyMatching(CFDictionaryRef query, CFTypeRef*result);
添加:OSStatus SecItemAdd(CFDictionaryRef attributes, CFTypeRef *result);
更新:KeyChain中的ItemOSStatus SecItemUpdate(CFDictionaryRef query, CFDictionaryRefattributesToUpdate);
删除:KeyChain中的ItemOSStatus SecItemDelete(CFDictionaryRef query)
位置查看:
使用Keychain-Dumper导出keychain数据
https://github.com/ptoomey3/Keychain-Dumper
操作步骤极其简单:
1)赋予Keychain数据库可读权限
Primer:~ root
# cd /private/var/Keychains/
Primer:/private/var/Keychains root
# ls
TrustStore.sqlite3 accountStatus.plist caissuercache.sqlite3 keychain-2.db keychain-2.db-shm keychain-2.db-wal ocspcache.sqlite3 ocspcache.sqlite3-shm ocspcache.sqlite3-wal
Primer:/private/var/Keychains root
# chmod +r keychain-2.db
2)使用Keychain-Dumper导出Keychain
Primer:/private/var/Keychains root
# /your_path/keychain_dumper >keychain-export.txt
然后拷贝到本地查看,到底iOS系统和第三方应用都存放了哪些信息,就一览无余了。
代码示例:
(1)系统原生
/********************************************************************/
+(void)saveValue:(NSString *)value key:(NSString *)key
{
if ((value && 0 != value.length)&& (key && 0 != key.length))
{
NSMutableDictionary *dict =(NSMutableDictionary *)[self load:keyChainSave];
if (dict == nil)
{
dict = [NSMutableDictionarydictionary];
}
[dict setObject:value forKey:key];
[self save:keyChainSave data:dict];
}
}
+ (NSString*)getValueWithKey:(NSString *)key
{
if (key && 0 != key.length)
{
NSMutableDictionary *dict = (NSMutableDictionary*)[self load:keyChainSave];
NSString *value = [dictobjectForKey:key];
return value;
}
return nil;
}
+(void)deleteValueWithKey:(NSString *)key
{
if (key && 0 != key.length)
{
NSMutableDictionary *dict =(NSMutableDictionary *)[self load:keyChainSave];
[dict removeObjectForKey:key];
[self save:keyChainSave data:dict];
}
}
+(void)deleteValue
{
[self delete:keyChainSave];
}
/********************************************************************/
+(NSMutableDictionary *)getKeychainQuery:(NSString *)service
{
return [NSMutableDictionarydictionaryWithObjectsAndKeys:
(__bridge_transferid)kSecClassGenericPassword,(__bridge_transfer id)kSecClass,
service, (__bridge_transferid)kSecAttrService,
service, (__bridge_transferid)kSecAttrAccount,
(__bridge_transferid)kSecAttrAccessibleAfterFirstUnlock,(__bridge_transfer id)kSecAttrAccessible,
nil];
}
+(void)save:(NSString *)service data:(id)data
{
//Get search dictionary
NSMutableDictionary *keychainQuery = [selfgetKeychainQuery:service];
//Delete old item before add new item
SecItemDelete((__bridge_retainedCFDictionaryRef)keychainQuery);
//Add new object to searchdictionary(Attention:the data format)
[keychainQuery setObject:[NSKeyedArchiverarchivedDataWithRootObject:data] forKey:(__bridge_transfer id)kSecValueData];
//Add item to keychain with the searchdictionary
SecItemAdd((__bridge_retainedCFDictionaryRef)keychainQuery, NULL);
}
+(id)load:(NSString *)service
{
id ret = nil;
NSMutableDictionary *keychainQuery = [selfgetKeychainQuery:service];
//Configure the search setting
[keychainQuery setObject:(id)kCFBooleanTrueforKey:(__bridge_transfer id)kSecReturnData];
[keychainQuery setObject:(__bridge_transferid)kSecMatchLimitOne forKey:(__bridge_transfer id)kSecMatchLimit];
CFDataRef keyData = NULL;
if (SecItemCopyMatching((__bridge_retainedCFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr)
{
@try
{
ret = [NSKeyedUnarchiverunarchiveObjectWithData:(__bridge_transfer NSData *)keyData];
}
@catch (NSException *e)
{
NSLog(@"Unarchive of %@failed: %@", service, e);
}
@finally
{
}
}
return ret;
}
+(void)delete:(NSString *)service
{
NSMutableDictionary *keychainQuery = [selfgetKeychainQuery:service];
SecItemDelete((__bridge_retainedCFDictionaryRef)keychainQuery);
}
/********************************************************************/
(2)第三方框架SSKeychain