kSecAttrKeyTypeEC swift

我试着用ECDSA键获得sha384。 我跟进这篇文章: https : //digitalleaves.com/blog/2015/10/asymmetric-cryptography-in-swift/?replytocom = 52690 #respond

但我当然将RSA改为EC。

和密钥生成,但encryptMessageWithPublicKey不起作用:(

方法中的变量“status”:encryptMessageWithPublicKey返回-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) -> UnsafeMutablePointer 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) -> UnsafeMutablePointer 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) }) } }) } } 

1)请先阅读https://www.apple.com/business/docs/iOS_Security_Guide.pdf 2)使用生成的ECDSA密钥进行签名

 import Foundation import Security private let kAsymmetricCryptoManagerApplicationTag = "com.AsymmetricCrypto.keypair" private let kAsymmetricCryptoManagerKeyType = kSecAttrKeyTypeEC private let kAsymmetricCryptoManagerKeySize = 384 // private key parameters let privateKeyParams: [String: AnyObject] = [ kSecAttrIsPermanent as String: false as AnyObject, kSecAttrApplicationTag as String: "com.AsymmetricCrypto.keypair" as AnyObject ] // private key parameters let publicKeyParams: [String: AnyObject] = [ kSecAttrIsPermanent as String: false as AnyObject, kSecAttrApplicationTag as String: "com.AsymmetricCrypto.keypair" as AnyObject ] // parameters 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, ] var pubKey, privKey: SecKey? let status = SecKeyGeneratePair(parameters as CFDictionary, &pubKey, &privKey) if let privKey = privKey, let pubKey = pubKey { let message = "qwerty" let messageData = message .utf8CString .map{ UInt8(bitPattern: $0) } var sign = [UInt8](repeating: 0, count: 256) var length = sign.count let status = SecKeyRawSign(privKey, .PKCS1SHA384, messageData, messageData.count, &sign, &length) print("message: \"\(message)\" was sign with status:", status == errSecSuccess ? "OK": "KO") let verified = SecKeyRawVerify(pubKey, .PKCS1SHA384, messageData, messageData.count, sign, length) print("message: \"\(message)\" was", verified == errSecSuccess ? "unmodified\t" : "modified \t", messageData) // modified messageData var modified = messageData modified[0] = messageData[0] + 1 let modifiedMessage = String(cString: modified) let verified2 = SecKeyRawVerify(pubKey, .PKCS1SHA384, modified, modified.count, sign, length) print("message: \"\(modifiedMessage)\" was", verified2 == errSecSuccess ? "unmodified" : "modified \t", modified) } 

它打印

 message: "qwerty" was sign with status: OK message: "qwerty" was unmodified [113, 119, 101, 114, 116, 121, 0] message: "rwerty" was modified [114, 119, 101, 114, 116, 121, 0] 

在实际应用中

  • a)使用一些对称密钥(AES,…)加密消息
  • b)密钥使用RSA加密(SecKeyEncrypt)
  • c)加密消息+ encryptedKey用ECDSA签名
  • d)一切都交付给接收者
  • e)接收机检查签名
  • f)解密encryptedKey(SecKeyDecrypt)
  • g)解密消息(AES,……)

要检查支持的内容,请使用

 SecKeyIsAlgorithmSupported(pubKey, .verify, .ecdsaSignatureRFC4754) == true 

另一种签署和validation数据的方法

 if let cdata = CFDataCreate(kCFAllocatorDefault, messageData, messageData.count), // create signature let csign = SecKeyCreateSignature(privKey, .ecdsaSignatureRFC4754, cdata, nil) { // transfer messageData, csign // verify signature let verified = SecKeyVerifySignature(pubKey, .ecdsaSignatureRFC4754, cdata, csign, nil) print(cdata, csign, verified) } 

对于加密/解密,请使用ECIES或RSA

 SecKeyIsAlgorithmSupported(pubKey, .encrypt, .eciesEncryptionCofactorX963SHA384AESGCM) SecKeyIsAlgorithmSupported(privKey, .decrypt, .eciesEncryptionCofactorX963SHA384AESGCM) 

使用密钥对返回true。 使用密钥对加密/解密

 if let cdata = CFDataCreate(kCFAllocatorDefault, messageData, messageData.count) { print("data", cdata) if let coded = SecKeyCreateEncryptedData(pubKey, .eciesEncryptionCofactorX963SHA384AESGCM, cdata, nil) { print("\ncoded",coded) if let decoded = SecKeyCreateDecryptedData(privKey, .eciesEncryptionCofactorX963SHA384AESGCM, coded, nil) { print("\ndecoded", decoded) } } } 

版画

 data <71776572 747900> coded <04ebbf3a 4bb5b767 3251f4dc d131f7be 11516a92 4c8b4f66 23d08751 5ab45cc2 a97e908d 0e689e02 81b74ba0 f9181b24 5a90dea0 052ef3ef 4be6027d 1b67ab71 cf123561 4dfdac16 837f3b6c 195f5122 985bbedb 9dd2e52e e1828f08 4ce6ecb8 6b089205 c820bf0f f8dc6620 24fa53ed 75431006 a6f14c9d> decoded <71776572 747900> 

欲了解更多信息,请阅读https://www.ietf.org/rfc/rfc5289.txt

确保在“常规”>“链接的框架和库”下的项目中添加了“Security.framework”。

所以答案很简单..

Apple的实现仅支持ECDSA,可用于签名但不能加密。

errorStatus -50表示您的密钥大小太大。 有关参考,请在此处查找“errSecKeySizeNotAllowed”: https ://www.osstatus.com/search/results?platform = all & framework = all & search = 50

苹果kSecAttrKeyTypeECSECPrimeRandom和kSecAttrKeyTypeEC仅支持安全区内外的密钥大小256, https://developer.apple.com/library/content/documentation/Security/Conceptual/CertKeyTrustProgGuide/SecureKeyGen.html ,因此您需要进行以下更改:

kAsymmetricCryptoManagerKeySize = 256

RSA允许更大的密钥大小,这就是您没有收到错误的原因。 据说256位EC密钥与3072位RSA密钥一样安全。