2011-03-22 61 views
1

我上检索从形式的ASP.NET Web服务的RSA公钥一个iPhone应用程序的工作:转换XML Dsig的格式DER ASN.1公钥

<RSAKeyValue> 
    <Modulus>qdd0paiiBJ+xYaN4TKDdbEzrJJw9xlbRAltb5OPdegjLoW60yOjL/sni52WVsGC9QxpNitZR33dnUscmI0cTJoxkXypPjbD94UpH+p4el2tuKBypHlE7bERApuUp55y8BiRkbQNFH8smZFWDwtIc/PsJryeGf8fAryel8c5V3PU=</Modulus> 
    <Exponent>AQAB</Exponent> 
</RSAKeyValue> 

我需要再转换这个响应的格式为NSData *(从一些激烈的谷歌搜索,最有可能的'ASN.1 DER'二进制格式。我有代码将两个部分从Base64表示转换为原始二进制值,但我可以对我来说,找出一个合理的方法来创建单件二进制密钥。

等待密钥的代码是-addPeerPublicKey:(NSString *) keyBits:(NSData *)来自Apple的CryptoExercise示例项目(代码here)的SecKeyWrapper类的方法。

我会非常乐意以另一种方式实现这一点 - 我需要的是加密单个字符串(不需要解密)。据我所知,内置的安全框架具有我所需要的,如果我能够缩小这种格式差距的话。如果有一种方法可以将密钥转换为Base64编码的web服务,那也适用于我 - 但我找不到任何可以ASN.1编码的方法。

+0

嗨,你可以分享如何将ASN.1转换为Base64。我很难找到它。谢谢 – HelmiB 2012-10-29 04:55:37

+0

@HelmiB - 它和任何其他二进制格式没有区别。 – 2012-10-29 17:02:53

回答

1

因此,我使用SecKeyWrapper类来生成一个随机密钥,然后使用-getPublicKeyBits方法获取公钥的二进制表示形式(以任何内部使用的格式)。假设它是某种形式的DER ASN.1,我将NSLog以十六进制格式存入控制台,并将其加载到this program中。果然,内部表示DER ASN.1,但它是什么,我通常发现RSA密钥表示一个非常简化的版本:

![SEQUENCE { INTEGER, INTEGER }][2] 

应该不会太难从二进制上,随时制作代表。的模数和指数,因为DER编码只是

30 (for SEQUENCE) LL (total sequence byte length) 
02 (INTEGER) LL (modulus byte length) XX XX... (modulus data bytes) 
02 LL XX XX XX... (exponent length and bytes) 

这是我的代码,为简单起见。它使用了一些用于XML + base64的Google库,只是站起来;还有Apple的演示代码SecKeyWrapper。有关进行此项工作的说明,请参见my other question。另外请注意,它是而不是 ARC兼容;这是留给读者的一个练习(我今年以前写过)。

#define kTempPublicKey @"tempPayKey" 
-(NSData *)encryptedDataWithXMLPublicKey:(NSString *)base64PublicKey data:(NSData *)data { 
    if(![data length]){ 
     @throw [NSException exceptionWithName:@"NSInvalidArgumentException" reason:@"Data not set." userInfo:nil]; 
    } 
    GTMStringEncoding *base64 = [GTMStringEncoding rfc4648Base64StringEncoding]; 
    NSData *keyData = [base64 decode:base64PublicKey]; 
    NSError *err = nil; 
    GDataXMLDocument *keyDoc = [[GDataXMLDocument alloc] initWithData:keyData options:0 error:&err]; 
    if(err){ 
     NSLog(@"Public key parse error: %@",err); 
     [keyDoc release]; 
     return nil; 
    } 

    NSString *mod64 = [[[[keyDoc rootElement] elementsForName:@"Modulus"] lastObject] stringValue]; 
    NSString *exp64 = [[[[keyDoc rootElement] elementsForName:@"Exponent"] lastObject] stringValue]; 
    [keyDoc release]; 
    if(![mod64 length] || ![exp64 length]){ 
     @throw [NSException exceptionWithName:@"NSInvalidArgumentException" reason:@"Malformed public key xml." userInfo:nil]; 
    } 

    NSData *modBits = [base64 decode:mod64]; 
    NSData *expBits = [base64 decode:exp64]; 

    /* the following is my (bmosher) hack to hand-encode the mod and exp 
    * into full DER encoding format, using the following as a guide: 
    * http://luca.ntop.org/Teaching/Appunti/asn1.html 
    * this is due to the unfortunate fact that the underlying API will 
    * only accept this format (not the separate values) 
    */ 

    // 6 extra bytes for tags and lengths 
    NSMutableData *fullKey = [[NSMutableData alloc] initWithLength:6+[modBits length]+[expBits length]]; 
    unsigned char *fullKeyBytes = [fullKey mutableBytes]; 
    unsigned int bytep = 0; // current byte pointer 
    fullKeyBytes[bytep++] = 0x30; 
    if(4+[modBits length]+[expBits length] >= 128){ 
     fullKeyBytes[bytep++] = 0x81; 
     [fullKey increaseLengthBy:1]; 
    } 
    unsigned int seqLenLoc = bytep; 
    fullKeyBytes[bytep++] = 4+[modBits length]+[expBits length]; 
    fullKeyBytes[bytep++] = 0x02; 
    if([modBits length] >= 128){ 
     fullKeyBytes[bytep++] = 0x81; 
     [fullKey increaseLengthBy:1]; 
     fullKeyBytes[seqLenLoc]++; 
    } 
    fullKeyBytes[bytep++] = [modBits length]; 
    [modBits getBytes:&fullKeyBytes[bytep]]; 
    bytep += [modBits length]; 
    fullKeyBytes[bytep++] = 0x02; 
    fullKeyBytes[bytep++] = [expBits length]; 
    [expBits getBytes:&fullKeyBytes[bytep++]]; 

    SecKeyRef publicKey = [[SecKeyWrapper sharedWrapper] addPeerPublicKey:kTempPublicKey keyBits:fullKey]; 
    [fullKey release]; 

    NSData *encrypted = [[SecKeyWrapper sharedWrapper] wrapSymmetricKey:data keyRef:publicKey]; 
    // remove temporary key from keystore 
    [[SecKeyWrapper sharedWrapper] removePeerPublicKey:kTempPublicKey]; 

    return encrypted; 
} 
+1

但要小心:如果模数的长度(从而整个序列)超过128个字节(但仍然<256),那么在LL前面需要一个0x81字节。如果您想了解:请参阅本文档的第3.1节:http://luca.ntop.org/Teaching/Appunti/asn1.html – 2011-03-23 17:43:39

+0

您是否有相同的示例代码? – Devarshi 2014-09-03 06:38:34

+0

128长度检查包含在示例Obj-C代码中。 – 2014-09-03 12:13:32