Подтвердить что ты не робот

IOS SecKeyRef для NSData

У меня есть два ключа, общедоступные и частные, которые хранятся в переменных SecKeyRef. Для простоты позвольте начать с публичного. Я хочу сделать это, экспортируя его в объект NSData. Для этого в Apple есть почти известный фрагмент кода, который находится здесь:

- (NSData *)getPublicKeyBits {
    OSStatus sanityCheck = noErr;
    NSData * publicKeyBits = nil;

    NSMutableDictionary * queryPublicKey = [[NSMutableDictionary alloc] init];

    // Set the public key query dictionary.
    [queryPublicKey setObject:(id)kSecClassKey forKey:(id)kSecClass];
    [queryPublicKey setObject:publicTag forKey:(id)kSecAttrApplicationTag];
    [queryPublicKey setObject:(id)kSecAttrKeyTypeRSA forKey:(id)kSecAttrKeyType];
    [queryPublicKey setObject:[NSNumber numberWithBool:YES] forKey:(id)kSecReturnData];

    // Get the key bits.
    sanityCheck = SecItemCopyMatching((CFDictionaryRef)queryPublicKey, (CFTypeRef *)&publicKeyBits);

    if (sanityCheck != noErr)
    {
        publicKeyBits = nil;
    }

    [queryPublicKey release];

    return publicKeyBits;
}

У меня есть Xcode 4.6.2, и код выглядит ошибочным ( "__bridge" добавляется перед каждым преобразованием в id). Новая версия выглядит так:

- (NSData *)getPublicKeyBitsFromKey:(SecKeyRef)givenKey {
    OSStatus sanityCheck = noErr;
    NSData * publicKeyBits = nil;

    NSMutableDictionary * queryPublicKey = [[NSMutableDictionary alloc] init];

    // Set the public key query dictionary.
    [queryPublicKey setObject:(__bridge id)kSecClassKey forKey:(__bridge id)kSecClass];
    [queryPublicKey setObject:publicTag forKey:(__bridge id)kSecAttrApplicationTag];
    [queryPublicKey setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
    [queryPublicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge id)kSecReturnData];

    // Get the key bits.
    sanityCheck = SecItemCopyMatching((__bridge CFDictionaryRef)queryPublicKey, (CFTypeRef *)&publicKeyBits);

    if (sanityCheck != noErr)
    {
        publicKeyBits = nil;
    }

    return publicKeyBits;
}

Есть еще две ошибки:

  • использование незаявленного идентификатора 'publicTag'
  • Приведение косвенного указателя на указатель Objective-C на 'CFTypeRef' (aka 'const void *') не разрешено с помощью ARC

Теперь я надеюсь, что после вашей помощи первая проблема больше не будет проблемой, потому что я не хочу создавать запрос или еще не извлекать ключ из брелка. Я имею его в переменной, и я хочу извлечь его оттуда. Имя переменной givenPublicKey и что ключ, который я хочу преобразовать в NSData.

Итак, как я буду заниматься этим и решить эту проблему ARC?

Последующие действия: Как я могу экспортировать закрытый ключ в NSData, так как я читал несколько раз, что функция, с которой я пытаюсь работать, работает только для открытых ключей.

4b9b3361

Ответ 1

  • использование незаявленного идентификатора 'publicTag'

publicTag - это просто уникальный идентификатор, добавленный к элементам Keychain. В примере с образцом CryptoExercise он определяется как

#define kPublicKeyTag "com.apple.sample.publickey"
static const uint8_t publicKeyIdentifier[] = kPublicKeyTag;
NSData *publicTag = [[NSData alloc] initWithBytes:publicKeyIdentifier length:sizeof(publicKeyIdentifier)];
  • Приведение косвенного указателя на указатель Objective-C на 'CFTypeRef' (aka 'const void *') не разрешено с помощью ARC

Это можно решить, используя временную переменную CFTypeRef:

CFTypeRef result;
sanityCheck = SecItemCopyMatching((__bridge CFDictionaryRef)queryPublicKey, &result);
if (sanityCheck == errSecSuccess) {
    publicKeyBits = CFBridgingRelease(result);
}
  • Я не хочу создавать запрос или еще что-то, чтобы извлечь ключ из брелка. Я имею его в переменной, и я хочу извлечь его оттуда...

Насколько я знаю, вам нужно временно хранить SecKeyRef в Keychain. SecItemAdd имеет возможность вернуть добавленный элемент в качестве данных. Из документации:

Чтобы получить данные добавленного элемента как объекта типа CFDataRef, укажите ключ типа возврата kSecReturnData со значением kCFBooleanTrue.

Объединяя все это, следующий код должен делать то, что вы хотите:

- (NSData *)getPublicKeyBitsFromKey:(SecKeyRef)givenKey {

    static const uint8_t publicKeyIdentifier[] = "com.your.company.publickey";
    NSData *publicTag = [[NSData alloc] initWithBytes:publicKeyIdentifier length:sizeof(publicKeyIdentifier)];

    OSStatus sanityCheck = noErr;
    NSData * publicKeyBits = nil;

    NSMutableDictionary * queryPublicKey = [[NSMutableDictionary alloc] init];
    [queryPublicKey setObject:(__bridge id)kSecClassKey forKey:(__bridge id)kSecClass];
    [queryPublicKey setObject:publicTag forKey:(__bridge id)kSecAttrApplicationTag];
    [queryPublicKey setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];

    // Temporarily add key to the Keychain, return as data:
    NSMutableDictionary * attributes = [queryPublicKey mutableCopy];
    [attributes setObject:(__bridge id)givenKey forKey:(__bridge id)kSecValueRef];
    [attributes setObject:@YES forKey:(__bridge id)kSecReturnData];
    CFTypeRef result;
    sanityCheck = SecItemAdd((__bridge CFDictionaryRef) attributes, &result);
    if (sanityCheck == errSecSuccess) {
        publicKeyBits = CFBridgingRelease(result);

        // Remove from Keychain again:
        (void)SecItemDelete((__bridge CFDictionaryRef) queryPublicKey);
    }

    return publicKeyBits;
}

Я надеюсь, что это сработает, я не могу проверить это на данный момент.

  • Последующие действия: Как я могу экспортировать закрытый ключ в NSData, так как я читал несколько раз, что функция, с которой я пытаюсь работать, работает только для открытых ключей.

Я не знаю.