1

ASP.NET Web サービスから次の形式で RSA 公開キーを取得する iPhone アプリに取り組んでいます。

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

次に、この応答を適切な形式に変換する必要がありNSData *ます (激しいグーグル、おそらく「ASN.1 DER」バイナリ形式から。両方の部分を Base64 表現から元のバイナリ値に変換するコードを用意しました。 、しかし、私は一生、ワンピースのバイナリキーを作成する合理的な方法を見つけることができません。

キーを待っているコードは、 Apple のサンプル プロジェクト (Code here )のクラスの-addPeerPublicKey:(NSString *) keyBits:(NSData *)メソッドです。SecKeyWrapperCryptoExercise

これを別の方法で実装できれば幸いです。必要なのは、単一の文字列を暗号化することだけです (復号化は必要ありません)。ただし、この形式のギャップを埋めることができれば、ビルトインのセキュリティ フレームワークには必要なものがすべて揃っていると言えます。キーを変換してWebサービスからBase64でエンコードして送信する方法があれば、それもうまくいきますが、ASN.1でエンコードする方法も見つかりませんでした。

4

1 に答える 1

1

そのため、このSecKeyWrapperクラスを使用してランダム キーを生成し、-getPublicKeyBitsメソッドを使用して公開キーのバイナリ表現を取得しました (内部で使用されている形式は何でも)。DER ASN.1 の何らかの形式であると仮定して、16 進数としてコンソールに NSLog し、このプログラムにロードしました。案の定、内部表現は 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 もあります。この作業に関するメモについては、私の他の質問を参照してください。また、 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 に答える