将XML Dsig格式转换为DER ASN.1公钥

我正在处理一个iPhone应用程序,它从ASP.NET web服务中以如下格式检索RSA公钥:

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

然后我需要将这个响应转换成适当格式的NSData * (从一些激烈的谷歌search,很可能是'ASN.1 DER'二进制格式。我已经有代码将两个部分从Base64表示转换为原始二进制值,但我不能为我的生活找出一个合理的方式来创build一个一体化的二进制密钥。

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

我将非常乐意以另一种方式实现这一点 – 我需要的只是encryption一个string(不需要解密)。 据我所知,虽然内置的安全框架有我所需要的,如果我能够缩小这种格式的差距。 如果有一种方法来转换密钥,并从webservice发送Base64编码,那也适用于我 – 但是我找不到ASN.1编码它的任何方法。

因此,我使用SecKeyWrapper类来生成一个随机密钥,然后使用-getPublicKeyBits方法来获取公钥的二进制表示forms(以内部使用的任何格式)。 假设它是某种forms的DER ASN.1,我NSLog把它作为hex的控制台,并加载到这个程序 。 果然,内部表示是DER ASN.1,但它是我通常在RSA密钥表示中发现的非常简化的版本:

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

从二进制代码中dynamic构build应该不是太难。 的模数和指数,因为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库, 还有苹果的演示代码SecKeyWrapper。 看到我的另一个问题作出这项工作的说明。 另外请注意,它不是 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; }