How to recover RSA from file?

I want to restore the public key from a file. Here is the Java code that works:

PublicKey readPubKeyFromFile(AssetFileDescriptor cle) throws IOException { // read RSA public key byte[] encodedKey = new byte[(int) cle.getDeclaredLength()]; 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; } 

And here is the iOS code that does not work:

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

Any idea on what's wrong with my iOS code?

+4
source share
1 answer

I checked your code and there is nothing wrong with that. The problem seems to be related to the format of the certificates you are trying to get with the public key.

The SecCertificateCreateWithData () function assumes that the certificate you provide is in DER format. Most of the certificates you find are base64 encoded as the well-known .pem format. I checked your code with a correctly formatted DER certificate (developer.apple.com certificate form converted to DER using openssl) and the public key is correctly extracted.

To convert a .pem certificate to DER, just use openssl in the terminal:

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

After that, the certificate output file should work without problems with your code.

But you can convert the certificate directly to the application, you just need to capture the x649 base64 certificate (provided that you use certificates with the .pem encoding) and convert it to binary.

Here is an example of how you can do this:

This code will assume that the certificate is encoded in the following standard:

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

Code to convert this certificate to binary DER:

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

Then a little adaptation in your perfectly functional code does the trick:

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

Then just name it:

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

And if your certificate is "valid", you should see:

 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> 

For testing, I used a certificate from developer.apple.com, you can check the public key in the journal and compare it.

+1
source

Source: https://habr.com/ru/post/1440036/


All Articles