2012-10-16 76 views
4

我想从文件恢复公钥。这里是工作的Java代码:如何从文件中恢复RSA?

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

这里是iOS的代码不起作用:

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

的什么是错的,我的iOS代码的任何想法?

+3

欢迎来到stackoverflow。它怎么不工作? –

+0

这返回零: SecCertificateRef cert = SecCertificateCreateWithData(kCFAllocatorSystemDefault,myCertData); – ettibo

+0

有任何意见,我在同一个地方堆叠。 – shebelaw

回答

1

我测试了你的代码,没有错。问题似乎与您试图获取公钥的证书的格式有关。

函数SecCertificateCreateWithData()假定您提供的证书是DER格式。您发现的大多数证书都使用base64编码,如着名的.pem格式。我用正确格式化的DER证书(使用openssl将证书表单developer.apple.com转换为DER)测试了您的代码,并且正确提取了公钥。

要转换的.pem证书为DER只需在终端使用OpenSSL:已

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

,输出证书文件后应与你的代码没有问题的工作。

但是,您可以在应用程序本身上转换证书,只需要抓取de x509 base64编码证书(假设您使用.pem编码的证书)并将其转换为二进制。

有一个例子,你如何能做到这一点:

此代码将假定证书在以下标准编码:

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

的代码为二进制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; 
} 

然后在你的完美的功能代码一个小调整的伎俩:

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

然后叫它:

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

如果您的证书是 “有效的”,你应该看到:

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> 

为了测试我从developer.apple.com使用的证书,您可以检查日志中的公钥并进行比较。