¿Cómo recuperar RSA del file?

Quiero recuperar una key pública de un file. Aquí está el código de Java que funciona:

PublicKey readPubKeyFromFile(AssetFileDescriptor cle) throws IOException { // read RSA public key byte[] encodedKey = new byte[(int) cle.getDeclanetworkingLength()]; cle.createInputStream().read(encodedKey); // create public key X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(encodedKey); PublicKey pk = null; try { KeyFactory kf = KeyFactory.getInstance("RSA"); pk = kf.generatePublic(publicKeySpec); } catch(Exception e) { Logger.getInstance().logError("KeyUtils", e.toString()); } return pk; } 

Y aquí está el código de iOS que no funciona:

 -(SecKeyRef)readPublicKeyFromFile:(NSString*)filename andExtension:(NSString*)extension { NSString* filePath = [[NSBundle mainBundle] pathForResource:filename ofType:extension]; NSData* encodedKey = [NSData dataWithContentsOfFile:filePath]; CFDataRef myCertData = (CFDataRef)encodedKey; SecCertificateRef cert = SecCertificateCreateWithData (kCFAllocatorSystemDefault, myCertData); CFArrayRef certs = CFArrayCreate(kCFAllocatorDefault, (const void **) &cert, 1, NULL); SecPolicyRef policy = SecPolicyCreateBasicX509(); SecTrustRef trust; OSStatus check = SecTrustCreateWithCertificates(certs, policy, &trust); if (check != noErr) { NSLog(@"Problem extracting public key from file: %@", filename); return nil; } SecTrustResultType trustResult; SecTrustEvaluate(trust, &trustResult); SecKeyRef pub_key_leaf = SecTrustCopyPublicKey(trust); return pub_key_leaf; } 

¿Alguna idea de lo que está mal en mi código iOS?

He probado su código y no hay nada malo con eso. El problema parece estar relacionado con el formatting de los certificates que está tratando de get de la key pública.

La function SecCertificateCreateWithData () supone que el certificate que está proporcionando está en formatting DER. La mayoría de los certificates que encuentra están codificados en base64 como el famoso formatting .pem. He probado su código con un certificate DER correctamente formateado (el formulario de certificate developer.apple.com convertido a DER con openssl) y la key pública se extrae correctamente.

Para convertir un certificate .pem a DER, simplemente use openssl en el terminal:

 openssl x509 -in developer.apple.com.pem -outform der -out cert.der 

Después de eso, el file de certificate de salida debería funcionar sin problemas con su código.

Pero puede convertir el certificate en la aplicación, solo necesita tomar el certificate codificado base x509 (suponiendo que está utilizando certificates codificados .pem) y convertirlo en binary.

Hay un ejemplo de cómo puedes hacerlo:

Este código asumirá que el certificate está codificado en el siguiente estándar:

 -----BEGIN CERTIFICATE----- < your base64 encoded certificate goes here > -----END CERTIFICATE----- 

El código para convertir este certificate en DER binary es:

 -(NSData *)getBinaryCertificateFromPemEncodedFile:(NSString *)filename andExtension:(NSString *)extension { NSString* filePath = [[NSBundle mainBundle] pathForResource:filename ofType:extension]; NSString *pemCert = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil]; //The header and footer conforms to .pem specificatio NSString *header = @"-----BEGIN CERTIFICATE-----"; NSString *footer = @"-----END CERTIFICATE-----"; NSString *base64Cert; NSScanner *scanner = [NSScanner scannerWithString:pemCert]; //First we ignore the header part [scanner scanString:header intoString:nil]; //Then we copy the base64 string excluding the footer [scanner scanUpToString:footer intoString:&base64Cert]; //The reason I'm using NSDataBase64DecodingIgnoreUnknownCharacters is to exclude possible line breaks in the encoding NSData *binaryCertificate = [[NSData alloc] initWithBase64EncodedString:base64Cert options:NSDataBase64DecodingIgnoreUnknownCharacters]; return binaryCertificate; } 

Entonces una pequeña adaptación en su código perfectamente funcional hace el truco:

 -(SecKeyRef)readPublicKeyFromCertificate:(NSData *)binaryCertificate { NSData *encodedKey = binaryCertificate; CFDataRef myCertData = (CFDataRef)CFBridgingRetain(encodedKey); SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorSystemDefault, myCertData); SecPolicyRef policy = SecPolicyCreateBasicX509(); SecTrustRef trust; //If you only have one certificate you don't need to put it inside an array OSStatus check = SecTrustCreateWithCertificates(cert, policy, &trust); if (check != noErr) { NSLog(@"Problem extracting public key from certificate"); return nil; } SecTrustResultType trustResult; SecTrustEvaluate(trust, &trustResult); SecKeyRef pub_key_leaf = SecTrustCopyPublicKey(trust); return pub_key_leaf; } 

Entonces simplemente llámalo:

 NSData *data = [self getBinaryCertificateFromPemEncodedFile:@"developer" andExtension:@"pem"]; SecKeyRef key = [self readPublicKeyFromCertificate:data]; NSLog(@"%@", key); 

Y si su certificate es "válido", debería ver:

 2014-09-15 21:52:13.275 cert[15813:60b] <SecKeyRef algorithm id: 1, key type: RSAPublicKey, version: 2, block size: 2048 bits, exponent: {hex: 10001, decimal: 65537}, modulus: BE19E30F47F2D31F27D576CF007B3E615F986D14AFD0D52B825E01E90BA3E1CBB6F3A472E6AECDC28BC13D0B6E58FC497ACF61D80F274E4799602DA4F819E54ADDE2FBFA89FC4EB2172501DDED8DE0FBDDBC5550CC018C73E1FD8152C905DE850862B8D57596025DE1908D8337E95637AF0F52C4A11DA178FF737DCE09471BC0A49DAD7DB39F1BA1B693D3A12F9CA50EF388B50292C73076BF1EEE412A5CFA940E99D4CF07F17FAC87F0D0E2FC8FA3ACDDEEFCCE8AFEC407B94536FCB1E4ACF34773728D189F85EAE4347E0BF868D25C7CE89F8A29B4E6865C68F4F915DFA540549EE9333007145D367FE2852622AAD776F3E5D505A02E5155CC8646A01C1031, addr: 0x9a48200> 

Para probar, he usado el certificate de developer.apple.com, puedes verificar la key pública en el logging y compararlo.