encryptMessageWithPublicKey

encryptMessageWithPublicKey

本文介绍了kSecAttrKeyTypeEC导致cryptoMessageWithPublicKey()失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用ECDSA密钥获取sha384.我正在关注这篇文章但是我当然将RSA更改为EC.

I'm trying to get sha384 with ECDSA keys. I'm following this article but I changed RSA to EC, of course.

密钥已成功生成,但encryptMessageWithPublicKey()不起作用:(

The keys are successfully generated, but encryptMessageWithPublicKey() doesn't work :(

方法encryptMessageWithPublicKey()中的变量状态"返回-50 ...

Variable "status" in method encryptMessageWithPublicKey() returns -50 ...

这是我的代码:

import UIKit
import Security

private let _singletonInstance = AsymmetricCryptoManager()


private let kAsymmetricCryptoManagerApplicationTag = "com.AsymmetricCrypto.keypair"
private let kAsymmetricCryptoManagerKeyType = kSecAttrKeyTypeEC//kSecAttrKeyTypeEC
private let kAsymmetricCryptoManagerKeySize = 384

// private key parameters
let privateKeyParams: [String: AnyObject] = [
    kSecAttrIsPermanent as String: true as AnyObject,
    kSecAttrApplicationTag as String: "com.AsymmetricCrypto.keypair" as AnyObject
]

// private key parameters
let publicKeyParams: [String: AnyObject] = [
    kSecAttrIsPermanent as String: true as AnyObject,
    kSecAttrApplicationTag as String: "com.AsymmetricCrypto.keypair" as AnyObject
]

enum AsymmetricCryptoException: Error {
    case unknownError
    case duplicateFoundWhileTryingToCreateKey
    case keyNotFound
    case authFailed
    case unableToAddPublicKeyToKeyChain
    case wrongInputDataFormat
    case unableToEncrypt
    case unableToDecrypt
    case unableToSignData
    case unableToVerifySignedData
    case unableToPerformHashOfData
    case unableToGenerateAccessControlWithGivenSecurity
    case outOfMemory
}



class AsymmetricCryptoManager: NSObject {

    /** Shared instance */
    class var sharedInstance: AsymmetricCryptoManager {
        return _singletonInstance
    }


    func createSecureKeyPair(_ completion: ((_ success: Bool, _ error: AsymmetricCryptoException?) -> Void)? = nil) {
        // private key parameters
        let privateKeyParams: [String: AnyObject] = [
            kSecAttrIsPermanent as String: true as AnyObject,
            kSecAttrApplicationTag as String: kAsymmetricCryptoManagerApplicationTag as AnyObject
        ]

        // private key parameters
        let publicKeyParams: [String: AnyObject] = [
            kSecAttrIsPermanent as String: true as AnyObject,
            kSecAttrApplicationTag as String: kAsymmetricCryptoManagerApplicationTag as AnyObject
        ]

        // global parameters for our key generation
        let parameters: [String: AnyObject] = [
            kSecAttrKeyType as String:          kAsymmetricCryptoManagerKeyType,
            kSecAttrKeySizeInBits as String:    kAsymmetricCryptoManagerKeySize as AnyObject,
            kSecPublicKeyAttrs as String:       publicKeyParams as AnyObject,
            kSecPrivateKeyAttrs as String:      privateKeyParams as AnyObject,
            ]

        // asynchronously generate the key pair and call the completion block
        DispatchQueue.global(qos: DispatchQoS.QoSClass.default).async { () -> Void in
            var pubKey, privKey: SecKey?
            let status = SecKeyGeneratePair(parameters as CFDictionary, &pubKey, &privKey)

            if status == errSecSuccess {
                DispatchQueue.main.async(execute: { completion?(true, nil) })
            } else {
                var error = AsymmetricCryptoException.unknownError
                switch (status) {
                case errSecDuplicateItem: error = .duplicateFoundWhileTryingToCreateKey
                case errSecItemNotFound: error = .keyNotFound
                case errSecAuthFailed: error = .authFailed
                default: break
                }
                DispatchQueue.main.async(execute: { completion?(false, error) })
            }
        }
    }



    private func getPublicKeyReference() -> SecKey? {
        let parameters = [
            kSecClass as String: kSecClassKey,
            kSecAttrKeyType as String: kSecAttrKeyTypeEC,
            kSecAttrApplicationTag as String: kAsymmetricCryptoManagerApplicationTag,
            kSecAttrKeyClass as String: kSecAttrKeyClassPublic,
            kSecReturnRef as String: true,
            ] as [String : Any]
        var ref: AnyObject?
        let status = SecItemCopyMatching(parameters as CFDictionary, &ref)
        if status == errSecSuccess { return ref as! SecKey? }
        else { return nil }
    }


    func encryptMessageWithPublicKey(_ message: String, completion: @escaping (_ success: Bool, _ data: Data?, _ error: AsymmetricCryptoException?) -> Void) {
        DispatchQueue.global(qos: DispatchQoS.QoSClass.default).async { () -> Void in

            if let publicKeyRef = self.getPublicKeyReference() {
                // prepare input input plain text
                guard let messageData = message.data(using: String.Encoding.utf8) else {
                    completion(false, nil, .wrongInputDataFormat)
                    return
                }


                let plainText = (messageData as NSData).bytes.bindMemory(to: UInt8.self, capacity: messageData.count)
                let plainTextLen = messageData.count

                // prepare output data buffer
                var cipherData = Data(count: SecKeyGetBlockSize(publicKeyRef))
                let cipherText = cipherData.withUnsafeMutableBytes({ (bytes: UnsafeMutablePointer<UInt8>) -> UnsafeMutablePointer<UInt8> in
                    return bytes
                })


                var cipherTextLen = cipherData.count

                let status = SecKeyEncrypt(publicKeyRef, .PKCS1SHA384, plainText, plainTextLen, cipherText, &cipherTextLen)

                // analyze results and call the completion in main thread
                DispatchQueue.main.async(execute: { () -> Void in
                    completion(status == errSecSuccess, cipherData, status == errSecSuccess ? nil : .unableToEncrypt)
                    cipherText.deinitialize()
                })
                return
            } else {


                DispatchQueue.main.async(execute: { completion(false, nil, .keyNotFound) }) }
        }
    }


    func decryptMessageWithPrivateKey(_ encryptedData: Data, completion: @escaping (_ success: Bool, _ result: String?, _ error: AsymmetricCryptoException?) -> Void) {
        DispatchQueue.global(qos: DispatchQoS.QoSClass.default).async { () -> Void in

            if let privateKeyRef = self.getPublicKeyReference() {
                // prepare input input plain text
                let encryptedText = (encryptedData as NSData).bytes.bindMemory(to: UInt8.self, capacity: encryptedData.count)
                let encryptedTextLen = encryptedData.count

                // prepare output data buffer
                var plainData = Data(count: 1024)
                let plainText = plainData.withUnsafeMutableBytes({ (bytes: UnsafeMutablePointer<UInt8>) -> UnsafeMutablePointer<UInt8> in
                    return bytes
                })
                var plainTextLen = plainData.count

                let status = SecKeyDecrypt(privateKeyRef, .PKCS1SHA384, encryptedText, encryptedTextLen, plainText, &plainTextLen)

                // analyze results and call the completion in main thread
                DispatchQueue.main.async(execute: { () -> Void in
                    if status == errSecSuccess {
                        // adjust NSData length
                        plainData.count = plainTextLen
                        // Generate and return result string
                        if let string = NSString(data: plainData as Data, encoding: String.Encoding.utf8.rawValue) as String? {
                            completion(true, string, nil)
                        } else { completion(false, nil, .unableToDecrypt) }
                    } else { completion(false, nil, .unableToDecrypt) }
                    plainText.deinitialize()
                })
                return
            } else { DispatchQueue.main.async(execute: { completion(false, nil, .keyNotFound) }) }
        }
    }


}



class ViewController: UIViewController {

    override func viewDidLoad() {
        AsymmetricCryptoManager.sharedInstance.createSecureKeyPair({ success, err in

            if success {

                AsymmetricCryptoManager.sharedInstance.encryptMessageWithPublicKey("thisShouldWork", completion: { (success, data, error) in
                    print(success)
                })

            }

            })

    }

}

推荐答案

errorStatus等于-50表示您的密钥太大.作为参考,寻找"errSecKeySizeNotAllowed". 此处.

errorStatus of -50 means your key size is too large. For a reference, look for "errSecKeySizeNotAllowed" here.

根据 Apple的文档kSecAttrKeyTypeECSECPrimeRandomkSecAttrKeyTypeEC(现已弃用) )仅在安全保护区,因此您需要进行以下更改才能使其正常工作:

According to Apple's Documentation, kSecAttrKeyTypeECSECPrimeRandom and kSecAttrKeyTypeEC (now deprecated) only support a key size of 256, inside and outside of the Secure Enclave, so you need to make the following change for it to work:

kAsymmetricCryptoManagerKeySize = 256

RSA允许使用更大的密钥大小,这就是为什么您不会收到错误的原因.据说256位EC密钥与3072位RSA密钥一样安全.

Larger key sizes are allowed for RSA, which is why you are not getting an error. A 256 bit EC key is said to be as secure as a 3072 bit RSA key.

这篇关于kSecAttrKeyTypeEC导致cryptoMessageWithPublicKey()失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!