Я пытаюсь прочитать значение Base64-Encoded из таблицы базы данных, управляемой на стороне Linux. В этой таблице есть столбец с именем first_name. На стороне Linux я могу легко ее расшифровать, используя следующую команду в PHP:
$data = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, "patient_fn_salt", base64_decode("H6XmkH+VWvdD88THCliKJjLisGZIBk3CTNvyQMLnhpo="), MCRYPT_MODE_ECB);
Однако я стараюсь как можно больше дублировать эту логику на стороне C #, и все, что я получаю, – тарабарщина.
Мой код C # ниже, я надеюсь, что у вас есть предложения, потому что у меня кончились идеи 🙁
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 // array 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; } }
Как говорит Paŭlo, режим ECB не использует IV. Если C # настаивает на одном, используйте все нулевые байты.
Ключ «patient_fn_salt» составляет 15 символов, 120 бит. Функция дешифрования ожидает 256 бит ключа. Вы должны быть уверены, что дополнительные биты идентичны в обеих системах и добавляются в одно и то же место в обеих системах. Даже однократное неправильное приведет к расшифровке мусора. Внимательно прочитайте документацию PHP, чтобы точно определить, как «patient_fn_salt» будет расширен до 256-битного ключа. В частности, проверьте, является ли фактический ключ SHA256("patient_fn_salt")
.
В стороне, режим ECB небезопасен. Используйте режим CTR или режим CBC. Режим CTR не требует заполнения, поэтому, вероятно, это означает, что меньше хранится cyphertext.
ETA: при повторном чтении я замечаю, что сторона C # заполняет нулями. Какое дополнение используется PHP-стороной? Нулевая прокладка – это не очень хорошая идея, поскольку она не может распознать ошибочное дешифрование. Заполнение PKCS7 имеет гораздо больше шансов распознать неисправный выход. Лучше явно указывать отступы на обоих концах, а не полагаться на значения по умолчанию.
Сообщение устарело, но это может помочь кому-то в будущем. Эта функция шифрует точно так же, как и mcrypt_encrypt с параметрами MCRYPT_RIJNDAEL_256 и 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; }
И вот функция для ее расшифровки
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; }