2011-11-27 7 views
13

Mi aplicación cifra y descifra (o debería) un NSString (el texto que se va a cifrar/descifrar) con otro NSString (la palabra clave) utilizando Cifrado de 256 bits. Cuando ejecuto mi proyecto y ejecuto el método de cifrado, nada se cifra, el campo de texto simplemente se borra. Aquí está el código que tengo:Cifrado NSString AES256 en iOS

-(void)EncryptText { 
    //Declare Keyword and Text 
    NSString *plainText = DataBox.text; 
    NSString *keyword = Keyword.text; 

    //Convert NSString to NSData 
    NSData *plainData = [plainText dataUsingEncoding:NSUTF8StringEncoding]; 

    //Encrypt the Data 
    NSData *encryptedData = [plainData AESEncryptWithPassphrase:keyword]; 

    //Convert the NSData back to NSString 
    NSString* cypherText = [[NSString alloc] initWithData:encryptedData encoding:NSUTF8StringEncoding]; 

    //Place the encrypted sting inside the Data Box 
    NSLog(@"Cipher Text: %@", cypherText); 
} 

Los archivos de cabecera se pueden descargar haciendo clic en este enlace: ZIP File containing AES Implementation

Me han dicho que tengo que usar base 64 codificación de mi cadena para conseguir cualquier resultado . Si esto es cierto, ¿cómo lo hago?

También me han dicho que el cifrado cambió en iOS 5, y mi aplicación es SOLO para iOS 5+. Si esto es cierto, entonces ¿qué tengo que hacer para que este cifrado funcione en iOS 5 o dónde puedo encontrar otra implementación AES de 256 bits que funcione en NSString?

¿Por qué este código no produce un resultado?

Respuesta

11

EDIT: Los enlaces a continuación se refieren a una implementación más. La última versión se llama RNCryptor.

Su código no utiliza la implementación AES incorporada de iOS. Tiene su propia implementación personalizada. AESEncryptWithPassphrase: también genera incorrectamente la clave, descartando la mayor parte de la entropía en la frase de contraseña.

En iOS, debe utilizar las funciones CCCrypt*() para AES. También debe asegurarse de comprender lo que está sucediendo en sus rutinas de cifrado y descifrado. Es muy fácil escribir código de cifrado que se ve correcto (en el sentido de que no se puede leer el resultado por inspección), pero es extremadamente inseguro.

Consulte Properly encrypting with AES with CommonCrypto para obtener una explicación de los problemas con la implementación anterior y cómo usar AES correctamente en iOS. Tenga en cuenta que iOS 5 ahora tiene CCKeyDerivationPBKDF disponible.

No es necesario que Base-64 codifique su cadena antes del cifrado. La codificación Base-64 se usa en casos donde necesita convertir datos binarios en un formulario que puede enviarse fácilmente por correo electrónico u otros lugares donde los caracteres de control serían un problema. Convierte datos binarios de 8 bits en datos ASCII de 7 bits. Eso no es necesario ni útil aquí.


EDITAR: Es muy importante que lea atentamente la explicación de cómo utilizar este código. Es peligroso simplemente cortar y pegar el código de seguridad y esperar que funcione. Dicho esto, la fuente completa para RNCryptManager está disponible como parte del código de ejemplo del Capítulo 11 para iOS 5 Programming Pushing the Limits y puede ser útil [EDITAR: Este es código antiguo; Recomiendo RNCryptor ahora, vinculado en la parte superior de la respuesta]. El libro (que debería estar disponible la próxima semana a pesar de lo que dice el sitio) incluye una discusión mucho más larga sobre cómo usar este código, que incluye cómo mejorar el rendimiento y tratar con conjuntos de datos muy grandes.

+0

Gracias Rob! ¡Eso es muy útil! –

+0

¿Dónde iría el código que se muestra en: http://robnapier.net/blog/aes-commoncrypto-564? No entraría en su propia clase porque no hay nada que entrar en un encabezado y una implementación, ¿entraría en el mismo archivo .m en el que está mi método? –

+0

Normalmente lo pongo en una clase llamada 'RNCryptManager', pero puede colocarlo en cualquier lugar. El código también podría convertirse trivialmente en funciones en lugar de métodos de clase. –

6

NSData con la categoría muy bien para el cifrado AES, no revisé el archivo zip, pero esto debería funcionar para usted;

#import <CommonCrypto/CommonCryptor.h> 
@implementation NSData (AESAdditions) 
- (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 

Use funciones de envoltura como;

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

Tenga en cuenta que esta implementación es altamente insegura ya que descarta la mayor parte del espacio de claves, no tiene IV, y no tiene sal o estiramiento de teclas. Ver http://robnapier.net/blog/aes-commoncrypto-564 para una discusión de por qué evitar esta pieza de código comúnmente copiada. –

+0

@tylerdurden Debe verificar la longitud de la clave, porque "getCString: maxlength: encoding" no hará nada si key.length> (kCCKeySizeAES256 + 1) y la cryptor usará 32 '\ 0' como su clave. Es peligroso. – MasterBeta