Конвертировать формат XML Dsig в ​​открытый ключ DER ASN.1 - PullRequest
1 голос
/ 22 марта 2011

Я работаю над приложением для iPhone, которое извлекает открытый ключ RSA из веб-службы ASP.NET в форме:

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

Мне нужно затем преобразовать этот ответ в NSData * изсоответствующий формат (из некоторого интенсивного поиска в Google, наиболее вероятно двоичного формата 'ASN.1 DER'. У меня есть код для преобразования обеих частей из их представлений Base64 в исходные двоичные значения, но я не могу на всю жизньнайти разумный способ создания цельного двоичного ключа.

Код, ожидающий ключа, - это метод -addPeerPublicKey:(NSString *) keyBits:(NSData *) класса SecKeyWrapper из примера проекта Apple CryptoExercise (Код здесь ).

Я был бы более чем рад реализовать этот другой способ - все, что мне нужно, - это зашифровать одну строку (расшифровка не требуется). Однако, насколько я могу судить,Встроенная структура безопасности имеет то, что мне нужно, если бы я мог просто закрыть этот пробел в формате. Если есть способ преобразовать ключ и отправить его в кодировке Base64 из веб-службы, это также работает для меня - но я могутам также нет никакого способа кодировать его в ASN.1.

1 Ответ

1 голос
/ 23 марта 2011

Итак, я использовал класс SecKeyWrapper для генерации случайного ключа, затем использовал метод -getPublicKeyBits для получения двоичного представления открытого ключа (в любом формате, который используется внутри). Предполагая, что это какая-то форма DER ASN.1, я перешел на консоль в шестнадцатеричном виде и загрузил ее в этой программы . Конечно, внутренним представлением является 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)

Вот мой код, для простоты. Он использует несколько библиотек Google для XML + base64, просто один на один; также демонстрационный код 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;
}
...