Compiling for iOS 11 (which allegedly solves all the secure enclave related bugs), I'm trying to create a key pair stored in the secure enclave to use for encrypting/decrypting data, but somewhere along the line the key gets corrupted:
CFErrorRef error = NULL;
NSError *gen_error = nil;
SecAccessControlRef sacObject = SecAccessControlCreateWithFlags(kCFAllocatorDefault, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, kSecAccessControlBiometryAny, &error);
if (sacObject == NULL || error != NULL) { /* handled */ }
NSDictionary *keyAttributes = @{
(id)kSecClass: (id)kSecClassKey,
(id)kSecAttrKeyType: (id)kSecAttrKeyTypeEC,
(id)kSecAttrKeySizeInBits: @256,
(id)kSecAttrTokenID: (id)kSecAttrTokenIDSecureEnclave,
(id)kSecAttrIsPermanent: @YES,
(id)kSecAttrApplicationTag: biometricKeyTag, //static between all calls
(id)kSecAttrAccessControl: (__bridge_transfer id)sacObject,
};
SecKeyRef privateKey = (__bridge SecKeyRef) CFBridgingRelease(SecKeyCreateRandomKey((__bridge CFDictionaryRef)keyAttributes, (void *)&gen_error));
if (gen_error != nil || privateKey == nil) { /* handled */ }
SecKeyRef publicKey = SecKeyCopyPublicKey(privateKey);
Boolean algorithmDSupported = SecKeyIsAlgorithmSupported(privateKey, kSecKeyOperationTypeDecrypt, kSecKeyAlgorithmECIESEncryptionCofactorX963SHA256AESGCM);
Boolean algorithmESupported = SecKeyIsAlgorithmSupported(publicKey, kSecKeyOperationTypeEncrypt, kSecKeyAlgorithmECIESEncryptionCofactorX963SHA256AESGCM);
// Returns true for both
// OK so far!
// Now retrieve the key just create to mock up using it later
NSDictionary *query = @{
(id)kSecClass: (id)kSecClassKey,
(id)kSecAttrApplicationTag: biometricKeyTag,
(id)kSecAttrKeyType: (id)kSecAttrKeyTypeEC,
(id)kSecReturnRef: @YES,
(id)kSecUseOperationPrompt: @""
};
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&privateKey);
if (status != noErr || privateKey == NULL) { /* handled */ }
publicKey = SecKeyCopyPublicKey(privateKey);
Boolean algorithmDSupported2 = SecKeyIsAlgorithmSupported(privateKey, kSecKeyOperationTypeDecrypt, kSecKeyAlgorithmECIESEncryptionCofactorX963SHA256AESGCM);
Boolean algorithmESupported2 = SecKeyIsAlgorithmSupported(publicKey, kSecKeyOperationTypeEncrypt, kSecKeyAlgorithmECIESEncryptionCofactorX963SHA256AESGCM);
// Encryption on the public key is supported, but algorithmDSupported2 is false – cannot decrypt with the key any more
Using the key retrieved with SecItemCopyMatching
for encryption with SecKeyCreateEncryptedData
seems to work, but SecKeyIsAlgorithmSupported
on …TypeDecrypt
returns false for these keys, and attempts to decrypt anyway unsurprisingly crashes the app.
How/why does the key not work after retrieval?
What solved it in the end was
kSecAccessControlBiometryAny|kSecAccessControlPrivateKeyUsage
kSecAttrKeyTypeECSECPrimeRandom
kSecPrivateKeyAttrs
keyNo idea why Apple lets you shoot yourself in the foot and doesn't properly validate key generation parameters.