晋级安全性是重要职分

图片 5

图片 1

上一篇主要讲了keychain的基本使用,这篇主要讲keychain安全方面的一些东西。

本文由腾讯数码独家发布

这个属性,决定了我们item在什么条件下可以获取到里面的内容,我们在添加item的时候,可以添加这个属性,来增强数据的安全性,具体的主要有以下几个:

众所周知,苹果计划在今年对旗下的iCloud云服务进行许多值得关注而且看起来很有趣的改进。那么,今年iCloud会有哪些变化呢?

  • kSecAttrAccessibleWhenUnlocked

  • kSecAttrAccessibleAfterFirstUnlock

  • kSecAttrAccessibleAlways

  • kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly

  • kSecAttrAccessibleWhenUnlockedThisDeviceOnly

  • kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly

  • kSecAttrAccessibleAlwaysThisDeviceOnly

关于苹果iCloud的计划消息已经不少

每个意思都很明确,item默认就是kSecAttrAccessibleWhenUnlocked。也就是在设备未锁屏的情况下。这个也是苹果推荐的。kSecAttrAccessibleAlways,这个苹果在WWDC中也说了,不建议使用,苹果自己已经都弃用了。kSecAttrAccessibleAfterFirstUnlock这个是在设备第一次解锁后,可以使用。这个最常见的就是后台唤醒功能里面,如果需要访问某个item,那么需要使用这个属性,不然是访问不了item的数据的。最后几个DeviceOnly相关的设置,如果设置了,那么在手机备份恢复到其他设备时,是不能被恢复的。同样iCloud也不会同步到其他设备,因为在其他设备上是解密不出来的。

苹果在今年WWDC开发者大会上公布了几项关于iCloud的改进,其中包括一些我们意料之中的事情,比如新的服务和新功能的支持,以及一些不太明显的方面,包括数据同步、计算和人工智能等。

keychain
item可以备份到iCloud上,我们只需要在添加item的时候添加@{(__bridge
id)kSecAttrSynchronizable :
@YES,}。如果想同步到其他设备上也能使用,请避免使用DeviceOnly设置或者其他和设备相关的控制权限。

近期,苹果又开始进行对iCloud通过Touch ID和Face
ID登录进行测试,这意味着如果你使用的是苹果设备(包括Mac、iPad、iPhone),就可以通过手指触摸或快速扫描面部信息的方式直接访问iCloud而无需输入密码。以前使用网页登录icloud,无论是否为苹果设备都需要输入密码。现在用户可以在运行iOS、iPadOS或macOS测试版设备上使用Face
ID或Touch
ID登录网页版iCloud。当这些设备访问Safari浏览器的iCloud时,用户会收到一个弹出窗口,询问是否使用生物识别功能登录。

ACL是iOS8新增的API,iOS9之后对控制权限进行了细化。在原来的基础上加了一层本地验证,主要是配合TouchID一起使用。对于我们使用者来说,在之前的item操作是一样的,只是在添加的时候,加了一个SecAccessControlRef对象。

同时这也可能是苹果在测试今年年底推出Apple ID隐私保护登录的一种方式。

CFErrorRef error = NULL; SecAccessControlRef accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenUnlockedThisDeviceOnly, kSecAccessControlUserPresence, &error); if  { NSLog(@"failed to create accessControl"); return; } NSDictionary *query = @{ (__bridge id)kSecClass : (__bridge id)kSecClassGenericPassword, (__bridge id)kSecValueData : [@"accesscontrol test" dataUsingEncoding:NSUTF8StringEncoding], (__bridge id)kSecAttrAccount : @"account name", (__bridge id)kSecAttrService : @"accesscontrol", (__bridge id)kSecAttrAccessControl : (__bridge id)accessControl, }; OSStatus status = SecItemAdd((__bridge CFDictionaryRef)query, nil);

苹果未来还有什么计划?

我们只需要创建SecAccessControlRef对象,主要是两个参数,一个是kSecAttrAccessible,另一个是SecAccessControlCreateFlags。在字典里面添加(__bridge
id)kSecAttrAccessControl : (__bridge id)accessControl即可。

我们都知道,最近一段时间以来,苹果一直在悄悄的实施iCloud增强计划。苹果在WWDC全球开发者大会上公布了几项重要公告,将iCloud视作新服务的核心环节。

SecAccessControlCreateFlags:

查找服务

  • kSecAccessControlUserPresence

    item通过锁屏密码或者Touch ID进行验证,Touch
    ID可以不设置,增加或者移除手指都能使用item。

  • kSecAccessControlTouchIDAny

    item只能通过Touch ID验证,Touch ID
    必须设置,增加或移除手指都能使用item。

  • kSecAccessControlTouchIDCurrentSet

    item只能通过Touch ID进行验证,增加或者移除手指,item将被删除。

  • kSecAccessControlDevicePasscode

    item通过锁屏密码验证访问。

  • kSecAccessControlOr

    如果设置多个flag,只要有一个满足就可以。

  • kSecAccessControlAnd

    如果设置多个flag,必须所有的都满足才行。

  • kSecAccessControlPrivateKeyUsage

    私钥签名操作

  • kSecAccessControlApplicationPassword

    额外的item密码,可以让用户自己设置一个访问密码,这样只有知道密码才能访问。

苹果的“查找服务”将在今年晚些时候发布,它可以帮助你找到朋友、智能手机和Mac电脑等硬件。除了这三项常规的跟踪内容之外,还有其它目标和硬件都可以被整合到这项服务中,比如背包、自行车甚至是汽车等。

获取操作和以前的都是一样的,只是加了一个提示信息kSecUseOperationPrompt,用来说明调用意图:

图片 2

 NSDictionary *query = @{(__bridge id)kSecClass : (__bridge id)kSecClassGenericPassword, (__bridge id)kSecReturnData : @YES, (__bridge id)kSecAttrService : @"accesscontrol", (__bridge id)kSecUseOperationPrompt : @"获取存储密码", }; CFTypeRef dataTypeRef = NULL; OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &dataTypeRef); if (status == errSecSuccess) { NSString *pwd = [[NSString alloc] initWithData:(__bridge NSData * _Nonnull)(dataTypeRef) encoding:NSUTF8StringEncoding]; NSLog(@"==result:%@", pwd); }

在即将推出的iOS和macOS版本中,新的“Find
My”功能将接收来自苹果设备的蓝牙信号,即使该设备的蓝牙处于关闭状态,也允许附近的苹果设备接收信号并将其位置转发到云端。这应该可以帮助你找到被盗的笔记本电脑,哪怕电脑已经被小偷藏好。事实证明,苹果精心设计的加密方案不仅可以防止闯入者从其蓝牙信号中识别或跟踪iDevice,还可以防止苹果自己获取位置信息。

图片 3

当你首次在苹果设备上设置“Find
My”时(苹果会跟你确认至少需要有两台设备才能使用此功能),它会生成一个不可破解私钥,该私钥通过端到端加密通信在所有这些设备上共享,只有事先确定好设备才能获取该私匙。

Secure Enclave 首次出现在iPhone
5s中,就是协处理器M7,用来保护指纹数据。SE里面的数据我们用户层面代码是访问不了的,哪怕系统越狱了,也无法访问到里面数据。只有特定的代码才能去访问(CPU
切换成Monitor
Mode)。SE本身也集成了加密库,加密解密相关的都在SE内部完成,这样应用程序只能拿到最后的结果,而无法拿到原始的数据。(关于Secure
Enclave
可以搜些资料了解下,这里就不展开了)。在iOS9之后苹果开放了一个新的属性:kSecAttrTokenIDSecureEnclave,也就是将数据保存到SE里面,当然只是key。

每个设备还生成一个公钥。与其他公钥加密设置一样,此公钥可用于加密数据,这样没有相应的私钥就无法解密数据信息,而私匙只有用户之前共享的设备才有。这公钥就是你的设备通过蓝牙向周边设备发出的“指示信号”。

如何使用:

公钥定期会发生变化,变成一个新数字,这些数字和之前的公钥也没什么关联性,但仍然保留了加密数据的功能,同样只有你自己的设备才可以解密它。苹果拒绝透露公钥具体的变化频率,但每这么做一次,就会增加利用蓝牙信号来追踪地理位置的难度。

//生成ECC公私钥CFErrorRef error = NULL; SecAccessControlRef accessControl = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenUnlockedThisDeviceOnly, kSecAccessControlPrivateKeyUsage | kSecAccessControlTouchIDAny, &error); if  { NSLog(@"failed to create accessControl"); return; } NSDictionary *params = @{ (__bridge id)kSecAttrTokenID: (__bridge id)kSecAttrTokenIDSecureEnclave, (__bridge id)kSecAttrKeyType: (__bridge id)kSecAttrKeyTypeEC, (__bridge id)kSecAttrKeySizeInBits: @256, (__bridge id)kSecPrivateKeyAttrs: @{ (__bridge id)kSecAttrAccessControl: (__bridge_transfer id)accessControl, (__bridge id)kSecAttrIsPermanent: @YES, (__bridge id)kSecAttrLabel: @"ECCKey", }, }; SecKeyRef publickKey, privateKey; OSStatus status = SecKeyGeneratePair((__bridge CFDictionaryRef)params, &publickKey, &privateKey); [self handleError:status]; if (status == errSecSuccess) { CFRelease(privateKey); CFRelease(publickKey); }

//签名 NSDictionary *query = @{ (__bridge id)kSecClass: (__bridge id)kSecClassKey, (__bridge id)kSecAttrKeyClass: (__bridge id)kSecAttrKeyClassPrivate, (__bridge id)kSecAttrLabel: @"ECCKey", (__bridge id)kSecReturnRef: @YES, (__bridge id)kSecMatchLimit : (__bridge id)kSecMatchLimitOne, (__bridge id)kSecUseOperationPrompt: @"签名数据" }; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // Retrieve the key from the keychain. No authentication is needed at this point. SecKeyRef privateKey; OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&privateKey); if (status == errSecSuccess) { // Sign the data in the digest/digestLength memory block. uint8_t signature[128]; size_t signatureLength = sizeof(signature); uint8_t digestData[16]; size_t digestLength = sizeof(digestData); status = SecKeyRawSign(privateKey, kSecPaddingPKCS1, digestData, digestLength, signature, &signatureLength); if (status == errSecSuccess) { NSLog(@"sign success"); } CFRelease(privateKey); } else { } });

图片 4

以上代码就是生成了一对公私钥,私钥会保存在SE中,而公钥交给应用程序。签名操作的时候,好像我们取到了私钥,但是实际上我们并不能拿到私钥,只是私钥在SE中的一个引用。加密的操作也是在SE中完成,最后返回给我们签名的数据。苹果在这边举了个简单例子,如何利用Touch
ID进行登录。客户端生成一对公私钥,公钥发给服务器,客户端在通过Touch
ID校验后,加密一段内容,将内容和结果发送给服务器,服务器取出公钥进行验签。如果一致,则通过验证。

假定有人偷了你的MacBook。即使小偷将Macbook的蓝牙关闭并断开互联网连接,你的笔记本电脑也会通过蓝牙定期发出公钥。附近陌生人的iPhone(此设备与事先享有私钥的设备无任何关联)将接收笔记本发出的信号,核对它所在的位置,并使用从笔记本电脑上获取的公钥加密该位置数据。公钥不包含任何识别信息,并且由于它的数字经常变化,陌生人的iPhone也无法将笔记本电脑连接到其先前的位置。然后陌生人的iPhone会将两样东西上传到苹果的服务器:加密的位置信息和笔记本电脑公钥的哈希值,它将被作为标识符。由于苹果自己也没有私钥,故也无法解密该位置。

图片 5

当你想要找到被盗的笔记本电脑时,你就可以借助于你的第二台苹果设备,比如iPad。它拥有与笔记本电脑相同的私钥,也产生了和笔记本电脑相同的一连串公钥。当你点击按钮寻找笔记本电脑时,iPad会上传相同的公钥哈希值到苹果上作为验证标识,以便苹果可以搜索其数百万个存储的加密位置,并找到匹配的哈希值。一个复杂的点在于iPad的公钥哈希值与被偷笔记本电脑的哈希值不同,因为自陌生人用手机获取蓝牙信号以来,公钥可能已经变换很多次了。苹果没有解释这是如何工作的,但Green指出iPad可以上传之前所有公钥的哈希值,这样苹果就可以对它们进行整理,以便找到笔记本之前所在的位置。

上面这个图就是普通item的一个解密流程。应用程序通过API访问item,在keychain里面取出加密的item,将加密的item,传递给SE解密,解密完返回给keychain,最后返回给应用。

苹果将笔记本电脑的加密位置返回到iPad,iPad可以使用其私钥对其进行解密,并告诉你笔记本电脑最后的位置。同时,苹果自己从未见过解密位置,并且由于散列函数被设计为不可逆转,因此它甚至无法使用散列公钥来收集有关设备所在位置的任何信息。

iOS8后,苹果将中间的keychain框架进行了拆分,增加了本地授权认证:

发表评论

电子邮件地址不会被公开。 必填项已用*标注