Question

Je travaille sur une application iPhone qui récupère une clé publique RSA à partir d'un service Web ASP.NET sous la forme:

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

Je dois ensuite convertir cette réponse en un NSData * du format approprié (à partir d'un certain googling intense, probablement le format binaire 'ASN.1 DER'. J'ai un code en place pour convertir les deux parties de leurs représentations Base64 en les valeurs binaires d'origine, mais je ne peux pas pour la vie de moi trouver un moyen raisonnable de créer la clé binaire en une seule pièce.

Le code en attente de la clé est la méthode -addPeerPublicKey:(NSString *) keyBits:(NSData *) de la classe SecKeyWrapper du projet d'exemple CryptoExercise d'Apple (Code ici ).

Je serais plus qu'heureux de l'implémenter d'une autre manière - tout ce dont j'ai besoin est de chiffrer une seule chaîne (aucun déchiffrement requis). Pour autant que je sache, cependant, le cadre de sécurité intégré a ce dont j'ai besoin, si je pouvais simplement combler cet écart de format. S'il existe un moyen de convertir la clé et de l'envoyer encodée en Base64 à partir du service Web, cela fonctionne également pour moi - mais je n'ai pas trouvé de moyen de l'encoder ASN.1 là non plus.

Était-ce utile?

La solution

J'ai donc utilisé la classe SecKeyWrapper pour générer une clé aléatoire, puis j'ai utilisé la méthode -getPublicKeyBits pour obtenir la représentation binaire de la clé publique (quel que soit le format utilisé en interne). En supposant qu'il s'agit d'une forme de DER ASN.1, je l'ai NSLoged dans la console sous forme hexadécimale et l'ai chargé dans ce programme . Effectivement, la représentation interne est DER ASN.1, mais c'est une version très simplifiée de ce que je trouve normalement pour les représentations de clé RSA:

![SEQUENCE { INTEGER, INTEGER }][2]

Ne devrait pas être trop difficile à construire à la volée à partir d'un représentant binaire. du module et de l'exposant, puisque l'encodage DER est juste

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)

Voici mon code, pour plus de simplicité. Il utilise quelques bibliothèques Google pour XML + base64, juste en tête; également le code de démonstration d'Apple SecKeyWrapper. Voir mon autre question pour une note sur la façon de faire fonctionner ce travail. Notez également qu'il n'est pas compatible ARC; ceci est laissé comme exercice pour le lecteur (j'ai écrit il y a des années, maintenant).

#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;
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top