是否可以更新钥匙串项目的 kSecAttrAccessible 值?

Posted

技术标签:

【中文标题】是否可以更新钥匙串项目的 kSecAttrAccessible 值?【英文标题】:Is it possible to update a Keychain item's kSecAttrAccessible value? 【发布时间】:2011-07-19 03:52:02 【问题描述】:

是否可以更新钥匙串中现有项目的属性kSecAttrAccessible 的值?项目添加到钥匙串后似乎无法更改。以下步骤支持我的假设。

向钥匙串添加新项目:

NSData *encodedIdentifier = [@"BUNDLE_IDENTIFIER" 
                             dataUsingEncoding:NSUTF8StringEncoding];
NSData *encodedPassword = [@"PASSWORD"
                           dataUsingEncoding:NSUTF8StringEncoding];

// Construct a Keychain item
NSDictionary *keychainItem = 
    [NSDictionary dictionaryWithObjectsAndKeys:
        kSecClassGenericPassword, kSecClass,
        encodedIdentifier, kSecAttrGeneric,
        encodedIdentifier, kSecAttrService,
        @"USERNAME", kSecAttrAccount,
        kSecAttrAccessibleWhenUnlocked, kSecAttrAccessible,
        encodedPassword, kSecValueData
        nil];

// Add item to Keychain
OSStatus addItemStatus = SecItemAdd((CFDictionaryRef)keychainItem, NULL);

稍后,将属性kSecAttrAccessiblekSecAttrAccessibleWhenUnlocked 更改为kSecAttrAccessibleAfterFirstUnlock

NSData *encodedIdentifier = [@"BUNDLE_IDENTIFIER" 
                             dataUsingEncoding:NSUTF8StringEncoding];

NSDictionary *query = [NSDictionary dictionaryWithObjectsAndKeys:
                       kSecClassGenericPassword, kSecClass,
                       encodedIdentifier, kSecAttrGeneric,
                       encodedIdentifier, kSecAttrService,
                       nil];

NSDictionary *updatedAttributes = 
    [NSDictionary dictionaryWithObject:kSecAttrAccessibleAfterFirstUnlock 
                                forKey:kSecAttrAccessible];

OSStatus updateItemStatus = SecItemUpdate((CFDictionaryRef)query, 
                                          (CFDictionaryRef)updatedAttributes);

这种方法的问题是updateItemStatus 总是导致errSecUnimplemented 状态。

我认为应该可以更新kSecAttrAccessible 的值,因为应用程序的需求发生了变化。如果一个应用程序过去在 Keychain 中添加了 10 个项目而没有使用 kSecAttrAccessible 指定保护等级会怎样。如果开发人员没有明确设置保护等级,钥匙串会隐式地为新项目分配值kSecAttrAccessibleWhenUnlocked。稍后,开发人员需要将保护类更改为kSecAttrAccessibleAfterFirstUnlock,因为应用程序必须在后台访问它(多任务)。开发者如何做到这一点?

苹果开发者论坛里已经有一个帖子了,但是还没有答案:https://devforums.apple.com/thread/87646?tstart=0

【问题讨论】:

【参考方案1】:

我无法得到其他答案。我最终测试了 kSecAttrAccessibile,如果不是我想要的,我将钥匙串中的值和属性记录在局部变量中,重置钥匙串,根据需要设置 kSecAttrAccessible,然后将钥匙串中的值和属性设置为其原始设置。

【讨论】:

你不会碰巧有这个代码sn-p吧?无法使其正常工作【参考方案2】:

在 Apple Developer Technical Support (ADTS) 中打开支持事件后,我收到了回答此问题的回复。 SecItemUpdate() 需要通过属性 kSecValueData 的 Keychain 项的数据来执行属性 kSecAttrAccessible 的更新。根据 ADTS,此约束目前未记录在参考文档中。

NSData *encodedIdentifier = [@"BUNDLE_IDENTIFIER" 
                             dataUsingEncoding:NSUTF8StringEncoding];
NSDictionary *query = [NSDictionary dictionaryWithObjectsAndKeys:
                       kSecClassGenericPassword, kSecClass,
                       encodedIdentifier, kSecAttrGeneric,
                       encodedIdentifier, kSecAttrService,
                       nil];

// Obtain the Keychain item's data via SecItemCopyMatching()
NSData *itemData = ...;

NSDictionary *updatedAttributes = 
    [NSDictionary dictionaryWithObjectsAndKeys:
        kSecAttrAccessibleAfterFirstUnlock, kSecAttrAccessible,
        (CFDataRef)itemData, kSecValueData,
        nil];

OSStatus updateItemStatus = SecItemUpdate((CFDictionaryRef)query, 
                                          (CFDictionaryRef)updatedAttributes);

// updateItemStatus should have the value errSecSuccess

【讨论】:

现在是documented 在ios 4 及更早版本中需要。 如果您使用 RSA 密钥对,请确保对 both 密钥执行此操作。 @PatrickGoley 我需要帮助在设备锁定时读取我的私钥您知道在生成密钥对期间我应该如何设置kSecAttrAccessible 吗?我应该如何设置kSecAttrAccessible 来阅读它?我的问题只针对密钥对。谢谢 这不起作用。有没有人解决这个问题?

以上是关于是否可以更新钥匙串项目的 kSecAttrAccessible 值?的主要内容,如果未能解决你的问题,请参考以下文章

NSInternalInconsistencyException:无法更新钥匙串项

在钥匙串 Swift 中存储整数

钥匙串:项目报告为 errSecItemNotFound,但在添加时收到 errSecDuplicateItem

我们可以访问在共享同一应用组的应用启用钥匙串共享之前保存的钥匙串项目吗?

iOS 钥匙串中的项目能否在应用程序卸载和重新安装后继续存在?

当 iPhone 从备份中恢复时,钥匙串会发生啥?