Swift签名和验证中的椭圆曲线导致错误-9809

时间:2019-05-09 13:17:40

标签: ios swift security encryption elliptic-curve

我之所以写这个问题,是因为我对下一个问题陷入僵局。

我试图用私钥对大量数据进行签名,然后使用公钥验证该数据,但是当我执行 SecKeyRawVerify 时,它返回错误代码- 9809 ,Apple将其描述为“ “遇到了潜在的密码错误。” ,这根本没有帮助。

我认为主要问题出在我的验证码中,该验证码无法正常工作。不过也许我弄错了。
如果有帮助,最低的iOS版本目标是 iOS10 。我认为Apple在iOS10上对安全框架进行了各种更改,但我不确定100%。

当心,代码很长(很抱歉)。

生成用于椭圆曲线加密的密钥对的代码如下。

    private func generateKeyPair(tagPrivate: String, tagPublic: String, typeAuthentication: KeystoreServiceConstants.Authentication, keyType: CFString, KeySize: Int, container: KeystoreServiceConstants.Container) throws {

        var privateKeyAttr: [String: Any]
        var publicKeyAttr: [String: Any]
        var generatePairKeyAttr: [String: Any]

        var accessControl: AccessControl

        switch typeAuthentication {
        case KeystoreServiceConstants.Authentication.none:
            do {
                accessControl = try AccessControl(protection: .whenUnlocked, policy: [])
            } catch {
                throw error
            }
        case KeystoreServiceConstants.Authentication.biometricAuthentication:
            do {
                accessControl = try AccessControl(protection: .whenUnlocked, policy: [.touchIDCurrentSet, .privateKeyUsage])
            } catch {
                throw error
            }
        }

        publicKeyAttr = createPublicKeyParams(tagPublic: tagPublic)
        privateKeyAttr = createPrivateKeyParams(tagPrivate: tagPrivate, accessControl: accessControl)
        generatePairKeyAttr = createGeneratePairKeyParams(publicKeyAttr: publicKeyAttr, privateKeyAttr: privateKeyAttr, keyType: keyType, KeySize: KeySize, container: container)

        var publicKey, privateKey: SecKey?

        let status = SecKeyGeneratePair(generatePairKeyAttr as CFDictionary, &publicKey, &privateKey)

        if status != errSecSuccess {
            throw handlingError(status: status)
        }

        do {
            try forceSaveInKeyChain(tagPublic: tagPublic, publicKey: publicKey!, keyType: keyType, keyClass: kSecAttrKeyClassPublic)
        } catch {
            throw error
        }
    }

    private func createPublicKeyParams(tagPublic: String) -> [String: Any] {

        let publicKeyParameters: [String: Any] = [
            kSecAttrIsPermanent as String: false,
            kSecAttrApplicationTag as String: KeystoreServiceConstants.Tag.application,
            kSecAttrLabel as String: tagPublic
        ]
        return publicKeyParameters
    }

    private func createPrivateKeyParams(tagPrivate: String, accessControl: AccessControl) -> [String: Any] {

        let context = LAContext()

        let privateKeyParams: [String: Any] = [
            kSecAttrIsPermanent as String: true,
            kSecAttrApplicationTag as String: KeystoreServiceConstants.Tag.application,
            kSecAttrLabel as String: tagPrivate,
            kSecUseAuthenticationContext as String: context,
            kSecUseAuthenticationUI as String: kSecUseAuthenticationUIAllow,
            kSecAttrAccessControl as String: accessControl.accessControl
        ]
        return privateKeyParams
    }

    private func createGeneratePairKeyParams(publicKeyAttr: [String: Any], privateKeyAttr: [String: Any], keyType: CFString, KeySize: Int, container: KeystoreServiceConstants.Container) -> [String: Any] {
        var params: [String: Any] = [
            kSecAttrKeyType as String: keyType,
            kSecAttrKeySizeInBits as String: KeySize,
            kSecPublicKeyAttrs as String: publicKeyAttr,
            kSecPrivateKeyAttrs as String: privateKeyAttr,
        ]
        if container == .secureEnclave {
            params[kSecAttrTokenID as String] = kSecAttrTokenIDSecureEnclave
        }
        return params
    }

    private func forceSaveInKeyChain(tagPublic: String, publicKey: SecKey, keyType: CFString, keyClass: CFString) throws {


        let query: [String: Any] = [
            kSecClass as String: kSecClassKey,
            kSecAttrKeyType as String: keyType,
            kSecAttrKeyClass as String: keyClass,
            kSecAttrLabel as String: tagPublic,
            kSecAttrApplicationTag as String: KeystoreServiceConstants.Tag.application,
            kSecValueRef as String: publicKey,
            kSecAttrIsPermanent as String: true,
            kSecReturnData as String: true,
            ]

        var raw: CFTypeRef?
        var status = SecItemAdd(query as CFDictionary, &raw)

        if status == errSecDuplicateItem {
            status = SecItemDelete(query as CFDictionary)
            status = SecItemAdd(query as CFDictionary, &raw)
        }

        guard status == errSecSuccess else {
            throw KeystoreServiceConstants.KeyError.saveFailureInKeychain
        }
    }

签名消息的代码是下一个:

   func signWithKey(data: String) throws -> String {
        let oneKeyPrivate = try getKeyTypeInSecureEnclave(tag: "TagKeyPrivate")
        let sign = try signWithPrivateKey(data, oneKeyPrivate)

        let dataSign = sign!.data(using: String.Encoding.utf8)!
        let testKeyPublicData = try getKeyTypeInKeyChain(tag: "TagKeyPublic", keyType: KeystoreServiceConstants.KeyType.EC)
        // The result is always false, because verifyString fails with code -9809
        let result = verifyString(string: data, signature: dataSign, publicKey: testKeyPublicData as! SecKey)

        // My 2nd try, with another method to get the public key
        let keyPrivate = try getKeyTypeInSecureEnclave(tag: "TagKeyPrivate")
        let publicKey = SecKeyCopyPublicKey(keyPrivate)
        let result2 = verifyString(string: data, signature: dataSign, publicKey: publicKey!)

        return sign!

    }



    private func getKeyTypeInKeyChain(tag: String, keyType: CFString) throws -> SecKey {

        let query: [CFString: Any] = [
            kSecClass: kSecClassKey,
            kSecAttrKeyType: keyType,
            kSecAttrApplicationTag: KeystoreServiceConstants.Tag.application,
            kSecAttrLabel: tag,
            kSecReturnRef: true
        ]
        var result: AnyObject?
        let status: OSStatus = SecItemCopyMatching(query as CFDictionary, &result)
        switch status {
        case errSecSuccess:
            return result as! SecKey
        case errSecItemNotFound:
            throw KeystoreServiceConstants.KeyError.keyNotFound
        default:
            throw KeystoreServiceConstants.KeyError.keyNotFound
        }
    }


    private func getKeyTypeInSecureEnclave(tag: String) throws -> SecKey {

        let query: [String: Any] = [
            kSecClass as String: kSecClassKey,
            kSecAttrKeyClass as String: kSecAttrKeyClassPrivate,
            kSecAttrApplicationTag as String: KeystoreServiceConstants.Tag.application,
            kSecAttrLabel as String: tag,
            kSecReturnRef as String: true,
            kSecUseOperationPrompt as String: LocalizerManager.stringForKey(key: "accessControl_message") as CFString,
            kSecUseAuthenticationUI as String: kSecUseAuthenticationUISkip
            ]
        let raw = try getSecKeyWithQuery(query)
        return raw as! SecKey
    }

下一个检查和验证签名消息的代码为

     func verifyString(string: String, signature: Data, publicKey: SecKey) -> Bool {
        var digest = Data(count: Int(CC_SHA256_DIGEST_LENGTH))
        let stringData: Data = string.data(using: String.Encoding.utf8)!

        _ = digest.withUnsafeMutableBytes { (digestBytes) in
            stringData.withUnsafeBytes { (stringBytes) in
                CC_SHA256(stringBytes, CC_LONG(stringData.count), digestBytes)
            }
        }

        let mutdata = NSMutableData(data: signature)

        let err: OSStatus = SecKeyRawVerify(
            publicKey,
            SecPadding.PKCS1SHA256,
            [UInt8](digest),
            digest.count,
            mutdata.mutableBytes.assumingMemoryBound(to: UInt8.self),
            signature.count
        )
        switch err {
        case noErr:
            return true
        default:
            return false
        }
    }

我会很感激您能提供的任何帮助或线索,因为我一直在Google StackOverflow上搜索和搜索了几个小时,而且还无法解决问题。
再说一遍,对不起,代码太长了!

0 个答案:

没有答案