重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
//密钥类型键
创新互联建站从2013年成立,先为石河子等服务建站,石河子等地企业,进行企业商务咨询服务。为石河子企业网站制作PC+手机+微官网三网同步一站式服务解决您的所有建站问题。
//CFTypeRef kSecClass
//
//值
//CFTypeRef kSecClassGenericPassword //一般密码
//CFTypeRef kSecClassInternetPassword //网络密码
//CFTypeRef kSecClassCertificate //证书
//CFTypeRef kSecClassKey //密钥
//CFTypeRef kSecClassIdentity //身份证书(带私钥的证书)
//
//不同类型的钥匙串项对应的属性不同
//
//一般密码
//kSecClassGenericPassword
//
//对应属性
//kSecAttrAccessible
//kSecAttrAccessGroup
//kSecAttrCreationDate
//kSecAttrModificationDate
//kSecAttrDescription
//kSecAttrComment
//kSecAttrCreator
//kSecAttrType
//kSecAttrLabel
//kSecAttrIsInvisible
//kSecAttrIsNegative
//kSecAttrAccount
//kSecAttrService
//kSecAttrGeneric
//网络密码
//kSecClassInternetPassword
//
//对应属性
//kSecAttrAccessible
//kSecAttrAccessGroup
//kSecAttrCreationDate
//kSecAttrModificationDate
//kSecAttrDescription
//kSecAttrComment
//kSecAttrCreator
//kSecAttrType
//kSecAttrLabel
//kSecAttrIsInvisible
//kSecAttrIsNegative
//kSecAttrAccount
//kSecAttrSecurityDomain
//kSecAttrServer
//kSecAttrProtocol
//kSecAttrAuthenticationType
//kSecAttrPort
//kSecAttrPath
//证书
//kSecClassCertificate
//
//对应属性
//kSecAttrAccessible
//kSecAttrAccessGroup
//kSecAttrCertificateType
//kSecAttrCertificateEncoding
//kSecAttrLabel
//kSecAttrSubject
//kSecAttrIssuer
//kSecAttrSerialNumber
//kSecAttrSubjectKeyID
//kSecAttrPublicKeyHash
//密钥
//kSecClassKey
//
//对应属性
//kSecAttrAccessible
//kSecAttrAccessGroup
//kSecAttrKeyClass
//kSecAttrLabel
//kSecAttrApplicationLabel
//kSecAttrIsPermanent
//kSecAttrApplicationTag
//kSecAttrKeyType
//kSecAttrKeySizeInBits
//kSecAttrEffectiveKeySize
//kSecAttrCanEncrypt
//kSecAttrCanDecrypt
//kSecAttrCanDerive
//kSecAttrCanSign
//kSecAttrCanVerify
//kSecAttrCanWrap
//kSecAttrCanUnwrap
//身份证书(带私钥的证书)
//kSecClassIdentity
//
//对应属性
// 证书属性
// 私钥属性
//键
//CFTypeRef kSecAttrAccessible; //可访问性 类型透明
//值
// CFTypeRef kSecAttrAccessibleWhenUnlocked; //解锁可访问,备份
// CFTypeRef kSecAttrAccessibleAfterFirstUnlock; //第一次解锁后可访问,备份
// CFTypeRef kSecAttrAccessibleAlways; //一直可访问,备份
// CFTypeRef kSecAttrAccessibleWhenUnlockedThisDeviceOnly; //解锁可访问,不备份
// CFTypeRef kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly;//第一次解锁后可访问,不备份
// CFTypeRef kSecAttrAccessibleAlwaysThisDeviceOnly; //一直可访问,不备份
//CFTypeRef kSecAttrCreationDate; //创建日期 CFDateRef
//CFTypeRef kSecAttrModificationDate; //最后一次修改日期 CFDateRef
//CFTypeRef kSecAttrDescription; //描述 CFStringRef
//CFTypeRef kSecAttrComment; //注释 CFStringRef
//CFTypeRef kSecAttrCreator; //创建者 CFNumberRef(4字符,如'aLXY')
//CFTypeRef kSecAttrType; //类型 CFNumberRef(4字符,如'aTyp')
//CFTypeRef kSecAttrLabel; //标签(给用户看) CFStringRef
//CFTypeRef kSecAttrIsInvisible; //是否隐藏 CFBooleanRef(kCFBooleanTrue,kCFBooleanFalse)
//CFTypeRef kSecAttrIsNegative; //是否具有密码 CFBooleanRef(kCFBooleanTrue,kCFBooleanFalse)此项表示当前的item是否只是一个占位项,或者说是只有key没有value。
//CFTypeRef kSecAttrAccount; //账户名 CFStringRef
//CFTypeRef kSecAttrService; //所具有服务 CFStringRef
//CFTypeRef kSecAttrGeneric; //用户自定义内容 CFDataRef
//CFTypeRef kSecAttrSecurityDomain; //网络安全域 CFStringRef
//CFTypeRef kSecAttrServer; //服务器域名或IP地址 CFStringRef
//键
//CFTypeRef kSecAttrProtocol; //协议类型 CFNumberRef
// 值
// CFTypeRef kSecAttrProtocolFTP; //
// CFTypeRef kSecAttrProtocolFTPAccount; //
// CFTypeRef kSecAttrProtocolHTTP; //
// CFTypeRef kSecAttrProtocolIRC; //
// CFTypeRef kSecAttrProtocolNNTP; //
// CFTypeRef kSecAttrProtocolPOP3; //
// CFTypeRef kSecAttrProtocolSMTP; //
// CFTypeRef kSecAttrProtocolSOCKS; //
// CFTypeRef kSecAttrProtocolIMAP; //
// CFTypeRef kSecAttrProtocolLDAP; //
// CFTypeRef kSecAttrProtocolAppleTalk; //
// CFTypeRef kSecAttrProtocolAFP; //
// CFTypeRef kSecAttrProtocolTelnet; //
// CFTypeRef kSecAttrProtocolSSH; //
// CFTypeRef kSecAttrProtocolFTPS; //
// CFTypeRef kSecAttrProtocolHTTPS; //
// CFTypeRef kSecAttrProtocolHTTPProxy; //
// CFTypeRef kSecAttrProtocolHTTPSProxy; //
// CFTypeRef kSecAttrProtocolFTPProxy; //
// CFTypeRef kSecAttrProtocolSMB; //
// CFTypeRef kSecAttrProtocolRTSP; //
// CFTypeRef kSecAttrProtocolRTSPProxy; //
// CFTypeRef kSecAttrProtocolDAAP; //
// CFTypeRef kSecAttrProtocolEPPC; //
// CFTypeRef kSecAttrProtocolIPP; //
// CFTypeRef kSecAttrProtocolNNTPS; //
// CFTypeRef kSecAttrProtocolLDAPS; //
// CFTypeRef kSecAttrProtocolTelnetS; //
// CFTypeRef kSecAttrProtocolIMAPS; //
// CFTypeRef kSecAttrProtocolIRCS; //
// CFTypeRef kSecAttrProtocolPOP3S; //
//键
//CFTypeRef kSecAttrAuthenticationType; //认证类型 CFNumberRef
// 值
// CFTypeRef kSecAttrAuthenticationTypeNTLM; //
// CFTypeRef kSecAttrAuthenticationTypeMSN; //
// CFTypeRef kSecAttrAuthenticationTypeDPA; //
// CFTypeRef kSecAttrAuthenticationTypeRPA; //
// CFTypeRef kSecAttrAuthenticationTypeHTTPBasic; //
// CFTypeRef kSecAttrAuthenticationTypeHTTPDigest; //
// CFTypeRef kSecAttrAuthenticationTypeHTMLForm; //
// CFTypeRef kSecAttrAuthenticationTypeDefault; //
//CFTypeRef kSecAttrPort; //网络端口 CFNumberRef
//CFTypeRef kSecAttrPath; //访问路径 CFStringRef
//CFTypeRef kSecAttrSubject; //X.500主题名称 CFDataRef
//CFTypeRef kSecAttrIssuer; //X.500发行者名称 CFDataRef
//CFTypeRef kSecAttrSerialNumber; //序列号 CFDataRef
//CFTypeRef kSecAttrSubjectKeyID; //主题ID CFDataRef
//CFTypeRef kSecAttrPublicKeyHash; //公钥Hash值 CFDataRef
//CFTypeRef kSecAttrCertificateType; //证书类型 CFNumberRef
//CFTypeRef kSecAttrCertificateEncoding; //证书编码类型 CFNumberRef
//CFTypeRef kSecAttrKeyClass; //加密密钥类 CFTypeRef
// 值
// CFTypeRef kSecAttrKeyClassPublic; //公钥
// CFTypeRef kSecAttrKeyClassPrivate; //私钥
// CFTypeRef kSecAttrKeyClassSymmetric; //对称密钥
//CFTypeRef kSecAttrApplicationLabel; //标签(给程序使用) CFStringRef(通常是公钥的Hash值)
//CFTypeRef kSecAttrIsPermanent; //是否永久保存加密密钥 CFBooleanRef
//CFTypeRef kSecAttrApplicationTag; //标签(私有标签数据) CFDataRef
//CFTypeRef kSecAttrKeyType; //加密密钥类型(算法) CFNumberRef
// 值
// extern const CFTypeRef kSecAttrKeyTypeRSA;
//CFTypeRef kSecAttrKeySizeInBits; //密钥总位数 CFNumberRef
//CFTypeRef kSecAttrEffectiveKeySize; //密钥有效位数 CFNumberRef
//CFTypeRef kSecAttrCanEncrypt; //密钥是否可用于加密 CFBooleanRef
//CFTypeRef kSecAttrCanDecrypt; //密钥是否可用于加密 CFBooleanRef
//CFTypeRef kSecAttrCanDerive; //密钥是否可用于导出其他密钥 CFBooleanRef
//CFTypeRef kSecAttrCanSign; //密钥是否可用于数字签名 CFBooleanRef
//CFTypeRef kSecAttrCanVerify; //密钥是否可用于验证数字签名 CFBooleanRef
//CFTypeRef kSecAttrCanWrap; //密钥是否可用于打包其他密钥 CFBooleanRef
//CFTypeRef kSecAttrCanUnwrap; //密钥是否可用于解包其他密钥 CFBooleanRef
//CFTypeRef kSecAttrAccessGroup; //访问组 CFStringRef
//CFTypeRef kSecMatchPolicy; //指定策略 SecPolicyRef
//CFTypeRef kSecMatchItemList; //指定搜索范围 CFArrayRef(SecKeychainItemRef, SecKeyRef, SecCertificateRef, SecIdentityRef,CFDataRef)数组内的类型必须唯一。仍然会搜索钥匙串,但是搜索结果需要与该数组取交集作为最终结果。
//CFTypeRef kSecMatchSearchList; //
//CFTypeRef kSecMatchIssuers; //指定发行人数组 CFArrayRef
//CFTypeRef kSecMatchEmailAddressIfPresent; //指定邮件地址 CFStringRef
//CFTypeRef kSecMatchSubjectContains; //指定主题 CFStringRef
//CFTypeRef kSecMatchCaseInsensitive; //指定是否不区分大小写 CFBooleanRef(kCFBooleanFalse或不提供此参数,区分大小写;kCFBooleanTrue,不区分大小写)
//CFTypeRef kSecMatchTrustedOnly; //指定只搜索可信证书 CFBooleanRef(kCFBooleanFalse或不提供此参数,全部证书;kCFBooleanTrue,只搜索可信证书)
//CFTypeRef kSecMatchValidOnDate; //指定有效日期 CFDateRef(kCFNull表示今天)
//CFTypeRef kSecMatchLimit; //指定结果数量 CFNumberRef(kSecMatchLimitOne;kSecMatchLimitAll)
//CFTypeRef kSecMatchLimitOne; //首条结果
//CFTypeRef kSecMatchLimitAll; //全部结果
//CFTypeRef kSecUseItemList; //CFArrayRef(SecKeychainItemRef, SecKeyRef, SecCertificateRef, SecIdentityRef,CFDataRef)数组内的类型必须唯一。用户提供用于查询的列表。当这个列表被提供的时候,不会再搜索钥匙串。
//可以同时指定多种返回值类型
//CFTypeRef kSecReturnData; //返回数据(CFDataRef) CFBooleanRef
//CFTypeRef kSecReturnAttributes; //返回属性字典(CFDictionaryRef) CFBooleanRef
//CFTypeRef kSecReturnRef; //返回实例(SecKeychainItemRef, SecKeyRef, SecCertificateRef, SecIdentityRef, or CFDataRef) CFBooleanRef
//CFTypeRef kSecReturnPersistentRef; //返回持久型实例(CFDataRef) CFBooleanRef
//CFTypeRef kSecValueData;
//CFTypeRef kSecValueRef;
//CFTypeRef kSecValuePersistentRef;
在开发过程中,我们经常会被要求获取每个设备的唯一标示,以便后台做相应的处理。
项目2若要使用项目1的Keychain则项目2要开启Keychain Sharing 且 Keychain Groups要包含项目1。 项目1的Keychain Sharing 没有要求。
使用第三方SSKeychain。
钥匙串这个技术大家每天都在用,它相当于一个容器,里面有已加密的和未加密的用户信息,它是怎么实现安全储存Mac、App、服务器和网站的帐户,开发过程中又该怎么使用这个技术呢。通过一个例子来介绍一下:
用户要登录你的APP,这个时候用户在文本框输入了他的用户信息和密码,那么你该如何存储这个信息?自然我们会有一个类似用户的结构来存储用户信息
这个结构里有一个String类型的用户名称和一个String类型的密码变量, 张三输入了它自己的用户名“zhangsan”和密码“******”来登陆,那么我们就会有一个生成用户的过程
那么接下来你希望存储到Keychain中,Keychain有哪些方法呢?第一步自然是添加
函数有三个参数,但是每个似乎都不认识,所以我们先简单看一下这三个参数要做什么
第一个参数是个字典,那自然是由许多key-value构成,首先它要包含一个这个数据的类型,数据类型使用kSecClass来做key,kSecClass的定义:
可以看到kSecClass是一个CFString类型的全局变量,它其中可用的值由Item Class Keys and Values列出。根据数据类型的不同有不同的值,例如密码、认证,对于密码它的值定义为:
也是一个CFString类型的变量, class对应的值会决定数据是否被加密,当选择这个password的时候数据就会被加密。那么我们字典中的第一个key-value对就有了:
那么这个字典还需要包含什么呢? 账号:也就是这个数据是谁的数据,这个属性由kSecAttrAccount这个Key来定义,同样它也是一个CFString类型的Key,它的值是你自定义的一个CFString类型的值。当然这个属性并不是必须的,于是字典中的第二个key-value对也有了
⚠️注意
字典中除了用户名还需要用户的数据,数据使用kSecValueData这个Key来定义,同样是CFString类型的Key,但是用户的数据可能多种多样,所以它的值类型是CFData。那么就需要把用户的信息加工一下
这样就得到了字典中第三个key-value对:
既然是钥匙串,那就不能随时随地访问,需要访问控制权限,所谓访问控制就是你希望当iPhone解锁的时候,或者是验证了用户的指纹之后才能继续进行的过程。权限由kSecAttrAccessControl这个Key来表示,它所对应的值是一个SecAccessControl的实例,而SecAccessControl又是什么?
它就是一个包含Keychain对象怎么被使用的信息的一个不透明类型,来看看它的实例化
它通过SecAccessControlCreateWithFlags(CFAllocatorRef allocator, CFTypeRef protection, SecAccessControlCreateFlags flags, CFErrorRef _Nullable *error)函数来创建
函数有四个参数:
1.第一个参数是用来初始化SecAccessControlRef对象的. 我们可以传 NULL 或者kCFAllocatorDefault
2.第二个参数是控制设备什么情况下可以访问这个Keychain信息, 它的值可以是添加Keychain函数的第一个参数字典中的一个其它key(kSecAttrAccessible)对应的值,例如可以控制当设备解锁的时候使用的值:kSecAttrAccessibleWhenUnlocked: CFString。其它可使用的还有kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly(只有这台设备且设置了密码)、kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly(只有这个设备第一次解锁后)。
3.第三个参数是一组额外的访问控制:用来控制用户级别的访问权限,如果设备没有密码总是处于unlocked的状态,你可能希望进一步限制KeyChain访问。例如在获取银行账户的认证时候,需要在获取认证信息之前验证是不是授权用户在操作,这使得KeyChain可以根据用户的输入来管理对Keychain的访问,可以选择devicePasscode来限制需要用户需要输入密码或者是选择userPresence来让系统根据当前状态选择一种验证方式或者是多种方式的组合
第四个是失败原因的一个指针,这里暂时传一个nil值
所以我们可以通过SecAccessControlCreateWithFlags来获得一个访问控制的参数
⚠️注意
现在我们可以回到之前创建函数的第一个参数字典的分析了,我们得到了
SecAccessControl的实例,所以字典的第四个key-value对也有了:
现在字典中有了数据的类型、哪个用户的数据、用户要存储的数据、什么条件可以访问这个数据。看起来不缺少什么了。我们的一个字典参数就处理好了:
函数会通过第二个参数来返回新添加的Keychain,具体的类型是根据第一个参数中指定的返回类型决定的(例如可以通过kSecReturnData这个可以指定返回类型为CFData) 当然,通常我们可以忽略这个返回的数据,所以可以传一个nil值
函数还有一个返回值,从声明上看是一个OSStatus类型的值,相应的定义在Security Framework Result Codes中,常见的值有:
我们通常需要将返回值和已知的返回值相比较来判断是否操作成功了,也就是我们通常可以使用如下的语句来处理添加操作
至此,添加操作就完成了。
查询主要使用SecItemCopyMatching(CFDictionaryRef query, CFTypeRef _Nullable *result)函数,函数会返回一个或者多个item,或者是指定的item属性的copy,默认情况下只会返回匹配的第一个结果。
函数的第一个参数就是和添加Keychain函数的参数一样的结构,通常有Keychain的class也就是由kSecClass为Key的一个key-value对。
属性:属性就是Keychain结果需要符合的条件,例如想查找哪个用户的数据,查询参数还可以带控制返回的key,因为添加方法和查询方法都会返回结果的数据和属性到提供的参数指针里,所以可以指定返回的key来控制指针对应的返回数据的格式,也就是通常的密码查询应该包含kSecReturnData为Key的key-value对。
例如可以使用kSecReturnPersistentRef这个Key来获得一个CFData的引用,然后可以把它存储在磁盘或在进程间传递,可以在这之后调用另一个SecItemCopyMatching函数将持久化引用转为常规引用,函数参数里需要将持久化的引用的数组作为kSecMatchItemList的值传入。如果使用kSecReturnData来控制返回data本身,搜索会返回一个代表实际数据的CFData,这个就是典型的密码Keychain的使用方式。同时,Keychain服务会在返回给你之前对数据进行解密
搜索参数:这个参数可以包含一些结果的数量条件,控制string属性是否大小写敏感等。
所以,希望查询上面的用户信息的时候查询字典参数会如下所示
函数的第二个参数是一个CFTypeRef类型的接收函数返回的指针,我们需要先定义一个这样的指针:
同样我们需要判断函数返回值是否成功:
因为查询字典参数里携带了kSecReturnData,所以这个指针指向的数据类型是一个CFData类型的参数,我们需要获取对应的值
这样 str就是我们之前存储在KeyChain中的用户信息了
至此,Keychain的添加和删除都已经具备了,基本的用户需求就解决了。
除了基础的使用之外,我们还可以
这些,下次再说吧
图1 苹果正式发布iOS 7.0.3
iCloud钥匙串功能是可用于在已经授权的苹果设备上记录用户名,用户密码和绑定的信用卡账号等信息,这是一个早已被使用在Mavericks的系统功能,而对于iOS系统来说却是一个新功能。那么iOS 7.0.3系统中的iCloud钥匙串怎么设置?下面我分享一下iCloud钥匙串的使用教程。
iCloud钥匙串怎么用?
我在本文中将以iPad为设备演示如何开启iOS 7.0.3中的iCloud钥匙串功能,在iPhone上开启iCloud钥匙串的方法基本一致。
1.首先在升级到iOS 7.0.3设备上找到“设置”图标,点击进入;
图2 iCloud钥匙串设置使用教程
2.在设置列表中找到“iCloud”的选项,点击打开;
3.若升级iOS 7.0.3设备后没有登录iCloud账户,必须先登录;已经登录成功的可以找到iCloud功能列表中的“钥匙串”功能,点击进入;
图3 在设置中找到iCloud钥匙串
4.这里只有“钥匙串”功能开关选项,开启“钥匙串”功能;
图4 开启iCloud钥匙串
5.这时候,iPad设备提示是否需要将iPad密码用作iCloud安全码,这个安全码是把iCloud钥匙串应用到其他iOS设备上的一个凭证。如果需要,则点击“使用密码”使用锁屏密码作为iCloud钥匙串的'安全码;
图5 创建iCloud钥匙串安全码
6.输入四位密码作为iCloud钥匙串的安全码;
图7 iCloud钥匙串绑定手机号码
8.等待苹果系统激活钥匙串功能即可完成。
iCloud钥匙串有何用?
这里解释一下苹果iOS 7.0.3 iCloud钥匙串有何作用?上文已经讲述到iCloud钥匙串功能是可用于在已经授权的多部苹果设备上记录用户名,用户密码和绑定的信用卡账号等信息,不同设备上想要使用同一个钥匙串,必须经过当前设备(本文中的iPad设备)批准后才能使用。
图8 其他设备需要使用iCloud钥匙串需经初始设备批准
使用同一个iCloud钥匙串功能,在不同的iOS设备上只要登录同一个Apple ID账号并且凭借前文中说到的安全码即可以后任何操作都无需输入密码信息。
图9 凭借iCloud钥匙串安全码恢复所有密码