2009-02-11 15 views
21

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".Interoperabilidad AES entre .Net y iPhone?

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

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

yo sepa mi configuración clave son los mismos:

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

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

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

yrKe5Z7p7MNqx9 + CbBvNqQ == en iPhone

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

Actualización: I've posted the working code for this here.

+0

también probé openSSL y no funcionó bien: openssl enc -d -aes -128-cbc -a -in crypt.txt -pass pase: hola –

+0

Si pasa el argumento -nosalt a openssl, obtendrá una codificación base64 de tamaño similar. Parece que .Net y iPhone no están usando un Vector de Inicialización explícito (salt). Pero incluso entonces, openssl no puede decodificar tampoco. ¿Supongo que cada biblioteca tiene su propia sal predeterminada? – johnny

+0

hey boss, sé que esta es una vieja pregunta, pero estoy teniendo problemas para tratar de implementar el código que cargó, ya que creo que tengo una forma diferente de implementar el cifrado de aes, utilizo un IV con una longitud de 16. Como soy nuevo con objetivos, no estoy muy seguro de dónde se está estableciendo esa duración. – gdubs

Respuesta

16

Como mínimo, está utilizando diferentes vectores de inicialización (IV).

  • El código .Net utiliza 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 antepone una sal generado de forma aleatoria (por lo que la salida es más larga!).

La salida de openssl es más segura ya que antecede 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 utilizan el mismo cifrado, solo debe tener cuidado al inicializar las API con la clave de cifrado y el vector de inicialización.

+0

Gracias! Una vez que cambié .Net para usar la clave correcta y 0 para el IV, la salida es la misma. ¿Qué debería ser la IV? ¿Está bien 0? ¿Sería más seguro si utilizo algo más? –

+0

IV = 0 solo está bien si usa cada tecla solo una vez. De lo contrario, debe usar un IV variable (un contador, un nonce o un IV completamente aleatorio). Uno de los riesgos con el uso de IV estático es que el mismo texto claro generará el mismo texto encriptado cada vez, lo que se abre para muchos ataques. –

+0

Normalmente usará un algoritmo hash seguro para derivar la clave y el IV de la contraseña y una sal al azar. Por ejemplo, vea RFC 2898, que creo que usa HMACSHA1. – Cheeso

2

¿Estás seguro de que estás utilizando 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).

generar un azar clave de 128 bits y especificar esta clave en formato hexadecimal para OpenSSL con:

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

No use IV = 0 en cualquier sistema seguro, pero para las pruebas de interoperabilidad que está bien.

+0

esto funciona para decodificar la muestra de iPhone usando openssl. clave = 68656c6c6f (hello). – johnny

+0

Usar "hello" como clave da solo 40 bits, por lo que las diferentes implementaciones de AES utilizarán algún método para aumentar esto a 128 bits. Probablemente no use el mismo método para esto ... Trate de especificar una clave completa de 128 bits (16 caracteres). –

+0

Finalmente. Trabajado como un encanto. Muchas gracias. – reinaldoluckman

2

en 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(“”); 
       //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, Agregar 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 = [@"" 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" 

} 
Cuestiones relacionadas