【问题标题】:Cannot get symmetric key from keychain无法从钥匙串中获取对称密钥
【发布时间】:2020-06-03 09:00:37
【问题描述】:

尝试从钥匙串中创建和检索对称密钥:

添加密钥

let key  = Data(repeating: 0xee, count: 32)
let name = "test"
let attributes = [
    kSecAttrKeyType: kSecAttrKeyTypeAES,
    kSecAttrKeySizeInBits: NSNumber(value: 256)
] as CFDictionary

var error: Unmanaged<CFError>?
let secKey = SecKeyCreateFromData(attributes, key as CFData, &error)

let addquery = [
    kSecClass: kSecClassKey,
    kSecAttrKeyClass: kSecAttrKeyClassSymmetric,
    kSecAttrLabel: name,
    kSecValueRef: secKey!
] as CFDictionary

let status = SecItemAdd(addquery as CFDictionary, nil)

if status != errSecSuccess {
    print(SecCopyErrorMessageString(status, nil)!)
}

钥匙串项已创建

拿到钥匙

let name = "test"
let getquery = [
    kSecClass: kSecClassKey,
    kSecAttrKeyClass: kSecAttrKeyClassSymmetric,
    kSecAttrLabel: name
] as [CFString : Any]

var secKey: CFTypeRef?

let status = SecItemCopyMatching(getquery as CFDictionary, &secKey)

if status == errSecSuccess {
    if let dic = SecKeyCopyAttributes(secKey as! SecKey) as? [CFString: Any] {
        if let key = dic[kSecValueData] {
            print("Ok")
        } else {
            print("Cannot get the key")
        }
    } else {
        print("Error retrieving dictionnary")
    }
} else {
    print(SecCopyErrorMessageString(status, nil)!)
}

如果在同一次运行中添加和检索密钥,它就可以工作。 dic中的元素个数是21。

但如果我只尝试获取存储在钥匙串中的密钥,我会得到字典而不是密钥。 dic中的元素个数为20(缺少kSecValueData)。

获取密钥缺少哪些参数?

谢谢

【问题讨论】:

    标签: swift macos security keychain symmetric


    【解决方案1】:

    为了从 KeyChain 中检索您的密钥,您还应该指定 kSecAttrAccessible 选项:

    let attributes = [
        kSecAttrKeyType: kSecAttrKeyTypeAES,
        kSecAttrKeySizeInBits: NSNumber(value: 256),
        kSecAttrAccessible: kSecAttrAccessibleWhenUnlocked
    ] as CFDictionary
    

    这个可以在Mac解锁时查询和检索。

    然后你就可以使用你已经提供的代码了

    let getquery = [
        kSecClass: kSecClassKey,
        kSecAttrKeyClass: kSecAttrKeyClassSymmetric,
        kSecAttrLabel: name,
        kSecMatchLimit: kSecMatchLimitAll
    ] as [CFString : Any]
    
    var secKeys: CFTypeRef?
    let status = SecItemCopyMatching(getquery as CFDictionary, &secKeys)
    
    if status == errSecSuccess {
        for symmetricKey in (secKeys as! [SecKey]) {
            guard let keyAttributes = SecKeyCopyAttributes(symmetricKey) as? [CFString: Any] else {
                fatalError("No key attributes for symmetric key")
            }
            
            guard let keyData = keyAttributes[kSecValueData] as? Data else {
                fatalError("No key data for symmetric key")
            }
            print("Key data retrieved: \(keyData.base64EncodedString())")
        }
    }
    

    现在,您可能会遇到已添加的旧键,它们仍然不会返回任何数据(因为它们的可访问性标志设置不正确)。使用 Mac 上的 Keychain Access 应用程序删除那些。之后,您应该能够添加 AES 密钥并检索 AES 密钥。

    【讨论】:

    • 我添加了 kSecMatchLimit: kSecMatchLimitOne,但如果我添加 kSecReturnData: kCFBooleanTrue!或 kSecReturnAttributes: kCFBooleanTrue!,我在 SecKeyCopyAttributes 中得到 EXC_BAD_ACCESS。如果我删除它,我会得到一个数组,但没有我描述的密钥。
    • @Stephane 请帮帮我。我确实重试了我的答案,它确实崩溃了。但是,在更彻底地阅读了您的问题之后,我确实想知道“如果我只尝试将密钥存储在钥匙串中”这句话是什么意思。当您使用标签时,您的添加查询每次都会添加一个键,对 KeyChain 没有约束。您的 SecItemCopyMatching 函数返回一个键数组。我已经用新代码更新了我的答案,这将允许检索对称密钥数据。
    • 感谢您的帮助。它不起作用“没有对称密钥的密钥数据”。如果我添加(创建一个新密钥)并在同一功能(相同运行)中检索密钥,它就可以工作。但是,如果我只尝试获取密钥(存储在钥匙串中),它就不起作用。我想存储密钥并稍后检索它,(没有什么特别的)但这不起作用。我不能每次都创建一个密钥!我需要存储它并随意检索它。它检索 dic 的 20 个元素而不是 21 个。
    • 很奇怪。我已经在它可以工作的测试游乐场中对此进行了测试。我不知道您是否也使用游乐场创建它,但是在 macOS 上为 KeyChain 创建密钥时需要一些权利。你可以检查一下
    • 是的,你说得对,在操场上它可以工作。(我刚刚测试过)但是在调试模式下的简单 pgm 中它不起作用。是的,我不知道它是什么的应用程序缺少某些东西。
    猜你喜欢
    • 1970-01-01
    • 2021-02-24
    • 2015-04-29
    • 1970-01-01
    • 1970-01-01
    • 2016-06-01
    • 2010-10-21
    • 1970-01-01
    • 2010-11-22
    相关资源
    最近更新 更多