2012-08-14 23 views
13

Lo primero es lo primero. Hace algún tiempo necesité un simple cifrado AES en Android para encriptar una contraseña y enviarla como parámetro para un servicio web .net donde se descifraba la contraseña.Encriptación AES en iOS y Android, y descifrado en C# .NET

La siguiente es mi cifrado Android:

private static String Encrypt(String text, String key) 
     throws Exception { 
     Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 
     byte[] keyBytes= new byte[16]; 
     byte[] b= key.getBytes("UTF-8"); 
     int len= b.length; 
     if (len > keyBytes.length) len = keyBytes.length; 
     System.arraycopy(b, 0, keyBytes, 0, len); 
     SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES"); 
     IvParameterSpec ivSpec = new IvParameterSpec(keyBytes); 
     cipher.init(Cipher.ENCRYPT_MODE,keySpec,ivSpec); 

     byte[] results = cipher.doFinal(text.getBytes("UTF-8")); 
     String result = Base64.encodeBytes(results); 
     return result; 
     } 

Y entonces descifrado en C# con:

 public static string Decrypt(string textToDecrypt, string key) 
    { 
     System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding(); 

     RijndaelManaged rijndaelCipher = new RijndaelManaged(); 
     rijndaelCipher.Mode = CipherMode.CBC; 
     rijndaelCipher.Padding = PaddingMode.PKCS7; 

     rijndaelCipher.KeySize = 0x80; 
     rijndaelCipher.BlockSize = 0x80; 

     string decodedUrl = HttpUtility.UrlDecode(textToDecrypt); 
     byte[] encryptedData = Convert.FromBase64String(decodedUrl); 
     byte[] pwdBytes = Encoding.UTF8.GetBytes(key); 
     byte[] keyBytes = new byte[0x10]; 
     int len = pwdBytes.Length; 
     if (len > keyBytes.Length) 
     { 
      len = keyBytes.Length; 
     } 
     Array.Copy(pwdBytes, keyBytes, len); 
     rijndaelCipher.Key = keyBytes; 
     rijndaelCipher.IV = keyBytes; 
     byte[] plainText = rijndaelCipher.CreateDecryptor().TransformFinalBlock(encryptedData, 0, encryptedData.Length); 
     return encoding.GetString(plainText); 
    } 

Esto funcionó como un encanto, pero los problemas llegaron cuando traté de hacer lo lo mismo en iOS. Soy bastante nuevo desarrollo de aplicaciones para el iPhone/iPad, por lo ofcause busqué en Google, y casi todas las muestras de código proporcionado fue el siguiente:

- (NSData *)AESEncryptionWithKey:(NSString *)key { 
char keyPtr[kCCKeySizeAES128]; // 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]; 

size_t bufferSize = dataLength + kCCBlockSizeAES128; 
void *buffer = malloc(bufferSize); 

size_t numBytesEncrypted = 0; 

CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, 
             keyPtr, kCCKeySizeAES128, 
             NULL /* initialization vector (optional) */, 
             [self bytes], [self length], /* 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; 

}

Tal vez era un poco demasiado optimista, cuando Tenía la esperanza de una transición sin problemas aquí, porque cuando el Android me está tirando algo como:

"EgQVKvCLS4VKLoR0xEGexA=="

entonces el iOS me da:

"yP42c9gajUra7n0zSEuVJQ==" 

Afortunadamente es solo algo que olvidé, o algunos de los ajustes son incorrectos?

[ACTUALIZACIÓN] Los resultados ahora se muestran después de la codificación base64.

+1

La versión de Android es una cadena base64 con codificación URL que es igual a '" YHH + gTxyIxvAx1cPFLcP0IEW2HcVHQVi9X11656CFsk = "' '(60 71 fe 81 3c 72 23 1b c0 c7 57 0f 14 b7 0f d0 81 16 d8 77 15 1d 05 62 f5 7d 75 eb 9e 82 16 c9) '. – Joe

+0

Woops, lo siento, me olvidé de mencionar eso. Estoy codificando el resultado de la versión iOS también, solo en otro método, pero los resultados son diferentes antes de la codificación. – Morten

+0

Se actualizó la pregunta para mostrar los resultados después de la codificación base64. Se usa la misma contraseña y la misma clave. – Morten

Respuesta

5

La primera nota es que tiene importantes problemas de seguridad en este código. Estás tomando una contraseña de cadena y solo la dejas caer en una clave. Si esa cadena es humanamente tipable, entonces has restringido drásticamente tu espacio de claves (convirtiendo a AES-128 en algo más parecido a AES-40 o AES-50, tal vez incluso peor). Necesita sal y estirar la clave usando PBKDF2. Vea Properly encrypting with AES with CommonCrypto para una discusión más completa.

También tiene un problema de seguridad importante porque está usando su llave como su IV (vea más abajo, esta es la causa de su síntoma). Esta no es la forma correcta de seleccionar un IV y hace que su texto cifrado sea predecible. El texto plano idéntico encriptado con la misma clave dará el mismo resultado. Esto es similar a no tener IV en absoluto. La IV debe ser aleatoria. Vea el enlace de arriba para más discusión.

Ahora a su síntoma real. El problema es que estás usando la clave como IV en Java y C#, pero estás usando 0 (NULL) como IV en iOS (el IV no es opcional, solo estás pasando 0). Debe usar el mismo IV en todos los casos.

+0

Sé que hay algunos problemas de seguridad, pero es solo una solución temporal. Esta es solo una solución rápida, por lo que no transmitiremos texto legible hasta que finalice nuestra solución final. Realmente no puedo probar nada en este momento, porque es un problema en el trabajo pero, si lo entiendo correctamente, debería corregirse si cambiara lo siguiente: En la descifración C#: rijndaelCipher.IV = X; En el cifrado de Java: IvParameterSpec ivSpec = new IvParameterSpec (X); ... y cambió el parámetro NULL a X, donde X ofcause tiene el mismo valor? Por cierto, muchas gracias por su respuesta ... – Morten

+0

Actualmente, "X" en el código anterior es una copia de la clave en todas partes, excepto en iOS. Puede hacer que sea la clave en iOS, o hacer que sea 0 de C# y Java. No lo convertiría en un valor estático (que no sea 0). –

+0

Bien, muchas gracias por su ayuda. Lo intentaré mañana, y marque tu respuesta como "aceptada" también ... – Morten

Cuestiones relacionadas