【问题标题】:Signture the message with private key and TouchID or FaceID swift使用私钥和 TouchID 或 FaceID 快速签名消息
【发布时间】:2019-06-17 10:32:10
【问题描述】:

我用SecKeyCreateRandomKey 在钥匙串中创建了一个私钥。当我尝试访问密钥以执行签名操作时,Touch ID 或 FaceID 对话框将永远不会出现。我得到了符号字符串,但没有 TouchID 或 FaceID。我尝试使用BiometryAnyTouchIdAny,但它不起作用。

static func createKey(keyName:String){
    DispatchQueue.main.async{
    var error : Unmanaged<CFError>?
    print("Key is generating for \(keyName)")
    let tag = (keyName + "PrivateKey").data(using: .utf8)!
    // private key parameters
    var privateKeyParams: [String: Any] = [:]
    let accessControlError:UnsafeMutablePointer<Unmanaged<CFError>?>? = nil
    // ^ Already a 'pointer'
    if #available(iOS 10 , *) {
        let allocator:CFAllocator!         = kCFAllocatorDefault
        let protection:AnyObject!             = kSecAttrAccessibleWhenUnlockedThisDeviceOnly

        let flags:SecAccessControlCreateFlags = SecAccessControlCreateFlags.userPresence
        let accessControlRef = SecAccessControlCreateWithFlags(
            allocator,
            protection,
            flags,
            accessControlError // <- Notice the lack of '&'
        )
        privateKeyParams = [
            kSecAttrIsPermanent as String: true,
            kSecAttrApplicationTag as String: tag,
            kSecAttrAccessControl as String : accessControlRef!,
        ]
    } else {

        // Fallback on earlier versions
    }


    // global parameters for our key generation
    let parameters: [String: Any] = [
        kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
        kSecAttrKeySizeInBits as String: 2048,

        kSecPrivateKeyAttrs as String: privateKeyParams
    ]
     if #available(iOS 10.0, *) {
        do{
            guard let privateKey = SecKeyCreateRandomKey(parameters as CFDictionary, nil) else {
                print("\(keyName)PrivateKey generator Error!")
                throw error!.takeRetainedValue() as Error
            }
          }
       }
    }

和签名功能:

static func SigntureWithPrivateKey(keyName: String, message : String) -> String {
    //print("sign started .........")
    guard let messageData = message.data(using: String.Encoding.utf8) else {
            print("bad message to sign")
            return ""
    }
    if #available(iOS 10.0, *) {
        guard let privateKeyLocal: SecKey = getPrivateKey("\(keyName)PrivateKey") else
        {
            return ""
        }
        guard let signData = SecKeyCreateSignature(privateKeyLocal,SecKeyAlgorithm.rsaSignatureDigestPKCS1v15SHA512,messageData as CFData, nil) else {
            print("priv ECC error signing")
            return ""
        }
        let convertedSignData = signData as Data
        let convertedString = convertedSignData.base64EncodedString()
        return convertedString

    } else {
        return ""
    }


}

和getPrivateKey函数:

fileprivate static func getPrivateKey(_ name: String) -> SecKey?
{
    let query: [String: Any] = [
        kSecClass as String: kSecClassKey,
        kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
        kSecAttrApplicationTag as String: name,
        kSecReturnRef as String: true
    ]

    var item: CFTypeRef? = nil
    let status = SecItemCopyMatching(query as CFDictionary, &item)

    guard status == errSecSuccess else
    {
        if status == errSecUserCanceled
        {
            print("\tError: Accessing private key failed: The user cancelled (%@).", "\(status)")
        }
        else if status == errSecDuplicateItem
        {
            print("\tError: The specified item already exists in the keychain (%@).", "\(status)")
        }
        else if status == errSecItemNotFound
        {
            print("\tError: The specified item could not be found in the keychain (%@).", "\(status)")
        }
        else if status == errSecInvalidItemRef
        {
            print("\tError: The specified item is no longer valid. It may have been deleted from the keychain (%@).", "\(status)")
        }
        else
        {
            print("\tError: Accessing private key failed (%@).", "\(status)")
        }
        return nil
    }

    return (item as! SecKey)
}

【问题讨论】:

    标签: ios swift rsa signature touch-id


    【解决方案1】:

    对不起,您的问题很长,所以我想我会给出一般性的答案。

    • 确保您已在您的 info.plist

      如果没有此密钥,系统将不允许您的应用使用 Face ID。这 此键的值是系统呈现给用户的字符串 您的应用第一次尝试使用面容 ID。字符串应该 清楚地解释为什么您的应用需要访问此身份验证 机制。该系统不需要类似的使用说明 用于触控 ID。

    • 确保您已添加 Security 和 LocalAuthentication 除了开启钥匙串服务之外的框架

    • 您必须在 SecAccessControlCreateWithFlags 类(请看清楚这有很大的不同)

    请在此处找到更多信息以及示例源代码

    https://developer.apple.com/documentation/localauthentication/accessing_keychain_items_with_face_id_or_touch_id

    希望这会有所帮助。

    【讨论】:

    • 我的 info.plist 中有 NSFaceIDUsageDescription,我必须在 SecAccessControlCreateWithFlags 中设置身份验证参数,但不起作用
    【解决方案2】:

    不要用模拟器,在真机上试试。

    【讨论】:

    • 我用的是真机
    【解决方案3】:

    你需要设置标志为

    let flags:SecAccessControlCreateFlags = 
     [SecAccessControlCreateFlags.privateKeyUsage, SecAccessControlCreateFlags.touchIDCurrentSet]
    

    【讨论】:

      猜你喜欢
      • 2015-06-01
      • 1970-01-01
      • 1970-01-01
      • 2022-08-06
      • 2018-12-16
      • 2018-02-22
      • 2020-11-29
      • 2016-12-20
      • 1970-01-01
      相关资源
      最近更新 更多