TripleDES en modo CFB, C # y Crypto ++ difieren

Aquí está mi problema: tengo un código heredado en C ++ (usando crypto ++ v5.6.1) y desarrollo uno nuevo en C # (.NET 3.5 usando System.Security.Cryptography). No puedo cambiar el código C ++, pero necesito poder descifrar los datos previamente encriptados y las aplicaciones anteriores deben poder descifrar los datos que cifraré con mi nuevo código C #.

El algoritmo utilizado es TripleDES con modo de cifrado CFB en ambos casos, pero al final, los datos cifrados no son los mismos, el número de bytes es idéntico y el primer byte, pero, aparte de eso, todos los demás bytes son diferentes.

El relleno se realiza manualmente (agregando ceros) en el código C ++. Así que puse el PaddingValue a PaddingMode.Zeros. (También intenté agregar ceros al final manualmente en el código C #, no cambió nada).

Intenté usar diferentes System.Text.Encoding pero el resultado es el mismo (de hecho, los caracteres probados son ASCII “puro” (es decir, entre 0 y 126)).

El valor de MandatoryBlockSize (), en el código C ++, es 8, así que también establezco FeedbackSize en 8. Pero si lo entiendo, escribo, de hecho es del tamaño de mi IV, ¿no es así?

El tamaño de la clave es de 24 bytes (3 claves diferentes) y el IV tiene una longitud de 8 bytes. Ambos son los mismos en los 2 códigos.

Si utilizo el modo CBC en ambos casos, los resultados son los mismos (pero, como dije, no puedo cambiar el código heredado …), el modo OFB y CTS produce excepciones (no disponible para uno e incompatible para el otro) en mi aplicación .NET, así que no puedo comparar resultados.

Intenté usar Mono, con versiones .Net 3.5 y 4.0, o usar visual, con .Net 3.5 o 4.0, y los 4 resultados encriptados son iguales pero difieren del resultado original.

Ahora realmente no sé qué probar … Preferiría no envolver Crypto ++ en un proyecto C ++ / CLI para usarlo en lugar de System.Security.Cryptography.

¿Alguien tiene un consejo o puede decir qué estoy haciendo mal?

Aquí está el código de C ++:

void *CryptData(BYTE *bDataIn, LONG lIn, LONG *lOut, byte* key, byte* iv) { byte *bIn; byte *bOut; LONG l2,lb; CFB_FIPS_Mode::Encryption encryption_DES_EDE3_CFB; encryption_DES_EDE3_CFB.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv)); lb = encryption_DES_EDE3_CFB.MandatoryBlockSize(); l2 = ((lIn + lb - 1)/lb)*lb; bIn = (byte*)malloc(l2); bOut = (byte*)malloc(l2); memset(bIn,0,l2); memset(bOut,0,l2); memcpy(bIn,bDataIn,lIn); encryption_DES_EDE3_CFB.ProcessString(bOut, bIn, l2); *lOut = l2; return bOut; } 

Aquí está el código C #:

 public FibxCrypt() { _cryptoAlgo = new TripleDESCryptoServiceProvider(); //_cryptoAlgo.GenerateKey(); _cryptoAlgo.Key = _key; //_cryptoAlgo.GenerateIV(); _cryptoAlgo.IV = _iv; _cryptoAlgo.Mode = CipherMode.CFB; _cryptoAlgo.Padding = PaddingMode.Zeros; _encoding = new UTF8Encoding(); } private MemoryStream EncryptingString(string plainText, out long encryptSize) { // Check arguments. if (plainText == null || plainText.Length <= 0) throw new ArgumentNullException("plainText"); // Create a decrytor to perform the stream transform. ICryptoTransform encryptor = _cryptoAlgo.CreateEncryptor(); // Create the streams used for encryption. //using (MemoryStream msEncrypt = new MemoryStream()) MemoryStream msEncrypt = new MemoryStream(); encryptSize = ((plainText.Length + _cryptoAlgo.FeedbackSize - 1) / _cryptoAlgo.FeedbackSize) * _cryptoAlgo.FeedbackSize; using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) { using (StreamWriter swEncrypt = new StreamWriter(csEncrypt, _encoding)) { //Write all data to the stream. swEncrypt.Write(plainText); } } // Return the encrypted memory stream. return msEncrypt; } 

EDITAR: Intenté usar el Encryptor directamente, en lugar de usar las secuencias y tengo el mismo problema.

 private MemoryStream EncryptingString(string plainText, out long encryptSize) { // Check arguments. if (plainText == null || plainText.Length <= 0) throw new ArgumentNullException("plainText"); ICryptoTransform encryptor = _cryptoAlgo.CreateEncryptor(); byte[] cipherData = encryptor.TransformFinalBlock( _encoding.GetBytes(plainText), 0, plainText.Length); // Return the encrypted memory stream. return msEncrypt; } 

El FeedBackSize que ha cambiado, se relaciona con el modo de operación de CFB ( documentación de msdn ). Por lo tanto, también debe verificar que el tamaño de los Comentarios en C ++ y C # sean los mismos.

Creo que su error podría ser difamado de tamaños de bloque entre el código C ++ y el código C #. ¿Ha intentado establecer BlockSize = 8 en la implementación de C #?

Estos no son correctos:

 CFB_FIPS_Mode::Encryption enc; enc.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv)); 

sizeof(key) y sizeof(iv) devuelve el tamaño de los punteros, no el tamaño de los parámetros de seguridad. Deberías usar esto en su lugar:

 enc.SetKeyWithIV(key, DES_EDE3::DEFAULT_KEYLENGTH, iv, DES_EDE3::BLOCKSIZE); 

Si funciona para .Net, entonces debería preferir boost el tamaño de los comentarios para bibliotecas como Mcrypt y .Net; y no reducir el tamaño de retroalimentación en Crypto ++. Esto se debe a que algunos modos pierden seguridad cuando el tamaño de realimentación no es el tamaño de bloque completo.

No sé si esto funcionará con .Net, pero es algo que debe considerar o probar:

 public FibxCrypt() { _cryptoAlgo = new TripleDESCryptoServiceProvider(); _cryptoAlgo.Key = _key; _cryptoAlgo.IV = _iv; _cryptoAlgo.Mode = CipherMode.CFB; _cryptoAlgo.Padding = PaddingMode.Zeros; // Add this: _cryptoAlgo.FeedbackSize = _cryptoAlgo.BlockSize; } 

Si no puede ajustar el tamaño de la retroalimentación en .Net, a continuación le indicamos cómo cambiar el tamaño de la retroalimentación en Crypto ++. Configura un AlgorithmParameters para mantener el parámetro de tamaño de realimentación y luego llama a SetKey con los parámetros adicionales:

 void *CryptData(BYTE *bDataIn, LONG lIn, LONG *lOut, byte* key, byte* iv) { AlgorithmParameters params = MakeParameters(Name::FeedbackSize(), 1 /*8-bits*/) (Name::IV(), ConstByteArrayParameter(iv, DES_EDE3::BLOCKSIZE)); CFB_FIPS_Mode::Encryption enc; enc.SetKey(key, 24, DES_EDE3::DEFAULT_KEYLENGTH); ... } 

No me queda claro si el modo CFB que opera en modo FIPS permite un tamaño de retroalimentación tan pequeño. Si lanza una excepción, entonces deberá usar solo CFB_Mode .

AlgorithmParameters puede parecer un poco extraño debido a la sobrecarga del operator() . Puedes leerlo en NameValuePairs en la wiki de Crypto ++. Otras páginas wiki de interés son TripleDES y CFB Mode .

—-

Otra cosa a tener en cuenta es la encoding de texto. Generalmente causa problemas de interoperabilidad en .Net y Java debido a UTF-16. UTF-8 y ASCII causan la menor cantidad de problemas. Deberías estar bien ya que encoding = new UTF8Encoding() .

Pero si las cosas aún no funcionan para usted, entonces usted es un mensaje de byte que no está codificado o interpretado. Por ejemplo, use esto tanto en .Net como en Crypto ++:

 byte msg[4] = { 0x01, 0x02, 0x03, 0x04 }; 

Los cuatro bytes no se interpretan, por lo que los pasos laterales de encoding de problemas.