Pregunta

¿Alguien puede señalarme en la dirección correcta para poder cifrar una cadena y devolver otra cadena con los datos cifrados? (He estado intentando con el cifrado AES256). Quiero escribir un método que tome dos instancias de NSString, una es el mensaje para cifrar y la otra es un 'código de acceso' para cifrarlo; sospecho que tendría que generar la clave de cifrado con el código de acceso, de manera que se puede invertir si el código de acceso se suministra con los datos cifrados. El método debería devolver un NSString creado a partir de los datos cifrados.

He probado la técnica detallada en el primer comentario sobre esta publicación , pero hasta ahora no he tenido suerte. El CryptoExercise de Apple ciertamente tiene algo, pero no puedo entenderlo. .. He visto muchas referencias a CCCrypt , pero ha fallado en todos los casos que lo he usado.

También tendría que poder descifrar una cadena cifrada, pero espero que sea tan simple como kCCEncrypt / kCCDecrypt.

¿Fue útil?

Solución

Dado que no ha publicado ningún código, es difícil saber exactamente qué problemas está encontrando. Sin embargo, la publicación de blog a la que te vinculas parece funcionar bastante decentemente ... aparte de la coma adicional en cada llamada a CCCrypt () que causó errores de compilación.

Un comentario posterior sobre esa publicación incluye este código adaptado , que funciona para mí, y parece un poco más sencillo. Si incluye su código para la categoría NSData, puede escribir algo como esto: (Nota: las llamadas a printf () son solo para demostrar el estado de los datos en varios puntos & # 8212; en una aplicación real, no tendría sentido imprimir tales valores.)

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;
}

Dado este código, y el hecho de que los datos cifrados no siempre se traducirán bien en una NSString, puede ser más conveniente escribir dos métodos que envuelvan la funcionalidad que necesita, hacia adelante y hacia atrás ...

- (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];
}

Esto definitivamente funciona en Snow Leopard, y @Boz informa que CommonCrypto es parte del Core OS en el iPhone. Tanto 10.4 como 10.5 tienen / usr / include / CommonCrypto , aunque 10.5 tiene una página de manual para CCCryptor.3cc y 10.4 no, así que YMMV.


EDITAR: Consulte esta pregunta de seguimiento sobre el uso de la codificación Base64 para representar bytes de datos cifrados como una cadena (si lo desea) utilizando conversiones seguras y sin pérdidas.

Otros consejos

He reunido una colección de categorías para NSData y NSString que utiliza soluciones que se encuentran en blog de Jeff LaMarche y algunas sugerencias de Quinn Taylor aquí en Stack Overflow.

Utiliza las categorías para extender NSData para proporcionar el cifrado AES256 y también ofrece una extensión de NSString para codificar los datos cifrados con BASE64 de forma segura a las cadenas.

Aquí hay un ejemplo para mostrar el uso para cifrar cadenas:

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] );

Obtenga el código fuente completo aquí:

  

https://gist.github.com/838614

¡Gracias por todos los consejos útiles!

- Michael

@owlstead, con respecto a su solicitud de " una variante criptográficamente segura de una de las respuestas dadas " Consulte RNCryptor . Fue diseñado para hacer exactamente lo que está solicitando (y fue creado en respuesta a los problemas con el código enumerado aquí).

RNCryptor usa PBKDF2 con sal, proporciona un IV al azar y adjunta HMAC (también generado desde PBKDF2 con su propia sal. Admite operación sincrónica y asíncrona.

Esperé un poco a @QuinnTaylor para actualizar su respuesta, pero como no lo hizo, aquí está la respuesta con más claridad y de una manera que se cargará en XCode7 (y quizás más). Utilicé esto en una aplicación de Cocoa, pero es probable que también funcione bien con una aplicación de iOS. No tiene errores ARC.

Pegue antes de cualquier sección @implementation en su archivo AppDelegate.m o 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

Pegue estas dos funciones en la clase @implementation que desee. En mi caso, elegí @implementation AppDelegate en mi archivo AppDelegate.mm o 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];
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top