Interoperabilidad AES entre .Net y iPhone?

Necesito cifrar una cadena en el iPhone y enviarla a un servicio web .Net para su descifrado. Puedo cifrar / descifrar en el iPhone y con .Net, pero las cadenas cifradas del iPhone no pueden ser descifradas por .Net. El error que recibo es “El relleno no es válido y no se puede eliminar”.

El código .Net es de: http://blog.realcoderscoding.com/index.php/2008/07/dot-net-encryption-simple-aes-wrapper/

El código de iPhone usa el código de ejemplo de: http://nootech.wordpress.com/2009/01/17/symmetric-encryption-with-the-iphone-sdk/

AFAIK la configuración de mi llave es la misma:

result.BlockSize = 128; // iPhone: kCCBlockSizeAES128 result.KeySize = 128; // kCCBlockSizeAES128 result.Mode = CipherMode.CBC; result.Padding = PaddingMode.PKCS7; // kCCOptionPKCS7Padding 

Probé diferentes formas de generar texto cifrado. hola / hola es:

e0PnmbTg / 3cT3W + 92CDw1Q == en .Net

yrKe5Z7p7MNqx9 + CbBvNqQ == en iPhone

y “openssl enc -aes-128-cbc -nosalt -a -in hello.txt -pass pase: hello” genera: QA + Ul + r6Zmr7yHipMcHSbQ ==

Actualización: he publicado el código de trabajo para esto aquí .

Al menos, estás usando diferentes vectores de inicialización (IV).

  • El código .Net usa la clave para IV.

     private static AesCryptoServiceProvider GetProvider(byte[] key) { //Set up the encryption objects AesCryptoServiceProvider result = new AesCryptoServiceProvider(); byte[] RealKey = Encryptor.GetKey(key, result); result.Key = RealKey; result.IV = RealKey; return result; } 

    y

     private static byte[] GetKey(byte[] suggestedKey, AesCryptoServiceProvider p) { byte[] kRaw = suggestedKey; List kList = new List(); for (int i = 0; i < p.LegalKeySizes[0].MinSize; i += 8 ) { kList.Add(kRaw[i % kRaw.Length]); } byte[] k = kList.ToArray(); return k; } 

    que probablemente debería ser: kList.Add(kRaw[(i / 8) % kRaw.Length]); . De lo contrario, una clave cuya longitud% 8 == 0 usará la misma letra repetidamente, doh!

    Por lo tanto, la IV (y la clave) utilizada por .Net es: hleolhleolhleolh . Esto no es parte de la API, sino más bien debido al código de envoltura que apuntaste (que tiene un error serio ...).

  • El código de iPhone usa 0 para IV.

     // Initialization vector; dummy in this case 0's. uint8_t iv[kChosenCipherBlockSize]; memset((void *) iv, 0x0, (size_t) sizeof(iv)); 
  • openssl por defecto prepede una sal generada aleatoriamente (¡por eso la salida es más larga!).

La salida de openssl es más segura ya que está anteponiendo un vector de inicialización aleatorio. Parece que los primeros pocos bytes de la cadena decodificada en base64 son "Salted__". También puede pedirle a openssl que no use una sal (-nosalt) y / o proporcione un IV (-iv).

Básicamente, openssl, .Net y el iPhone usan el mismo cifrado, solo debe tener cuidado al inicializar las API con la clave de cifrado y el vector de inicialización.

¿Estás seguro de que estás usando la misma clave AES en tus pruebas? El ejemplo de OpenSSL en su publicación utiliza una contraseña de la cual OpenSSL deriva una clave y una IV de (y probablemente también usa una sal).

Genere una clave aleatoria de 128 bits y especifique esta clave en formato hexadecimal para OpenSSL con:

 openssl enc -aes-128-cbc -a -in hello.txt -K KEY_IN_HEX -iv 0 

No debe usar IV = 0 en ningún sistema seguro, pero para probar la interoperabilidad está bien.

Cª#

 void test(){ string ctB64 = encrypt("hola"); Console.WriteLine(ctB64); // the same as in objective-c } string encrypt(string input) { try { // Create a new instance of the AesManaged class. This generates a new key and initialization vector (IV). AesManaged myAes = new AesManaged(); // Override the cipher mode, key and IV myAes.Mode = CipherMode.CBC; myAes.IV = new byte[16] { 0x10, 0x16, 0x1F, 0xAD, 0x10, 0x10, 0xAA, 0x22, 0x12, 0x51, 0xF1, 0x1E, 0x15, 0x11, 0x1B, 0x10 }; // must be the same as in objective-c myAes.Key = Encoding.UTF8.GetBytes(“0123456789123456”); //CipherKey; // Byte array representing the key myAes.Padding = PaddingMode.PKCS7; // Create a encryption object to perform the stream transform. ICryptoTransform encryptor = myAes.CreateEncryptor(); // perform the encryption as required... MemoryStream ms = new MemoryStream(); CryptoStream ct = new CryptoStream(ms, encryptor, CryptoStreamMode.Write); byte[] binput = Encoding.UTF8.GetBytes(input); ct.Write(binput, 0, binput.Length); ct.Close(); byte [] result = ms.ToArray(); return Convert.ToBase64String(result); } catch (Exception ex) { // TODO: Log the error Console.WriteLine(ex); throw ex; } } 

· En objective-c, agregue la biblioteca CocoaSecurity de https://github.com/kelp404/CocoaSecurity

 #import "CocoaSecurity.h" #import "Base64.h" … - (void) test{ unsigned char bytes[] = { 0x10, 0x16, 0x1F, 0xAD, 0x10, 0x10, 0xAA, 0x22, 0x12, 0x51, 0xF1, 0x1E, 0x15, 0x11, 0x1B, 0x10 }; // must be the same as in c# NSData *iv = [NSData dataWithBytesNoCopy:bytes length:16 freeWhenDone:YES]; NSData* key = [@"0123456789123456" dataUsingEncoding:NSUTF8StringEncoding]; CocoaSecurityResult *result = [CocoaSecurity aesEncrypt:@"hola" key:key iv:iv]; NSLog(@"%@", result.base64); // the same as in c# NSData *data = [NSData dataWithBase64EncodedString:result.base64]; CocoaSecurityResult *result2 = [CocoaSecurity aesDecryptWithData:data key:key iv:iv]; NSLog(@"%@", result2.utf8String); // show "hola" }