I am using SecureEnclave on iOS to encrypt/decrypt my confidential key and save it in UserPreferences. It has been setup and encrypting the data successfully. But whenever I try to decrypt the data, it gives me the following error:
Error Domain=NSOSStatusErrorDomain Code=-50 \"ECIES: Failed to aes-gcm decrypt data\" UserInfo={NSDescription=ECIES: Failed to aes-gcm decrypt data}
After a lot of searching, I found some links but they are not of any help. This Github issue talks about the issue. It states,
Additionally, on 10.3 there was a problem with decrypting large amounts of data with kSecKeyAlgorithmECIESEncryptionCofactorX963SHA256AESGCM. I filed a bug report for it, and it got fixed in iOS 11. :)
But I am using iPhone 8 with iOS 12.2 and there is still a problem.
These two SO questions, here and here provide some details but I am not able to decipher it. Plus, I am using Swift 4.
Below is the relevant code which I am using to encrypt/decrypt the data.
To Generate Key Pair
func generateKeyPair(accessControl: SecAccessControl) throws -> (`public`: SecureEnclaveKeyReference, `private`: SecureEnclaveKeyReference) {
let publicKeyParameters: [String: AnyObject] = [
kSecAttrIsPermanent as String: false as AnyObject,
kSecAttrApplicationTag as String: "com.xxx.xxx" as AnyObject,
kSecAttrLabel as String: "PublicKey" as AnyObject
]
let privateKeyParameters: [String: AnyObject] = [
(kSecAttrCanDecrypt as CFString) as String: true as CFBoolean,
kSecAttrIsPermanent as String: true as AnyObject,
kSecAttrAccessControl as String: accessControl,
kSecAttrApplicationTag as String: "com.xxx.xxx" as AnyObject,
kSecAttrLabel as String: "PrivateKey" as AnyObject
]
let parameters: [String: AnyObject] = [
kSecAttrKeyType as String: kSecAttrKeyTypeEC,
kSecAttrKeySizeInBits as String: 256 as AnyObject,
kSecAttrTokenID as String: kSecAttrTokenIDSecureEnclave,
kSecPublicKeyAttrs as String: publicKeyParameters as AnyObject,
kSecPrivateKeyAttrs as String: privateKeyParameters as AnyObject
]
var publicKey, privateKey: SecKey?
let status = SecKeyGeneratePair(parameters as CFDictionary, &publicKey, &privateKey)
print("Result = \(status) - Public Key = \(publicKey) - Private Key = \(privateKey)")
guard status == errSecSuccess else {
throw SecureEnclaveHelperError(message: "Could not generate keypair", osStatus: status)
}
return (public: SecureEnclaveKeyReference(publicKey!), private: SecureEnclaveKeyReference(privateKey!))
}
Encryption
@available(iOS 10.3, *)
func encrypt(_ digest: Data, publicKey: SecureEnclaveKeyReference) throws -> Data {
var error : Unmanaged<CFError>?
let result = SecKeyCreateEncryptedData(publicKey.underlying, SecKeyAlgorithm.eciesEncryptionStandardX963SHA256AESGCM, digest as CFData, &error)
if result == nil {
throw SecureEnclaveHelperError(message: "\(error)", osStatus: 0)
}
return result as! Data
}
Decryption
@available(iOS 10.3, *)
func decrypt(_ digest: Data, privateKey: SecureEnclaveKeyReference) throws -> Data {
var error : Unmanaged<CFError>?
let result = SecKeyCreateDecryptedData(privateKey.underlying, SecKeyAlgorithm.eciesEncryptionStandardX963SHA256AESGCM, digest as CFData, &error)
if result == nil {
throw SecureEnclaveHelperError(message: "\(error)", osStatus: 0)
}
return result as! Data
}
Any help is highly appreciated. Thanks.
I got the same error and found out that I generated two different key pairs where I encrypted my data with one public key but performed decryption using the other wrong private key. So make sure that the decryption operation uses the right private key corresponding to the public key used in encryption.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With