Come posso decodificare un valore MCRYPT_RIJNDAEL_256 crittografato in C #, che è stato crittografato da mcrypt in PHP?

Sto cercando di leggere un valore Base64-Encoded da una tabella Database gestita sul lato Linux. In quella tabella c'è una colonna chiamata first_name. Da parte di Linux posso decodificarlo facilmente usando il seguente command in PHP:

$data = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, "patient_fn_salt", base64_decode("H6XmkH+VWvdD88THCliKJjLisGZIBk3CTNvyQMLnhpo="), MCRYPT_MODE_ECB); 

Comunque cerco il più ansible di duplicare questa logica sul lato C # e tutto ciò che ottengo è senza senso.

Il mio codice C # è sotto, spero che tu abbia qualche suggerimento perché ho esaurito le idee 🙁

 byte [] cipherText = Convert.FromBase64String("H6XmkH+VWvdD88THCliKJjLisGZIBk3CTNvyQMLnhpo="); byte [] key = Encoding.UTF8.GetBytes("patient_fn_salt"); Array.Resize(ref key, 32); byte [] iv = new byte[32]; string fname = Utilities.Decrypt(cipherText, key, iv); public static string Decrypt(byte[] cipherText, byte[] Key, byte[] IV) { // Check arguments. if (cipherText == null || cipherText.Length <= 0) throw new ArgumentNullException("cipherText"); if (Key == null || Key.Length <= 0) throw new ArgumentNullException("Key"); if (IV == null || IV.Length <= 0) throw new ArgumentNullException("Key"); // TDeclare the streams used // to decrypt to an in memory // arrays of bytes. MemoryStream msDecrypt = null; CryptoStream csDecrypt = null; StreamReader srDecrypt = null; // Declare the AesManaged object // used to decrypt the data. RijndaelManaged rj = new RijndaelManaged(); // Declare the string used to hold // the decrypted text. string plaintext = null; try { // Create an AesManaged object // with the specified key and IV. rj.Mode = CipherMode.ECB; rj.BlockSize = 256; rj.KeySize = 256; rj.Padding = PaddingMode.Zeros; rj.Key = Key; rj.GenerateIV(); //rj.IV = IV; // Create a decrytor to perform the stream transform. ICryptoTransform decryptor = rj.CreateDecryptor(rj.Key, rj.IV); // Create the streams used for decryption. msDecrypt = new MemoryStream(cipherText); csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read); srDecrypt = new StreamReader(csDecrypt); // Read the decrypted bytes from the decrypting stream // and place them in a string. plaintext = srDecrypt.ReadToEnd(); } finally { // Clean things up. // Close the streams. if (srDecrypt != null) srDecrypt.Close(); if (csDecrypt != null) csDecrypt.Close(); if (msDecrypt != null) msDecrypt.Close(); // Clear the AesManaged object. if (rj != null) rj.Clear(); } return plaintext; } } 

Come dice Paŭlo, la modalità ECB non usa una flebo. Se C # insiste su uno allora usa tutti i byte zero.

Il tasto "patient_fn_salt" è di 15 caratteri, 120 bit. La tua function di decrittografia prevede 256 bit di chiave. È necessario essere molto sicuri che i bit aggiuntivi siano identici in entrambi i sisthemes e vengano aggiunti nello stesso posto in entrambi i sisthemes. Anche un singolo bit sbagliato comporterà la decrittazione dei rifiuti. Leggi con attenzione la documentazione di PHP per determinare esattamente come "patient_fn_salt" è espanso su una chiave a 256 bit. In particolare, controllare se la chiave effettiva è SHA256("patient_fn_salt") .

Per inciso, la modalità ECB è insicura. Preferire la modalità CTR o CBC. La modalità CTR non richiede il riempimento, quindi probabilmente significherà less text cifrato da memorizzare.

ETA: su un'altra lettura, noto che il lato C # è riempito di zeri. Quale padding usa il lato PHP? Zero padding non è una buona idea, in quanto non può riconoscere una decifratura difettosa. Il padding PKCS7 ha una possibilità molto migliore di riconoscere un output difettoso. Meglio specificare esplicitamente il padding su entrambe le estremità piuttosto che fare affidamento sui valori predefiniti.

Il post è vecchio, ma questo potrebbe aiutare qualcuno in futuro. Questa function crittografa esattamente come mcrypt_encrypt con i parametri MCRYPT_RIJNDAEL_256 e MCRYPT_MODE_ECB

  static byte[] EncryptStringToBytes(string plainText, byte[] key) { if (plainText == null || plainText.Length <= 0) throw new ArgumentNullException("plainText"); if (key == null || key.Length <= 0) throw new ArgumentNullException("key"); byte[] encrypted; using (var rijAlg = new RijndaelManaged()) { rijAlg.BlockSize = 256; rijAlg.Key = key; rijAlg.Mode = CipherMode.ECB; rijAlg.Padding = PaddingMode.Zeros; rijAlg.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV); using (var msEncrypt = new MemoryStream()) using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) { using (var swEncrypt = new StreamWriter(csEncrypt)) swEncrypt.Write(plainText); encrypted = msEncrypt.ToArray(); } } return encrypted; } 

Ed ecco la function per decodificarlo

  static string DecryptStringFromBytes(byte[] cipherText, byte[] key) { if (cipherText == null || cipherText.Length <= 0) throw new ArgumentNullException("cipherText"); if (key == null || key.Length <= 0) throw new ArgumentNullException("key"); string plaintext; using (var rijAlg = new RijndaelManaged()) { rijAlg.BlockSize = 256; rijAlg.Key = key; rijAlg.Mode = CipherMode.ECB; rijAlg.Padding = PaddingMode.Zeros; rijAlg.IV = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV); using (var msDecrypt = new MemoryStream(cipherText)) using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)) using (var srDecrypt = new StreamReader(csDecrypt)) plaintext = srDecrypt.ReadToEnd(); } return plaintext; }