Конвертировать формат XML Dsig в ​​открытый ключ DER ASN.1

Я работаю над приложением для 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 ответ

Решение

Итак, я использовал 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;
}
Другие вопросы по тегам