安全Enclave,ECIES:无法aes-gcm解密数据(错误-69)

问题描述 投票:0回答:1

使用iOS Secure Enclave时遇到解密失败,导致部分用户在生产环境中解密失败,影响大部分手机和系统功能。

错误信息是:

解密:解密数据失败:可选(错误域=NSOSStatusErrorDomain代码=-50“ECIES:无法aes-gcm解密数据(err -69)”UserInfo = {numberOfErrorsDeep = 0,NSDescription = ECIES:无法aes-gcm解密数据(错误-69)}),数据长度:113

我的代码:

static func getPrivateKey(keyName: String) -> (key: SecKey?, errorMsg: String?) {
    var key: SecKey?
    key = loadKey(name: keyName)
    if let key = key { return (key, nil) }
    let keyInfo = makeAndStoreKey(keyName: keyName)
    if let key = keyInfo.key { return (key, nil) }
    return (nil, keyInfo.errorMsg)
}

static func makeAndStoreKey(keyName: String, requiresBiometry: Bool = false) -> (key: SecKey?, errorMsg: String?) {
    removeKey(name: keyName)
    let flags: SecAccessControlCreateFlags
    if #available(iOS 11.3, *) {
        flags = requiresBiometry ?
        [.privateKeyUsage, .biometryCurrentSet] : .privateKeyUsage
    } else {
        flags = requiresBiometry ?
        [.privateKeyUsage, .touchIDCurrentSet] : .privateKeyUsage
    }
    let access = SecAccessControlCreateWithFlags(kCFAllocatorDefault,
                                                    kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly,
                                                    flags,
                                                    nil)
    guard let tag = keyName.data(using: .utf8), let access = access else {
        return (nil, Crypto.Err.accessOrTagFail.errorDescription)
    }
    let attributes: [CFString: Any] = [
        kSecAttrKeyType: kSecAttrKeyTypeEC,
        kSecAttrKeySizeInBits: 256,
        kSecAttrTokenID: kSecAttrTokenIDSecureEnclave,
        kSecPrivateKeyAttrs: [
            kSecAttrIsPermanent: true,
            kSecAttrApplicationTag: tag,
            kSecAttrAccessControl: access
        ]
    ]
    var error: Unmanaged<CFError>?
    guard let privateKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error) else {
        return (nil, "SecKeyCreateRandomKeyFail: \((error?.takeRetainedValue() as? Error)?.localizedDescription ?? "")")
    }
    return (privateKey, nil)
}

static func loadKey(name: String) -> SecKey? {
    guard let tag = name.data(using: .utf8) else { return nil }
    let query: [CFString: Any] = [
        kSecClass: kSecClassKey,
        kSecAttrApplicationTag: tag,
        kSecAttrKeyType: kSecAttrKeyTypeEC,
        kSecReturnRef: true
    ]
    var item: CFTypeRef?
    let status = SecItemCopyMatching(query as CFDictionary, &item)
    guard status == errSecSuccess, let item = item else { return nil }
    return item as! SecKey
}

static func removeKey(name: String) {
    guard let tag = name.data(using: .utf8) else { return }
    let query: [CFString: Any] = [
        kSecClass: kSecClassKey,
        kSecAttrApplicationTag: tag
    ]
    SecItemDelete(query as CFDictionary)
}

static func encrypt(data: Data, keyName: String) -> Data? {
    var tmpData: Data?
    var errMsg: String?
    defer {
        if tmpData == nil {
            self.updateDeviceDecryptFail()
            self.errorCallBack?(.masterKey(state: .deviceEncryptErr(errMsg: errMsg)))
        }
    }
    guard #available(iOS 11.0, *) else { return nil }
    let keyInfo = getPrivateKey(keyName: keyName)
    guard let key = keyInfo.key else {
        errMsg = "encrypt: \(Crypto.Err.getPrivateKeyFail.errorDescription ?? "") \(keyInfo.errorMsg ?? "")"
        return nil
    }
    guard let publicKey = SecKeyCopyPublicKey(key) else {
        errMsg = "encrypt: \(Crypto.Err.getPublicKeyFail.errorDescription ?? "")"
        return nil
    }
    let algorithm: SecKeyAlgorithm = .eciesEncryptionCofactorVariableIVX963SHA256AESGCM
    guard SecKeyIsAlgorithmSupported(publicKey, .encrypt, algorithm) else {
        errMsg = "encrypt: \(Crypto.Err.isAlgorithmSupportedFail.errorDescription ?? "")"
        return nil
    }
    var error: Unmanaged<CFError>?
    let cipherData = SecKeyCreateEncryptedData(publicKey,
                                                algorithm,
                                                data as CFData,
                                                &error) as Data?
    guard let cipherData = cipherData else {
        errMsg = "encrypt: \(Crypto.Err.encryptedDataFail(error: (error?.takeRetainedValue() as? Error)).errorDescription ?? "")"
        return nil
    }
    tmpData = cipherData
    return cipherData
}

static func decrypt(encryptedData: Data, keyName: String) -> Data? {
    var tmpData: Data?
    var errMsg: String?
    defer { if tmpData == nil { self.errorCallBack?(.masterKey(state: .deviceDecryptErr(errMsg: errMsg))) } }
    guard #available(iOS 11.0, *) else { return nil }
    let keyInfo = getPrivateKey(keyName: keyName)
    guard let key = keyInfo.key else {
        errMsg = "decrypt: \(Crypto.Err.getPrivateKeyFail.errorDescription ?? "") \(keyInfo.errorMsg ?? "")"
        return nil
    }
    let algorithm: SecKeyAlgorithm = .eciesEncryptionCofactorVariableIVX963SHA256AESGCM
    guard SecKeyIsAlgorithmSupported(key, .decrypt, algorithm) else {
        errMsg = "decrypt: \(Crypto.Err.isAlgorithmSupportedFail.errorDescription ?? "")"
        return nil
    }
    var error: Unmanaged<CFError>?
    let data = SecKeyCreateDecryptedData(key,
                                            algorithm,
                                            encryptedData as CFData,
                                            &error) as Data?
    guard let data = data else {
        errMsg = "decrypt: \(Crypto.Err.decryptedDataFail(error: (error?.takeRetainedValue() as? Error)).errorDescription ?? ""), DataLength: \(encryptedData.count)"
        return nil
    }
    tmpData = data
    return data
}

我在网上找了很久,但没有用。请帮忙或尝试给出一些如何实现这一目标的想法。

ios swift security encryption aes-gcm
1个回答
-1
投票

我只在一台设备上突然遇到同样的问题。我们有解决方案吗?

© www.soinside.com 2019 - 2024. All rights reserved.