【问题标题】:Convert XML Dsig format to DER ASN.1 public key将 XML Dsig 格式转换为 DER ASN.1 公钥
【发布时间】:2011-07-20 19:17:19
【问题描述】:

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

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

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

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

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

【问题讨论】:

  • 您好,您能分享一下如何将 ASN.1 转换为 Base64。我很难找到它。谢谢
  • @HelmiB - 它与任何其他二进制格式没有什么不同。

标签: ios rsa asn.1 xml-signature der


【解决方案1】:

所以,我使用SecKeyWrapper 类生成随机密钥,然后使用-getPublicKeyBits 方法获取公钥的二进制表示(内部使用的任何格式)。假设它是某种形式的 DER ASN.1,我将其 NSLog'd 以十六进制形式发送到控制台并将其加载到 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 库,请注意;还有苹果的演示代码 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;
}

【讨论】:

  • 不过要小心:如果模数(以及整个序列)的长度超过 128 个字节(但仍小于 256),则在 LL 前面需要一个 0x81 字节.想了解请看本文档第3.1节:luca.ntop.org/Teaching/Appunti/asn1.html
  • 128 长度检查包含在示例 Obj-C 代码中。
  • 您好,请问您的函数输入参数中的 base64PublicKey 是什么?为什么它被解码并存储到 keyData 中,只是为了再次初始化为 xml 文档?进入keydoc?
  • IIRC,它是一个 base64 编码的 XML 文档,来自一些 .NET Web 服务。 (可能来自对RSA.ToXmlString(false) 的一些调用)我不记得为什么它是base64 的;这发生在我工作的上游。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-08-23
  • 1970-01-01
  • 2020-01-25
  • 2021-06-22
  • 2010-11-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多