netshark1000
netshark1000

Reputation: 7403

Saving and Reading SecKey to Keychain

I save a key to keychain and read it back to compare the result. Thing is: Values are now different. Any idea what could be wrong?

Here is how I read and write a SecKey:

var privateKey: SecKey?{
        get{
            let query: [String: Any] = [
                String(kSecClass)             : kSecClassKey,
                String(kSecAttrKeyType)       : kSecAttrKeyTypeEC,
                String(kSecReturnRef)         : true as Any
            ]

            var result : AnyObject?
            let status = SecItemCopyMatching(query as CFDictionary, &result)

            if status == errSecSuccess {
                return result as! SecKey?
            }
            return nil
        }
        set{
            if let value = newValue{
                let attribute = [
                    String(kSecClass)              : kSecClassKey,
                    String(kSecAttrKeyType)        : kSecAttrKeyTypeEC,
                    String(kSecValueRef)           : value,
                    String(kSecReturnPersistentRef): true
                    ] as [String : Any]

                let status = SecItemAdd(attribute as CFDictionary, nil)

                if status != noErr {
                    logger.error("easyLoginPrivateKey Error!")
                    return
                }
            }
            else{
                deleteAllSecKeys()
            }
        }
    }

And here is my test:

 func testPrivateKey(){

        let helper = KeychainHelper()
        let key = LoginModel().createJWK()?.privateKey


        let storedPrivateKey = try! helper.privateKey?.ecPrivateKeyComponents()
        let cachedPrivateKey = try! key?.ecPrivateKeyComponents()
        XCTAssertNotNil(storedPrivateKey)

        XCTAssertEqual(String(data: storedPrivateKey!.x, encoding: .ascii), String(data: cachedPrivateKey!.x, encoding: .ascii))
        XCTAssertEqual(String(data: storedPrivateKey!.y, encoding: .ascii), String(data: cachedPrivateKey!.y, encoding: .ascii))
        XCTAssertEqual(String(data: storedPrivateKey!.d, encoding: .ascii), String(data: cachedPrivateKey!.d, encoding: .ascii))
        XCTAssertEqual(storedPrivateKey!.crv, cachedPrivateKey!.crv)
    }

Values of x, y and d are different. Crv is still the same.

Upvotes: 1

Views: 848

Answers (1)

Rob Napier
Rob Napier

Reputation: 299265

Your query doesn't request the key you put it. It requests "the first key I have access to." You need some kind of identifier to distinguish the key you're inserting, and then use that identifier to search for it.

For keys, the "label" (kSecAttrApplicationLabel) should automatically be set to the hash of the public key. Alternately, you can set and search for the tag (kSecAttrApplicationTag) which is any arbitrary data you'd like to use to identify this key.

Keep in mind that the keys are considered unique based on both their label (hash) and tag, which means that you can have multiple keys in the keychain with the same tag. Your test case should, at a minimum, delete any keys it creates. Your code probably also needs to be resilient to situations where there are multiple keys with the same tag if you use tags rather than labels/hashes to identify keys.

Upvotes: 1

Related Questions