1

我正在开发一个 iPhone 应用程序,该应用程序以以下形式从 ASP.NET Web 服务中检索 RSA 公钥:

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

然后我需要将此响应转换为NSData *适当的格式(来自一些激烈的谷歌搜索,很可能是“ASN.1 DER”二进制格式。我已经准备好将这两个部分从它们的 Base64 表示形式转换为原始二进制值的代码,但我终其一生都无法找到一种合理的方法来创建一体式二进制密钥。

等待key的代码是来自Apple的示例项目-addPeerPublicKey:(NSString *) keyBits:(NSData *)的类的方法(代码在这里)。SecKeyWrapperCryptoExercise

我很乐意以另一种方式实现这一点——我只需要加密一个字符串(不需要解密)。不过,据我所知,如果我能缩小这种格式差距,内置的安全框架就可以满足我的需求。如果有一种方法可以转换密钥并从 Web 服务发送 Base64 编码的密钥,那也适用于我——但我也找不到任何 ASN.1 编码的方法。

4

1 回答 1

1

因此,我使用SecKeyWrapper该类生成一个随机密钥,然后使用该-getPublicKeyBits方法获取公钥的二进制表示(以内部使用的任何格式)。假设它是某种形式的 DER ASN.1,我 NSLog'd 以十六进制形式将其登录到控制台并将其加载到此程序中。果然,内部表示是 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 库,请注意;还有苹果的演示代码 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;
}
于 2011-03-23T13:39:01.493 回答