iOS Keychain,SSKeychain,使用 理解 原理_RabinRow的博客-程序员宅基地

https://www.cnblogs.com/m4abcd/p/5242254.html

Keychain 使用? ---为了实用最大化我觉得我应该直接先说使用!

当然是使用第三方库啦:sskeychain 3000+星星的库不开玩笑。github地址:https://github.com/soffes/sskeychain

导入完之后首先,编译一下有无错。

如果是自己手动导入:

1.把SSKeychain.h SSKeychain.m SSKeychainQuery.h SSKeychainQuery.m 复制到工程

2.添加Security.framework 怎么添加?点一下那个+ 

 

3.SSKeychain.h有错?把SSKeychain.h 中的#import <SSKeychain/SSKeychainQuery.h> 换成 #import <Foundation/Foundation.h> #import "SSKeychainQuery.h" 吧。

还有错?作为小白我的也不知道了,发我邮件一起讨论吧。

 

 

接下来演示4个过程

基本说明:储存的数据有三个 1.服务名(这个方便对账号密码进行分类)2.账号3.密码 而这三个数据都是NSString (如果要存其他类型呢,请看后面吧)

所用到的API :

添加和更新都用这个: + (BOOL)setPassword:(NSString *)password forService:(NSString *)serviceName account:(NSString *)account ;

查询密码:+ (NSString *)passwordForService:(NSString *)serviceName account:(NSString *)account;

删除:+ (BOOL)deletePasswordForService:(NSString *)serviceName account:(NSString *)account;

1.添加一条钥匙    (这个钥匙的信息 由 服务名+账号+密码 组成)

记得添加头文件

#import "SSKeychain.h"

#import "SSKeychainQuery.h"

 

//先定义一下要用的东东

    NSString *serviceName@"com.keychaintest.data";

    NSString *account = @"m4abcd";

    NSString *password = @"12345678";

//加入钥匙串!

    if ([SSKeychain setPassword:password forService:serviceName account:account]) {

        NSLog(@"success !");

    }

说明:就是这么简单咯。

2.查询

1.查询某service 下 count 的密码并且打印出来:

  NSLog(@"%@",[SSKeychain passwordForService:serviceName account:account]);

2.查询service下所有钥匙:

     NSArray *keys = [SSKeychain accountsForService:serviceName];

这是我的输出:

2016-03-04 15:08:43.785 keychaintest[31342:4403403] (

        {

        acct = m4abcd;

        agrp = test;

        cdat = "2016-03-03 07:10:58 +0000";

        mdat = "2016-03-04 07:08:43 +0000";

        pdmn = ak;

        svce = "com.keychaintest.data";

        sync = 0;

        tomb = 0;

    }

)

说明:返回的结果为数组,数组成员就是我们查询的钥匙,这里只有一个钥匙,而钥匙信息以字典的形式构建的,键acct 就是count,键svce 就是serviceName。密码在哪里?用方法1去取吧骚年!

3.查询本appkeychain的所有钥匙

  NSArray *keys = [SSKeychain allAccounts]; 

3.更新

    if([SSKeychain setPassword:@"321321" forService:serviceName account:account]){

    NSLog(@"set success!");

  }

4.删除 

  if([SSKeychain deletePasswordForService:serviceName account:account]){

    NSLog(@"delete success!");

  }

 说明:删除就是把这一条钥匙删除哦,不是只删除密码!

另外的说明:如果你的password 是NSData 

查询: + (NSData *)passwordDataForService:(NSString *)serviceName account:(NSString *)account;

设置or更新:+ (BOOL)setPasswordData:(NSData *)password forService:(NSString *)serviceName account:(NSString *)account;

 

下面开始浅浅的理解还有对苹果API进行一点点说明吧

1.Keychain 是什么?

keychain 就是放钥匙柜子!就是苹果提供给我们的一个保险柜。

这篇文章仅针对iOS。

在iOS中每个APP 都有属于自己的Keychain,最常用就是保存用户的账户和密码,就是记住密码,放在这里很安全(苹果负责帮我们加密再存起来,如果出了问题怪他咯!),假如用NSUserDefault 保存这些秘密数据,生成的plist文件(就放在那个Library/Preferences 下)容易被拿到,而且还要自己做加密。

特性:1.当app删除了,又再次重新安装,这个保险柜里的信息还存在哦。 所以当你的某女同学登了APP并保存了密码,你重装了APP,如果不删除记录,你女票还是可以发现的。

   2.安全!作为小白的我并不知道它实际上是存在哪里的。

2.Keychain 组成?

1.组成部分由  {N个标签(属性) + 一个重要数据} 组成!

2.结构可以看成是一个字典的形式大概是这样的: @{@"属性key1":@"属性值1",@"属性keyN":@"属性值N",@"valueData":@数据} 

3.内容说明:

一个重要数据:就是密码password!

N个标签:也是属性,都是用来表明这条钥匙的,如我们的serviceName ,account 都是属性,他们对应的键为 kSecAttrAccount 和 kSecAttrAccount,还有系统给我们加的创建时间,修改时间等还有label,type,port,你自己打开文件进去看看吧,这些标签的任务就是来表明这条钥匙是独一无二的。 

3.原始API操作

先来看看几个API

添加钥匙:        OSStatus SecItemAdd(CFDictionaryRef attributes, CFTypeRef * __nullable CF_RETURNS_RETAINED result)

查询密码与查询标签:     OSStatus SecItemCopyMatching(CFDictionaryRef query, CFTypeRef * __nullable CF_RETURNS_RETAINEDresult)

更新钥匙信息:             OSStatus SecItemUpdate(CFDictionaryRef query, CFDictionaryRef attributesToUpdate)

删除钥匙:        OSStatus SecItemDelete(CFDictionaryRef query)

先说明一下 这些API的关键在于1.是理解和配置好这个操作字典 2.注意返回的OSStatus 状态 3.CF对象与OC 之间的bridge

1.先来一发查找  

过程:

1.(关键)先配置一个操作字典内容有:

kSecAttrService(属性),kSecAttrAccount(属性) 这些属性or标签是查找的依据

kSecReturnData(值为@YES 表明返回类型为data),kSecClass(值为kSecClassGenericPassword 表示重要数据为“一般密码”类型) 这些限制条件是返回结果类型的依据

2.然后用查找的API 得到查找状态和返回数据(密码)

3.最后如果状态成功那么将数据(密码)转换成string 返回

//用原生的API 实现查询密码

- (NSString *)passwordForService:(nonnull NSString *)service account:(nonnull NSString *)account{

//生成一个查询用的 可变字典

    NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithCapacity:4];

    [dict setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass]; //表明为一般密码可能是证书或者其他东西

    [dict setObject:service forKey:(__bridge id)kSecAttrService];    //输入service

    [dict setObject:account forKey:(__bridge id)kSecAttrAccount];  //输入account

    [dict setObject:@YES forKey:(__bridge id)kSecReturnData];     //返回Data

//查询    

    OSStatus status = -1;

    CFTypeRef result = NULL;

    status = SecItemCopyMatching((__bridge CFDictionaryRef)dict,&result);//核心API 查找是否匹配 和返回密码!

    if (status != errSecSuccess) { //判断状态

        return nil;

    }

//返回数据

    NSString *password = [[NSString allocinitWithData:(__bridge_transfer NSData *)result encoding:NSUTF8StringEncoding];//转换成string

    return password;

}

说明:其实关键就在于这个操作字典的配置上!

2.添加&更新

说明:当添加的时候我们一般需要判断一下当前钥匙串里面是否已经存在我们要添加的钥匙。如果已经存在我们就更新好了,不存在再添加,所以这两个操作一般写成一个函数搞定吧。

过程关键:1.检查是否已经存在 构建的查询用的操作字典:kSecAttrService,kSecAttrAccount,kSecClass(标明存储的数据是什么类型,值为kSecClassGenericPassword 就代表一般的密码)

   2.添加用的操作字典: kSecAttrService,kSecAttrAccount,kSecClass,kSecValueData

   3.更新用的操作字典1(用于定位需要更改的钥匙):kSecAttrService,kSecAttrAccount,kSecClass 

        操作字典2(新信息)kSecAttrService,kSecAttrAccount,kSecClass ,kSecValueData

 

//用原生的API 添加一条钥匙

-(BOOL)addItemWithService:(NSString *)service account:(NSString *)account password:(NSString *)password{

//先查查是否已经存在

//构造一个操作字典用于查询

    NSMutableDictionary *searchDict = [[NSMutableDictionary alloc]initWithCapacity:4];

    [searchDict setObject:service forKey:(__bridge id)kSecAttrService];                         //标签service

    [searchDict setObject:account forKey:(__bridge id)kSecAttrAccount];                         //标签account

    [searchDict setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];//表明存储的是一个密码

    

    OSStatus status = -1;

    CFTypeRef result =NULL;

    status = SecItemCopyMatching((__bridge CFDictionaryRef)searchDict, &result);

    if (status == errSecItemNotFound) {                                              //没有找到则添加

        NSData *passwordData = [password dataUsingEncoding:NSUTF8StringEncoding];    //password 转换为 NSData

        [searchDict setObject:passwordData forKey:(__bridge id)kSecValueData];       //添加密码      

        status = SecItemAdd((__bridge CFDictionaryRef)searchDict, NULL);             //!!!!!关键的添加API

    }else if (status == errSecSuccess){                                              //成功找到,说明钥匙已经存在则进行更新

        NSData *passwordData = [password dataUsingEncoding:NSUTF8StringEncoding];    //password 转换为 NSData

        NSMutableDictionary *dict = [[NSMutableDictionary allocinitWithDictionary:searchDict];

        [dict setObject:passwordData forKey:(__bridge id)kSecValueData];             //添加密码     

        status = SecItemUpdate((__bridge CFDictionaryRef)searchDict, (__bridge CFDictionaryRef)dict);//!!!!关键的更新API

    }

    return (status == errSecSuccess);

}

其他操作的重要都在操作字典上-_-! 有特殊的东东遇到了再写上!

 

转载于:https://www.cnblogs.com/sundaysgarden/p/10361421.html

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_30783629/article/details/98977092

智能推荐

原生方法实现之C和C++头文件生成器javah,Eclipse中调用_jsa158的博客-程序员宅基地

javah 使用参数用法: javah [options] <classes>其中, [options] 包括: -o <file> 输出文件 (只能使用 -d 或 -o 之一) -d <dir> 输出目录 -v -verbose 启用详细输出 -h --help -?

PAT甲题题解-1115. Counting Nodes in a BST (30)-(构建二分搜索树+dfs)_weixin_30875157的博客-程序员宅基地

题意:给出一个序列,构建二叉搜索树(BST),输出二叉搜索树最后两层的节点个数n1和n2,以及他们的和sum:n1 + n2 = sum递归建树,然后再dfs求出最大层数,接着再dfs计算出最后两层的节点个数,也可以直接一遍dfs,顺便存储各个层的节点数。#include &lt;iostream&gt;#include &lt;cstdio&gt;#incl...

激光中心线提取的一些论文截图_哈哈kls的博客-程序员宅基地

若,则说明一阶导数为零的点位于当前像素内,再加上该方向上二阶导数的极小值小于一定阈值,则通过两层判断,则会比较准确的提取出线条边缘的中心点。...

第一行代码(kotlin版)_第一行代码是kol_门前无树的博客-程序员宅基地

郭霖先生所著的《第一行代码》以Java为基本语言,是许多Android童鞋的入门书籍(包括我)。而由于各种原因,2017年Google I/O 中Google宣布kotlin将成为Android官方语言。kotlin将在不久的将来替代Java在Android开发的功能。本人系列博客《第一行代码(kotlin版)》将会把郭霖先生的书籍的Java代码转述为kotlin代码,帮助大家学习。Java与ko...

pip下载了pytorch后,anaconda解释器里找不到的解决方案(可能完全错误的解决方案……)_pip list 找不到torch_weixin_44190823的博客-程序员宅基地

第一次写文章,就把内容发出来把,其他先不管了,说不定也没人看呢……标题的问题就是我遇到的问题(刚接触python的小白,我不知道我标题的表述是不是正确的……)具体来说,就是我确定已经pip,下载好了torch,因为在cmd里可以查看torch的版本了而且我在pycharm的解释器中,选择python3.8.exe,列表中也显示有了torch,测试过是能用的但问题是这里的库太少了,网上说使用anaconda,会自带很多库,所以我又添加了anaconda的python.exe。换完之后,库确实是多了

随便推点

ecshop 2.6.2 版本的sql注入漏洞_yangjiehuan的博客-程序员宅基地

简要:      这个漏洞不是我发现的。现在目前2.7.3也已经改了,所以放上来,是为了说明变量初始化的重要性。refer link:http://bbs.wolvez.org/viewtopic.php?pid=179#p179内容:影响2.5.x和2.6.x,其他版本未测试goods_script.php44行:    if (empty($_GET['type']

牛客网_PAT乙级_10234有理数四则运算(20)【通过5/7:格式错误】_寒泉Hq的博客-程序员宅基地

题目描述本题要求编写程序,计算2个有理数的和、差、积、商。输入描述:输入在一行中按照“a1/b1 a2/b2”的格式给出两个分数形式的有理数,其中分子和分母全是整型范围内的整数,负号只可能出现在分子前,分母不为0。输出描述:分别在4行中按照“有理数1 运算符 有理数2 = 结果”的格式顺序输出2个有理数的和、差、积、商。注意输出的每个有理数必须是该有理数的最简形式“k a/b”,其中k是...

边界不一致区域检测与修复_T0XIc.的博客-程序员宅基地

Color Image-Guided Boundary-Inconsistent RegionRefinement for Stereo Matching提出的算法边界不一致区域边界不一致区域检测边界不一致区域恢复Refinement for Stereo Matching)本文提出了一种新的方法来改善目标边界附近的虚假视差。在我们的方法中,使用彩色图像来指导整个修复过程。我们将目标边界附近...

aida64注册信息已损坏_AIDA64 Extreme(硬件检测)_小弯指的博客-程序员宅基地

AIDA64Extreme是一款国外优秀的软硬件检测工作,相比常用的cpu-z,Gpu-z,它的功能更加全面。此次给大家带来的版本为已注册的,内含一个注册key,已经设置好中文,无需安装,解压就可以使用了。支援数千种主机板(3400+)和数百种显示卡(360+)。· 支援对 并口 / 串口 / USB 这些 PNP 设备的检测。· 支援对各种处理器的侦测。· 新版增加查看远端系统资讯和管理,结果导...

【数学】加性函数与积性函数-程序员宅基地

一、前置知识艾佛森括号[P]={1if&nbsp;P&nbsp;is&nbsp;true0otherwise[P]=\begin{cases}1 &amp; \text{if}\ P\ \text{is true} \\0 &amp; \text{otherwise}\end{cases}[P]={10​if&nbsp;P&nbsp;is&nbsp;trueotherwise​其中 PPP 是一个可真可假的命题。如 [114514≤1919810]=1,[−1∈N]=0[114514\l

计算机网络实验一_luoawai的博客-程序员宅基地

实验名称        实验一:常用网络命令操作              一、实验目的:1.学会使用Ping、IPConfig、TraceRt、Netstat、ARP等常用网络命令。2.学会配置网络接口IP属性(IP地址、子网掩码、默认网关)。二、实验环境:   一台装有Cisco Packet Tracer的计算机。三、实验内容:1、设置网络接口为自动获取IP地址方式。运行IPConfig命令...