Como descobrir o módulo e o expoente da chave pública RSA no iPhone / Objective C

Existe uma maneira possível de descobrir o módulo e o expoente da chave pública, criada com o SecKeyGeneratePair (a estrutura de segurança em geral)?

Busted minha cabeça sobre isso, mas aqui está uma solução que encontrei (sem usar nenhum pacote externo).

Primeiro, vá ao exemplo do CryptoExercise da Apple. Baixe a class “SecKeyWrapper” de lá. A function interessante nessa class é getPublicKeyBits.

Link para o exemplo: http://developer.apple.com/library/ios/#samplecode/CryptoExercise/Introduction/Intro.html

Os bits que você receberá são uma chave pública codificada pelo DER (wiki) contendo tanto o módulo quanto o exp. Aqui está um código que irá decodificá-lo para você, muito fácil:

- (NSData *)getPublicKeyExp { NSData* pk = [self getPublicKeyBits]; if (pk == NULL) return NULL; int iterator = 0; iterator++; // TYPE - bit stream - mod + exp [self derEncodingGetSizeFrom:pk at:&iterator]; // Total size iterator++; // TYPE - bit stream mod int mod_size = [self derEncodingGetSizeFrom:pk at:&iterator]; iterator += mod_size; iterator++; // TYPE - bit stream exp int exp_size = [self derEncodingGetSizeFrom:pk at:&iterator]; return [pk subdataWithRange:NSMakeRange(iterator, exp_size)]; } - (NSData *)getPublicKeyMod { NSData* pk = [self getPublicKeyBits]; if (pk == NULL) return NULL; int iterator = 0; iterator++; // TYPE - bit stream - mod + exp [self derEncodingGetSizeFrom:pk at:&iterator]; // Total size iterator++; // TYPE - bit stream mod int mod_size = [self derEncodingGetSizeFrom:pk at:&iterator]; return [pk subdataWithRange:NSMakeRange(iterator, mod_size)]; } - (int)derEncodingGetSizeFrom:(NSData*)buf at:(int*)iterator { const uint8_t* data = [buf bytes]; int itr = *iterator; int num_bytes = 1; int ret = 0; if (data[itr] > 0x80) { num_bytes = data[itr] - 0x80; itr++; } for (int i = 0 ; i < num_bytes; i++) ret = (ret * 0x100) + data[itr + i]; *iterator = itr + num_bytes; return ret; } 

Eu tentei essa abordagem e funciona bem para extrair o expoente. Ele tem 3 bytes de tamanho como esperado, mas o módulo extraído não tem o tamanho correto. O tamanho do módulo é 129 bytes em vez de 128 bytes.

O código é o seguinte:

 - (NSData *)getPublicKeyBits: (NSString*) publicKeyIdentifier { OSStatus sanityCheck = noErr; NSData * publicKeyBits = nil; CFTypeRef pk; NSMutableDictionary * queryPublicKey = [[NSMutableDictionary alloc] init]; NSData* publicTag = [publicKeyIdentifier dataUsingEncoding:NSUTF8StringEncoding]; // Set the public key query dictionary. [queryPublicKey setObject:(__bridge_transfer id)kSecClassKey forKey:(__bridge_transfer id)kSecClass]; [queryPublicKey setObject:publicTag forKey:(__bridge_transfer id)kSecAttrApplicationTag]; [queryPublicKey setObject:(__bridge_transfer id)kSecAttrKeyTypeRSA forKey:(__bridge_transfer id)kSecAttrKeyType]; [queryPublicKey setObject:[NSNumber numberWithBool:YES] forKey:(__bridge_transfer id)kSecReturnData]; // Get the key bits. sanityCheck = SecItemCopyMatching((__bridge_retained CFDictionaryRef)queryPublicKey, &pk); if (sanityCheck != noErr) { publicKeyBits = nil; } publicKeyBits = (__bridge_transfer NSData*)pk; //NSLog(@"public bits %@",publicKeyBits); return publicKeyBits; } - (NSData *)getPublicKeyExp { NSData* pk = [self getPublicKeyBits:@"RSA Public Key"]; if (pk == NULL) return NULL; int iterator = 0; iterator++; // TYPE - bit stream - mod + exp [self derEncodingGetSizeFrom:pk at:&iterator]; // Total size iterator++; // TYPE - bit stream mod int mod_size = [self derEncodingGetSizeFrom:pk at:&iterator]; iterator += mod_size; iterator++; // TYPE - bit stream exp int exp_size = [self derEncodingGetSizeFrom:pk at:&iterator]; return [pk subdataWithRange:NSMakeRange(iterator, exp_size)]; return pk; } - (NSData *)getPublicKeyMod { NSData* pk = [self getPublicKeyBits:@"RSA Public Key"]; if (pk == NULL) return NULL; int iterator = 0; iterator++; // TYPE - bit stream - mod + exp [self derEncodingGetSizeFrom:pk at:&iterator]; // Total size iterator++; // TYPE - bit stream mod int mod_size = [self derEncodingGetSizeFrom:pk at:&iterator]; return [pk subdataWithRange:NSMakeRange(iterator, mod_size)]; return pk; NSLog(@"public size: %d",pk.length); } - (int)derEncodingGetSizeFrom:(NSData*)buf at:(int*)iterator { const uint8_t* data = [buf bytes]; int itr = *iterator; int num_bytes = 1; int ret = 0; if (data[itr] > 0x80) { num_bytes = data[itr] - 0x80; itr++; } for (int i = 0 ; i < num_bytes; i++) ret = (ret * 0x100) + data[itr + i]; *iterator = itr + num_bytes; return ret; } 

Algo como o seguinte é muito mais confiável:

 + (NSInteger)keyModulusSize:(NSData *)keyData { NSString *randomTag = [NSString ptk_randomStringOfLength:32]; SecKeyRef key = [self addPublicKeyRef:keyData withTag:randomTag]; NSInteger size = 0; if (key) { size = SecKeyGetBlockSize(key); [self removePublicKeyRef:randomTag]; } return size; } 

Eu removi esse byte extra no começo, agora funciona bem. No meu caso, foi sempre extrair o módulo de 129 bytes.

 - (NSData *)getPublicKeyModFromKeyData:(NSData*)pk { if (pk == NULL) return NULL; int iterator = 0; iterator++; // TYPE - bit stream - mod + exp [self derEncodingGetSizeFrom:pk at:&iterator]; // Total size iterator++; // TYPE - bit stream mod int mod_size = [self derEncodingGetSizeFrom:pk at:&iterator]; // return [pk subdataWithRange:NSMakeRange(iterator, mod_size)]; NSData* subData=[pk subdataWithRange:NSMakeRange(iterator, mod_size)]; return [subData subdataWithRange:NSMakeRange(1, subData.length-1)]; }