使用私钥和TouchID或FaceID swift签名消息

时间:2019-06-17 10:32:10

标签: ios swift rsa signature touch-id

我已使用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)
}

3 个答案:

答案 0 :(得分:0)

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

  • 确保已在自己的计算机中设置 NSFaceIDUsageDescription info.plist

    没有此键,系统将不允许您的应用使用Face ID。的 此键的值是系统提供给用户的字符串 您的应用首次尝试使用Face ID。该字符串应 明确说明您的应用为何需要访问此身份验证 机制。该系统不需要类似的用法说明 触摸ID。

  • 确保同时添加了安全性和LocalAuthentication 除了启用钥匙串服务之外的框架

  • 您必须在以下位置专门设置身份验证参数 SecAccessControlCreateWithFlags类(请清楚地进行此操作,这会带来很大的不同)

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

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

希望这会有所帮助。

答案 1 :(得分:0)

请勿使用模拟器,请在真实设备上试用。

答案 2 :(得分:0)

您需要将标志设置为

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