Question

Quelqu'un peut-il m'indiquer la bonne direction pour pouvoir chiffrer une chaîne en renvoyant une autre chaîne avec les données chiffrées? (J'ai essayé avec le chiffrement AES256.) Je souhaite écrire une méthode prenant deux instances de NSString, l'une étant le message à chiffrer et l'autre, un "code d'accès" permettant de le chiffrer. Je suppose que je devrais générer la clé de cryptage avec le code secret, de manière à pouvoir être inversée si le code secret est fourni avec les données cryptées. La méthode devrait ensuite renvoyer une chaîne NSString créée à partir des données chiffrées.

J'ai essayé la technique détaillée dans le premier commentaire sur ce post , mais je n’ai pas eu de chance jusqu’à présent. Le CryptoExercise d'Apple a certainement quelque chose à offrir, mais je ne peux pas le comprendre. .. J'ai vu beaucoup de références à CCCrypt , mais dans tous les cas je l’ai utilisé.

Je devrais également pouvoir déchiffrer une chaîne chiffrée, mais j'espère que c'est aussi simple que kCCEncrypt / kCCDecrypt.

Était-ce utile?

La solution

Puisque vous n'avez posté aucun code, il est difficile de savoir exactement quels problèmes vous rencontrez. Cependant, la publication de blog vers laquelle vous créez un lien semble fonctionner assez correctement ... mis à part la virgule supplémentaire dans chaque appel de CCCrypt () qui a entraîné des erreurs de compilation.

Un commentaire ultérieur sur ce message inclut ce code adapté , qui fonctionne pour moi et semble un peu plus simple. Si vous incluez leur code pour la catégorie NSData, vous pouvez écrire quelque chose comme ceci: (Remarque: les appels printf () servent uniquement à montrer l’état des données à divers points dans une application réelle, il ne serait pas logique d'imprimer de telles valeurs.)

int main (int argc, const char * argv[]) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    NSString *key = @"my password";
    NSString *secret = @"text to encrypt";

    NSData *plain = [secret dataUsingEncoding:NSUTF8StringEncoding];
    NSData *cipher = [plain AES256EncryptWithKey:key];
    printf("%s\n", [[cipher description] UTF8String]);

    plain = [cipher AES256DecryptWithKey:key];
    printf("%s\n", [[plain description] UTF8String]);
    printf("%s\n", [[[NSString alloc] initWithData:plain encoding:NSUTF8StringEncoding] UTF8String]);

    [pool drain];
    return 0;
}

Etant donné ce code et le fait que les données chiffrées ne se traduisent pas toujours dans une chaîne NSString, il peut être plus pratique d'écrire deux méthodes qui englobent la fonctionnalité dont vous avez besoin, en avant et en arrière ...

- (NSData*) encryptString:(NSString*)plaintext withKey:(NSString*)key {
    return [[plaintext dataUsingEncoding:NSUTF8StringEncoding] AES256EncryptWithKey:key];
}

- (NSString*) decryptData:(NSData*)ciphertext withKey:(NSString*)key {
    return [[[NSString alloc] initWithData:[ciphertext AES256DecryptWithKey:key]
                                  encoding:NSUTF8StringEncoding] autorelease];
}

Cela fonctionne vraiment sur Snow Leopard et @Boz indique que CommonCrypto fait partie du système d'exploitation principal de l'iPhone. Les codes 10.4 et 10.5 ont tous deux / usr / include / CommonCrypto , bien que 10.5 ait une page de manuel pour CCCryptor.3cc et 10.4 pas, donc YMMV.

MODIFIER: voir cette question complémentaire sur l'utilisation du codage Base64 pour la représentation d'octets de données cryptés. sous forme de chaîne (si nécessaire) à l'aide de conversions sûres et sans perte.

Autres conseils

J'ai rassemblé une série de catégories pour NSData et NSString qui utilisent les solutions trouvées sur Le blog de Jeff LaMarche et Quelques astuces de Quinn Taylor sur Stack Overflow.

Il utilise des catégories pour étendre NSData afin de fournir le cryptage AES256 et offre également une extension de NSString aux données cryptées encodées en BASE64 en toute sécurité.

Voici un exemple illustrant l'utilisation du chiffrement de chaînes:

NSString *plainString = @"This string will be encrypted";
NSString *key = @"YourEncryptionKey"; // should be provided by a user

NSLog( @"Original String: %@", plainString );

NSString *encryptedString = [plainString AES256EncryptWithKey:key];
NSLog( @"Encrypted String: %@", encryptedString );

NSLog( @"Decrypted String: %@", [encryptedString AES256DecryptWithKey:key] );

Obtenez le code source complet ici:

  

https://gist.github.com/838614

Merci pour tous les conseils utiles!

- Michael

@owlstead, en ce qui concerne votre demande "une variante cryptographiquement sécurisée de l'une des réponses données". veuillez consulter RNCryptor . Il a été conçu pour faire exactement ce que vous demandez (et a été conçu en réponse aux problèmes rencontrés avec le code répertorié ici).

RNCryptor utilise PBKDF2 avec du sel, fournit un IV aléatoire et associe HMAC (également généré à partir de PBKDF2 avec son propre sel. Il prend en charge les opérations synchrones et asynchrones.

J'ai un peu attendu @QuinnTaylor pour mettre à jour sa réponse, mais comme il ne l'a pas fait, voici la réponse un peu plus clairement et d'une manière qui se chargera sur XCode7 (et peut-être plus). Je l'ai utilisé dans une application Cocoa, mais cela fonctionnera probablement aussi avec une application iOS. N'a pas d'erreur ARC.

Coller avant toute section @implementation dans votre fichier AppDelegate.m ou AppDelegate.mm.

#import <CommonCrypto/CommonCryptor.h>

@implementation NSData (AES256)

- (NSData *)AES256EncryptWithKey:(NSString *)key {
    // 'key' should be 32 bytes for AES256, will be null-padded otherwise
    char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)
    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)

    // fetch key data
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];

    NSUInteger dataLength = [self length];

    //See the doc: For block ciphers, the output size will always be less than or 
    //equal to the input size plus the size of one block.
    //That's why we need to add the size of one block here
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);

    size_t numBytesEncrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
                                     keyPtr, kCCKeySizeAES256,
                                     NULL /* initialization vector (optional) */,
                                     [self bytes], dataLength, /* input */
                                     buffer, bufferSize, /* output */
                                     &numBytesEncrypted);
    if (cryptStatus == kCCSuccess) {
        //the returned NSData takes ownership of the buffer and will free it on deallocation
        return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
    }

    free(buffer); //free the buffer;
    return nil;
}

- (NSData *)AES256DecryptWithKey:(NSString *)key {
    // 'key' should be 32 bytes for AES256, will be null-padded otherwise
    char keyPtr[kCCKeySizeAES256+1]; // room for terminator (unused)
    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)

    // fetch key data
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];

    NSUInteger dataLength = [self length];

    //See the doc: For block ciphers, the output size will always be less than or 
    //equal to the input size plus the size of one block.
    //That's why we need to add the size of one block here
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    void *buffer = malloc(bufferSize);

    size_t numBytesDecrypted = 0;
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
                                     keyPtr, kCCKeySizeAES256,
                                     NULL /* initialization vector (optional) */,
                                     [self bytes], dataLength, /* input */
                                     buffer, bufferSize, /* output */
                                     &numBytesDecrypted);

    if (cryptStatus == kCCSuccess) {
        //the returned NSData takes ownership of the buffer and will free it on deallocation
        return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
    }

    free(buffer); //free the buffer;
    return nil;
}

@end

Collez ces deux fonctions dans la classe @implementation souhaitée. Dans mon cas, j'ai choisi @implementation AppDelegate dans mon fichier AppDelegate.mm ou AppDelegate.m.

- (NSString *) encryptString:(NSString*)plaintext withKey:(NSString*)key {
    NSData *data = [[plaintext dataUsingEncoding:NSUTF8StringEncoding] AES256EncryptWithKey:key];
    return [data base64EncodedStringWithOptions:kNilOptions];
}

- (NSString *) decryptString:(NSString *)ciphertext withKey:(NSString*)key {
    NSData *data = [[NSData alloc] initWithBase64EncodedString:ciphertext options:kNilOptions];
    return [[NSString alloc] initWithData:[data AES256DecryptWithKey:key] encoding:NSUTF8StringEncoding];
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top