Posts

Post marked as solved
11 Replies
2.1k Views
My end goal is to use eciesEncryptionCofactorX963SHA256AESGCM with a key generated on the Secure Enclave using CryptoKit, that requires Biometric Authentication. CryptoKit does not implement the ECIES encryption algorithms, so my goal was to fall back to the Security framework. The public key can be easily converted to a SecKey because it implements x963Representation which can then be imported as follows: let enclaveSecKey: SecKey = SecKeyCreateWithData(enclaveKey.x963Representation as CFData, [ kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom, kSecAttrKeyClass: kSecAttrKeyClassPublic, kSecAttrKeySizeInBits: 256 ] as [String: Any] as CFDictionary, nil), I have everything working except the code to decrypt with the private key. Naturally, the Secure Enclave does not expose the private key - as is its design - rather some kind of token? I did read the Keychain documentation which notes that it is not possible to simply obtain an x963Representation of the private key (as it's a custom representation returned by the Secure Enclave). However, my ultimate question is this: can one convert the Secure Enclave representation into something that can be used as a SecKey for encryption/decryption (without necessarily being stored in the Keychain - i.e., 'correct') as it seems both CryptoKit and Security have a means of representing the private key token returned by the Secure Enclave? (Or is one's only recourse to use the Security framework for generating and storing the keys too?) I have also tried this code to create a SecKey representation, having retrieved the GenericPasswordConvertible out of the keychain (note the use of kSecAttrTokenID: kSecAttrTokenIDSecureEnclave) with the aforementioned goal of loading the Secure Enclave's private token as a SecKey: let enclaveSecKey: SecKey = SecKeyCreateWithData(enclaveKey.rawRepresentation as CFData, [ kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom, kSecAttrKeyClass: kSecAttrKeyClassPrivate, kSecAttrTokenID: kSecAttrTokenIDSecureEnclave, kSecAttrAccessible: kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, kSecUseAuthenticationContext: try await createAuthContext( reason: "Decrypt data", fallbackTitle: "Enter your device password to decrypt data", mustEvaluate: true ), kSecAttrIsPermanent: true, kSecAttrIsExtractable: false, kSecAttrSynchronizable: false, kSecAttrKeySizeInBits: 256, kSecAttrAccessControl: SecAccessControlCreateWithFlags( nil, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, [.biometryAny, .privateKeyUsage], &cfSecKeyCreateError )! ] as [String: Any] as CFDictionary, nil) This works, in and of itself, (i.e., it loads without error and cfSecKeyCreateError is nil, however when I try SecSecKeyCopyPublicKey I get a different, incorrect public key and - naturally, I suppose - if I attempt to decrypt data with the private key that fails with: Optional(Swift.Unmanaged<__C.CFErrorRef>(_value: Error Domain=NSOSStatusErrorDomain Code=-50 "ECIES: Failed to aes-gcm decrypt data (err -69)" UserInfo={numberOfErrorsDeep=0, NSDescription=ECIES: Failed to aes-gcm decrypt data (err -69)}))
Posted
by samjakob.
Last updated
.