Unable to delete symmetric key from keychain.

Hi,

New to the forum, I had some specific queries I wanted to discuss. My current goal is to encrypt NSData objects using Security Transforms, specified in the Apple Developer website. I managed to create a random symmetric key following the tutorial here, in the form of a SecKeyRef object.

https://developer.apple.com/library/content/documentation/Security/Conceptual/SecTransformPG/EncryptionandDecryption/EncryptionandDecryption.html

The symmetric key performs flawlessly for both encryption and decryption. However, I need to store this key into the keychain, for which Im facing a lot of issues.

Firstly, using this method to store key into the keychain gives me an error -67712 : Invalid key object.

+(BOOL) addKeyToKeyChain:(SecKeyRef) key
{
    NSString *tag = @"com.mykey";
    NSData *tagData = [tag dataUsingEncoding:NSUTF8StringEncoding];
    NSDictionary *addQuery = @{ (id)kSecClass: (id)kSecClassKey,
                                (id)kSecValueRef: (__bridge id)key,
                                (id)kSecAttrApplicationTag: tagData,
                                (id)kSecAttrKeyType: (id)kSecAttrKeyTypeAES,
                                };
    OSStatus status = SecItemAdd((CFDictionaryRef)addQuery, NULL);
    if(status != errSecSuccess) {
        NSLog(@"%d", (int)status);
        NSLog(@"Error in storing key to keychain");
        return FALSE;
    }

    NSLog(@"Key successfully stored in keychain");
    return TRUE;
}

If I create a key manually using this method

+ (NSString*)generateSecureKey
{
    NSMutableData *data = [NSMutableData dataWithLength:256];
    int result = SecRandomCopyBytes(kSecRandomDefault, 256, data.mutableBytes);
    if (result != noErr) {
        return nil;
    }
    return [data base64EncodedStringWithOptions:kNilOptions];
}

and try to store it by using kSecValueData instead of kSecValueRef, passing a CFString, generated and casted from the above method, the key item does appear in the keychain but it has missing values and im unable to delete it.

Using terminal command

security find-key -l com.mykey

does locate the key but lists invalid or missing data. I cant find any other way to delete this key other than drop the keychain altogether and reset it, which is a massive pain as I have to revoke and renable my xcode developer profile and certificates to get code signing to work.


Id like a solution to this :

1) How to delete a corrupt key from keychain, without resetting whole keychain. (Remember, im using the login keychain).

2) How to store a SecKeyRef key to the keychain and retrieve it without any loss.


Thanks in advance

Replies

Hello,


The documentation to only store end retrieve symmetric key is very poor. Apple to everthing they can to discourage people to do it, tell them to use generic password type (with account and service) and not using "the low level SecItemAdd" forgetting that its not a password but a key and with symmetric key you don't need keychain authentification. Force their clients to use their opaque, black box and very obscure encryption tool.


They have the stomach to write : "If you obtain a key by some other means, you can still store it in the keychain."

But they do nothing to help you to do it (example...)


if you use their example you'll create an entry in keychain but you will be unable to delete it.This entry is unusable, like your point N° 1


2 - I found a way to store and retrieve symmetric key but sometime (i dont know why ) you can't retrieve them.


The sequence is Data -> SecKey -> Keychain

and Keychain -> SecKey -> Data


To store a symmetric key:


- Create an attributes dictionnary (CFString, any) with :


kSecAttrKeyType -> kSecAttrKeyTypeAES

kSecAttrKeySizeInBits -> 128 for example


Convert your data to SecKey with SecKeyCreateFromData (attributesDic, yourData, nil)


Create anotther dictionnary for keychain with :


kSecClass -> kSecClassKey

kSecAttrApplicationTag -> yourApplicationTag (Data)

kSecAttrApplicationLabel -> yourApplication label (Data)

kSecValueRef -> SecKey


i added


kSecAttrLabel -> String type

kSecAttrIsPermanent -> true


Create the keychain item with SecItemAdd(attributesKeychain, nil)


To retrieve from keychain


Create a query dictionnary with :


kSecClass -> kSecClassKey

kSecAttrApplicationTag -> yourApplicationTag (Data)

kSecAttrApplicationLabel -> yourApplication label (Data)

kSecReturnRef -> true


define secKey as CFTypeRef

get the secKey with SecItemCopyMatching(query, &seccKey)


get the dictionnary of the secKey with SecKeyCopyAttributes(secKey)

get the data with kSecValueData as key of the dictionnary.


Sometime the last step does not work, there is a missing entry in the secKey dictionnary, i don't know why.


Hope this help