2011-03-22 63 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