我正在开发一个iPhone应用程序,它以以下形式从ASP.NET Web服务检索RSA公钥:
<RSAKeyValue>
<Modulus>qdd0paiiBJ+xYaN4TKDdbEzrJJw9xlbRAltb5OPdegjLoW60yOjL/sni52WVsGC9QxpNitZR33dnUscmI0cTJoxkXypPjbD94UpH+p4el2tuKBypHlE7bERApuUp55y8BiRkbQNFH8smZFWDwtIc/PsJryeGf8fAryel8c5V3PU=</Modulus>
<Exponent>AQAB</Exponent>
</RSAKeyValue>
然后我需要将此响应转换为适当格式的NSData *
(来自一些强烈的谷歌搜索,最可能是'ASN.1 DER'二进制格式。我已经有代码来转换这两个部分他们的Base64表示原始的二进制值,但我不能为我的生活找出一个合理的方法来创建一个二进制密钥。
等待密钥的代码是Apple的-addPeerPublicKey:(NSString *) keyBits:(NSData *)
示例项目{代码here)SecKeyWrapper
类的CryptoExercise
方法。
我非常乐意以另一种方式实现 - 我只需要加密一个字符串(不需要解密)。据我所知,内置的安全框架有我需要的东西,如果我可以关闭这种格式差距。如果有一种方法来转换密钥并从Web服务发送Base64编码,这对我也有用 - 但我找不到任何方法在那里进行ASN.1编码。
答案 0 :(得分:1)
因此,我使用SecKeyWrapper
类生成随机密钥,然后使用-getPublicKeyBits
方法获取公钥的二进制表示(以内部使用的任何格式)。假设它是某种形式的DER ASN.1,我将它作为十六进制格式化到控制台并将其加载到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;
}