iOS SecKeyRef a NSData

Tengo dos keys, públicas y privadas, que están almacenadas en SecKeyRef-variables. Para simplificar, comencemos con el público. Lo que quiero hacer es exportarlo a un object NSData. Para eso, hay un fragment de código casi famoso proporcionado por Apple, que está aquí:

- (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; } 

Sin embargo, tengo Xcode 4.6.2 y el código aparece erróneo ("__bridge" se agrega antes de cada conversión a id). La nueva versión se ve así:

 - (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; } 

Sin embargo, todavía hay dos errores:

  • uso del identificador no declarado 'publicTag'
  • El lanzamiento de un puntero indirecto a un puntero de Objective-C a 'CFTypeRef ' (también conocido como 'const void * ') no está permitido con ARC

Ahora, espero que después de su ayuda, el primer problema ya no sea un problema, ya que no quiero crear una consulta o extraer la key del llavero. Lo tengo en una variable y deseo extraerlo de allí. El nombre de la variable se le da a givenPublicKey , y esa es la key que deseo convertir a NSData.

Entonces, ¿cómo iba a hacer esto y resolver este problema de ARC?

Seguimiento: ¿Cómo puedo exportar una key privada a NSData, ya que he leído varias veces que la function con la que bash trabajar solo funciona para keys públicas.

  • uso del identificador no declarado 'publicTag'

La publicTag es solo un identificador único agregado a los elementos del llavero. En el proyecto de ejemplo CryptoExercise se define como

 #define kPublicKeyTag "com.apple.sample.publickey" static const uint8_t publicKeyIdentifier[] = kPublicKeyTag; NSData *publicTag = [[NSData alloc] initWithBytes:publicKeyIdentifier length:sizeof(publicKeyIdentifier)]; 
  • El lanzamiento de un puntero indirecto a un puntero de Objective-C a 'CFTypeRef' (también conocido como 'const void *') no está permitido con ARC

Esto se puede resolver utilizando una variable temporal CFTypeRef :

 CFTypeRef result; sanityCheck = SecItemCopyMatching((__bridge CFDictionaryRef)queryPublicKey, &result); if (sanityCheck == errSecSuccess) { publicKeyBits = CFBridgingRelease(result); } 
  • No quiero crear una consulta o lo que sea para extraer la key del llavero. Lo tengo en una variable y deseo extraerlo de allí …

Por lo que sé, debes almacenar temporalmente el SecKeyRef en el llavero. SecItemAdd tiene la opción de devolver el elemento agregado como datos. De la documentation:

Para get los datos del elemento agregado como un object de tipo CFDataRef , especifique la key de tipo de retorno kSecReturnData con un valor de kCFBooleanTrue .

Al unir todo esto, el siguiente código debería hacer lo que desea:

 - (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; } 

Espero que esto funcione, no puedo probarlo en este momento.

  • Seguimiento: ¿Cómo puedo exportar una key privada a NSData, ya que he leído varias veces que la function con la que bash trabajar solo funciona para keys públicas.

No lo sé.