TripleDES en mode CFB, C # et Crypto ++ diffèrent

Voici mon problème: j’ai un code hérité en C ++ (en utilisant crypto ++ v5.6.1) et j’en développe un nouveau en C # (.NET 3.5 en utilisant System.Security.Cryptography). Je ne peux pas changer le code C ++, mais je dois pouvoir déchiffrer les données précédemment chiffrées et les applications précédentes doivent pouvoir déchiffrer les données que je vais chiffrer avec mon nouveau code C #.

L’algorithme utilisé est TripleDES avec le mode de chiffrement CFB dans les deux cas, mais au final, les données chiffrées ne sont pas identiques, le nombre d’octets est identique ainsi que celui du premier octet, mais mis à part, tous les autres octets sont différents.

Le remplissage est fait manuellement (ajout de zéros) dans le code C ++. J’ai donc défini PaddingValue sur PaddingMode.Zeros. (J’ai aussi essayé d’append des zéros à la fin manuellement dans le code C #, cela n’a rien changé).

J’ai essayé d’utiliser différents System.Text.Encoding mais le résultat est le même (en fait, les caractères testés sont en ASCII “pur” (c’est-à-dire: entre 0 et 126)).

La valeur de MandatoryBlockSize (), dans le code C ++, est 8, je règle donc FeedbackSize sur 8 également. Mais si je comprends bien, c’est en fait la taille de mon IV, n’est-ce pas?

La taille de la clé est de 24 octets (3 clés différentes) et le IV de 8 octets. Ils sont les mêmes dans les 2 codes.

Si j’utilise plutôt le mode CBC que dans les deux cas, les résultats sont les mêmes (mais, comme je l’ai dit, je ne peux pas modifier le code hérité …), le mode OFB & CTS émet des exceptions (non disponibles pour l’un et incompatibles pour l’autre). sur mon application .NET, donc je ne peux pas comparer les résultats.

J’ai essayé d’utiliser Mono, avec les versions 3.5 et 4.0 de Net, ou visuel, avec .Net 3.5 ou 4.0, et les 4 résultats chiffrés sont identiques, mais ils diffèrent du résultat d’origine.

Maintenant, je ne sais vraiment pas quoi tester … Je préférerais ne pas envelopper Crypto ++ dans un projet C ++ / CLI pour l’utiliser au lieu de System.Security.Cryptography.

Est-ce que quelqu’un a un conseil ou peut dire ce que je fais mal?

Voici le code 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.ProcessSsortingng(bOut, bIn, l2); *lOut = l2; return bOut; } 

Voici le code 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 EncryptingSsortingng(ssortingng 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; } 

EDIT: J’ai essayé d’utiliser Encryptor directement, au lieu d’utiliser les stream et j’ai le même problème.

 private MemoryStream EncryptingSsortingng(ssortingng 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; } 

Le FeedBackSize que vous avez modifié est lié au mode de fonctionnement de CFB ( documentation msdn ). Par conséquent, vous devez également vérifier que la taille des commentaires en C ++ et en C # est identique.

Je crois que votre bug pourrait être maligne BlockSizes entre le code C ++ et le code C #. Avez-vous essayé de définir BlockSize = 8 dans l’implémentation C #?

Ce ne sont pas corrects:

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

sizeof(key) et sizeof(iv) renvoie la taille des pointeurs, pas la taille des parameters de sécurité. Vous devriez utiliser ceci à la place:

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

Si cela fonctionne pour .Net, vous devriez préférer augmenter la taille des commentaires pour des bibliothèques telles que Mcrypt et .Net; et ne pas réduire la taille des commentaires dans Crypto ++. En effet, certains modes perdent la sécurité lorsque la taille du retour n’est pas la taille du bloc complet.

Je ne sais pas si cela fonctionnera avec .Net, mais c’est quelque chose que vous devriez considérer ou essayer:

 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 vous ne pouvez pas ajuster la taille des commentaires dans .Net, voici comment modifier la taille des commentaires dans Crypto ++. Vous configurez un AlgorithmParameters pour contenir le paramètre de taille de feedback, puis vous appelez SetKey avec les parameters supplémentaires:

 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); ... } 

Ce n’est pas clair pour moi si le mode CFB fonctionnant en mode FIPS permet une taille de retour aussi petite. S’il lève une exception, vous devrez utiliser uniquement CFB_Mode .

AlgorithmParameters peut sembler un peu étrange à cause de la surcharge de operator() . Vous pouvez en savoir plus sur NameValuePairs sur le wiki Crypto ++. Les autres pages wiki intéressantes sont TripleDES et le mode CFB .

—-

Une autre chose à surveiller est le codage de texte. Cela provoque généralement des problèmes d’interopérabilité en .Net et Java en raison de l’UTF-16. UTF-8 et ASCII causent le moins de problèmes. Vous devriez être ok puisque vous encoding = new UTF8Encoding() .

Mais si les choses ne fonctionnent toujours pas pour vous, alors vous obtenez un message d’octet qui n’est ni codé ni interprété. Par exemple, utilisez ceci dans .Net et Crypto ++:

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

Les quatre octets ne sont pas interprétés, aussi évite-t-il les problèmes de codage.