KeyChine的使用

转载 2015年11月21日 18:59:54

[转]iOS开发 -- KeyChain使用与共享数据

2014-5-1阅读1805 评论0

keyChain是iOS提供的一种安全保存私密数据的方式,整个系统的keychain被保存在/private/var/Keychains/keychain-2.db中,其中保存的数据是经过加密的(不过上有政策下有对策,越狱后导出keychain变为可能,请看我下篇文章)


keychain优点:

1.每个组(keychain-access-groups)之间数据访问隔离,没有权限的app如何读取他人数据,保证了数据安全。

2.全局统一存储,即使删除了app,keychain里的数据也还在,下次重新安装app后依然能访问

3.存储后的数据加密

4.同一个组的app可以共享keychain中的数据

5.暂时想不到了,求大伙补充


keychain缺点:

1.删除app后不会自动清除keychain里的数据,如果存储密码等敏感数据会有一定风险(越狱后keychain能被导出来)

2.有可能会速度略慢(原因是最近无意间导了台4s的keychain的数据库文件出来一看,好家伙,几万条数据,估计有和长年积累有关,也估计是有不少app已经把它当kv数据库用了····无语···)

3.暂时想不到了,求大伙补充


keychain使用:

好,先不几人忧天,言归正传先看看如何使用它。

keychain的读取和写入都有点类似组装一个查询条件然后传给Security.framework里的接口去做。首先new一个工程,导入Security.framework,然后写一个工具类如下:

#import <Foundation/Foundation.h>
#import <Security/Security.h>


@interface CHKeychain : NSObject

+ (void)save:(NSString *)service account:(NSString *)acc data:(NSData *)data;
+ (void)save:(NSString *)service data:(NSData *)data;

+ (NSData *)load:(NSString *)service;
+ (NSData *)load:(NSString *)service account:(NSString *)acc;


+ (void)delete:(NSString *)service;
+ (void)delete:(NSString *)service account:(NSString *)acc;
@end

//
//  CHKeychain.m
//  CleanWBKeyChain
//
//  Created by iBcker on 14-4-30.
//  Copyright (c) 2014年 iBcker. All rights reserved.
//

#import "CHKeychain.h"

@implementation CHKeychain
+ (NSMutableDictionary *)getKeychainQuery:(NSString *)service account:(NSString *)acc{
    NSMutableDictionary *dicx = [NSMutableDictionary dictionaryWithObjectsAndKeys:
            (__bridge_transfer id)kSecClassGenericPassword,(__bridge_transfer id)kSecClass,
            nil];
    if (acc) {
        dicx[(__bridge_transfer id)kSecAttrAccount]=acc;
    }
    if (service) {
        dicx[(__bridge_transfer id)kSecAttrService]=service;
    }
    return dicx;
}

+ (void)save:(NSString *)service account:(NSString *)acc data:(NSData *)data
{
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:service account:acc];
    SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery);
    [keychainQuery setObject:data forKey:(__bridge_transfer id)kSecValueData];
    SecItemAdd((__bridge_retained CFDictionaryRef)keychainQuery, NULL);
}

+ (void)save:(NSString *)service data:(id)data {
    [[self class] save:service account:service data:data];
}

+ (NSData *)load:(NSString *)service account:(NSString *)acc
{
    NSData *ret = nil;
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:service account:acc];
    [keychainQuery setObject:(__bridge_transfer id)kCFBooleanTrue forKey:(__bridge_transfer id)kSecReturnData];
    [keychainQuery setObject:(__bridge_transfer id)kSecMatchLimitOne forKey:(__bridge_transfer id)kSecMatchLimit];
    CFDataRef keyData = NULL;
    if (SecItemCopyMatching((__bridge_retained CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) {
        ret = (__bridge_transfer NSData*)keyData;
    }
    if (keyData)
        CFRelease(keyData);
    return ret;
}

+ (NSData *)load:(NSString *)service {
   return [[self class] load:service account:service];
}

+ (void)delete:(NSString *)service {
   return [[self class] delete:service account:service];
}

+ (void)delete:(NSString *)service account:(NSString *)acc
{
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:service account:acc];
    SecItemDelete((__bridge_retained CFDictionaryRef)keychainQuery);
}
@end

然后使用的话就直接

        //写
        [CHKeychain save:@"uname" data:[@"xiaoxiao" dataUsingEncoding:NSUTF8StringEncoding]];
        [CHKeychain save:@"pwd" data:[@"123" dataUsingEncoding:NSUTF8StringEncoding]];
        
        //读
        NSData *nameData =[CHKeychain load:@"uname"];
        NSLog(@"name:%@",[[NSString alloc] initWithData:nameData encoding:NSUTF8StringEncoding]);


不过这只是举个例子,建议不要这么直接存,原因见上面提到的 keychain的缺点。所以建议大家可以把多条数据合并在一起然后再存,例如可以改为:

<span style="padding: 0px; margin: 0px;">	</span>//写
        NSDictionary *userInfo = @{@"uname":@"xiaoxiao",@"pwd":@"123"};
        [CHKeychain save:@"userInfo" data:[NSKeyedArchiver archivedDataWithRootObject:userInfo]];
        //读
        NSData *userData =[CHKeychain load:@"userInfo"];
        NSLog(@"userInfo:%@",[NSKeyedUnarchiver unarchiveObjectWithData:userData]);

当然,我个人还是建议先在代码里把数据进行一定的加密后再存入kechain,以加大逆向的难度



keychain数据共享:

如果我们有多个APP,他们之间又需要互相共享一下数据,那么我可以考虑下使用keychain进行数据共享。

首先我们需要新建一个权限申明文件,例如新建一 keychain.entitlements  ,上传了一个给需要的人(http://download.csdn.net/detail/u011690307/7279715

拖入xcode中,效果如下:




并且在build setting里面的Code Signing Entitlements填上keychain.entitlements





作用是定义我们能访问的组有$(AppIdentifierPrefix)*和$(AppIdentifierPrefix)$(CFBundleIdentifier),AppIdentifierPrefix为App的前缀,例如这串数字






例如你的AppIdentifierPrefix为7H96H3XX,那么$(AppIdentifierPrefix)*就代表7H96H3XX.*  ,$(AppIdentifierPrefix)$(CFBundleIdentifier)就代表7H96H3XX.com.xxx.xxx

注意,访问权限是你定义的所有item,而默认写入组是这些item的第一个。也就是说如果你现在写入keychain,那么所属组就是7H96H3XX.*,其他app也需要能访问7H96H3XX.*才能

读取到你的数据。如果不想让别人读取到你的数据,可以改为$(AppIdentifierPrefix)$(CFBundleIdentifier)在前面。


最后还需要提醒一点的是,如果你的帐号有多个AppIdentifierPrefix(team帐号),一需要确认一下你的mobileprovision文件里面的keychain-access-groups是否和你的keychain.entitlements文件定义的一致,否则xcode会报错。具体查看mobileprovision的方法是:命令行cat一下


定义好这些之后,就再new一个工程来看看能不能互相访问彼此存的数据吧,enjoy it。

安卓项目框架,可直接使用。

  • 2017年12月13日 16:12
  • 420KB
  • 下载

使用openssl库进行DES加密

openssl库实现了大多数的加密算法,如AES,DES,RSAdend
  • p0x1307
  • p0x1307
  • 2014年10月15日 19:35
  • 2965

定时器的使用

  • 2017年12月13日 09:44
  • 170KB
  • 下载

用openSSL创建证书,然后在tomcat上配置https使用

用openSSL创建证书OpenSSL功能远胜于KeyTool,可用于根证书,服务器证书和客户证书的管理下面给出如何用OpenSSL创建自己签名的证书,这个证书可以做为SSL服务器的证书。Git在安装...

MFC Flash的简单使用

  • 2017年12月12日 13:18
  • 93.56MB
  • 下载

如何在Linux上安装和使用MS SQL Server

今年早些时候,微软宣布他们的将MS SQL Server运行在Linux上的计划震惊了IT界。在Satya Nadella的领导下,微软这个雷德蒙德的巨头在Linux主导的产业(如快速推动云的技术)方...

CAM350使用教程

  • 2017年12月11日 16:26
  • 1.38MB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:KeyChine的使用
举报原因:
原因补充:

(最多只允许输入30个字)