2013-07-07 2 views
4

Я работаю с формами SagePay и в настоящее время конвертирует примеры VB, которые они имеют для C#. Я добился хороших результатов, поэтому часть шифрования моего проекта прекрасно работает (SagePay может расшифровать его).C# AES Decryption

Проблема, с которой я сталкиваюсь, заключается в том, что когда я пытаюсь расшифровать строку, она превращается в мусор. Если кто-то сделал это раньше, я бы очень признателен за помощь в моем дешифрованном коде. Я включил код шифрования, который работает, и первые две строки - это настройка и вызов другого метода.

Я не добавил код VB, но если это необходимо, я могу добавить его. Не хотел, чтобы огромный пост, если не требуется.

Методы Подсобные:

public string byteArrayToHexString(byte[] ba) 
    { 
    return BitConverter.ToString(ba).Replace("-", ""); 
    } 

public static byte[] StringToByteArray(string hex) 
    { 
     return Enumerable.Range(0, hex.Length) 
         .Where(x => x % 2 == 0) 
         .Select(x => Convert.ToByte(hex.Substring(x, 2), 16)) 
         .ToArray(); 
    } 

Главная Метод шифрования с первой парой линий, являющихся призванием он извлекается из большого метода.

string crypt = "blahblahblah" 
string EncryptAndEncode = "@" + byteArrayToHexString(aesEncrypt(crypt)); 


     private byte[] aesEncrypt(string inputText) 
    { 

     RijndaelManaged AES = new RijndaelManaged(); 

     //set the mode, padding and block size for the key 
     AES.Padding = PaddingMode.PKCS7; 
     AES.Mode = CipherMode.CBC; 
     AES.KeySize = 128; 
     AES.BlockSize = 128; 

     //convert key and plain text input into byte arrays 
     Byte[] keyAndIvBytes = UTF8Encoding.UTF8.GetBytes("tR7nR6wZHGjYMCuV"); 
     Byte[] inputBytes = UTF8Encoding.UTF8.GetBytes(inputText);//AbHLlc5uLone0D1q 

     //create streams and encryptor object 
     MemoryStream memoryStream = new MemoryStream(); 
     CryptoStream cryptoStream = new CryptoStream(memoryStream, AES.CreateEncryptor(keyAndIvBytes, keyAndIvBytes), CryptoStreamMode.Write); 

     //perform encryption 
     cryptoStream.Write(inputBytes, 0, inputBytes.Length); 
     cryptoStream.FlushFinalBlock(); 

     //get encrypted stream into byte array 
     Byte[] outBytes = memoryStream.ToArray(); 

     //close streams 
     memoryStream.Close(); 
     cryptoStream.Close(); 
     AES.Clear(); 

     return outBytes; 
    } 

Декодирование и дешифрование методы

public string DecodeAndDecrypt(string strIn) 
    { 
     //** HEX decoding then AES decryption, CBC blocking with PKCS5 padding - DEFAULT ** 


     string DecodeAndDecrypt = aesDecrypt(StringToByteArray(strIn.Substring(1))); 
     return (DecodeAndDecrypt); 
    } 

    private string aesDecrypt(Byte[] inputBytes) 
    { 
    RijndaelManaged AES = new RijndaelManaged(); 
    Byte[] keyAndIvBytes = UTF8Encoding.UTF8.GetBytes("tR7nR6wZHGjYMCuV"); 
    Byte[] outputBytes = inputBytes;//Convert.FromBase64String(inputBytes); 

    //set the mode, padding and block size 
    AES.Padding = PaddingMode.PKCS7; 
    AES.Mode = CipherMode.CBC; 
    AES.KeySize = 128; 
    AES.BlockSize = 128; 

    //create streams and decryptor object 
    MemoryStream memoryStream = new MemoryStream(outputBytes); 
    CryptoStream cryptoStream = new CryptoStream(memoryStream, AES.CreateEncryptor(keyAndIvBytes, keyAndIvBytes), CryptoStreamMode.Read); 
    //perform decryption 
    cryptoStream.Read(outputBytes, 0, outputBytes.Length); 
    Trace.WriteLine(outputBytes); 
    //close streams 
    memoryStream.Close(); 
    cryptoStream.Close(); 
    AES.Clear(); 
    //return System.Text.Encoding.UTF8.GetString(outputBytes); 

    string plainText = Encoding.UTF8.GetString(outputBytes, 
            0, 
            outputBytes.Length); 

    return plainText; 
    } 
+0

Где вы нашли спецификации? Возможно, вы можете включить ссылку на них. –

+2

Если вы делаете дешифрование, возможно, вы должны использовать 'AES.CreateDecryptor' вместо' AES.CreateEncryptor' –

+0

Спасибо, Грег, ваш последний комментарий теперь привел к чтению строки, хотя и по-прежнему дерьмо в конце по какой-либо причине. Теперь я думаю о нем, но не мог его увидеть. Я дам ему еще один раз проанализировать строку и посмотреть, как я нахожусь. Большое спасибо, Стив. –

ответ

6

Есть на самом деле несколько проблем с кодом. Сначала в вашем методе расшифровки вы создаете шифр, который должен быть расшифровщиком. Во-вторых, вы читаете весь блок, включая дополнение вашего алгоритма в буфер, когда вы выполняете дешифрование. Ниже приведен класс с фиксированными элементами и должен возвращать правильный результат. Тем не менее, я предлагаю вам найти лучший способ хранения ключа, вставить свой код и создать его так, как вы его рекламируете, это нет. Вы должны сгенерировать свой ключ с помощью RNG (RNGCryptoServiceProvider), а затем использовать его с помощью безопасного алгоритма хеширования, такого как SHA512, использовать этот вывод для вашего ключа. Затем вам нужно найти хорошее место для его хранения, я бы посмотрел на шифрование вашего файла web.config.

public static class EncryptionHelper 
{ 
    private static byte[] keyAndIvBytes; 

    static EncryptionHelper() 
    { 
     // You'll need a more secure way of storing this, I hope this isn't 
     // the real key 
     keyAndIvBytes = UTF8Encoding.UTF8.GetBytes("tR7nR6wZHGjYMCuV"); 
    } 

    public static string ByteArrayToHexString(byte[] ba) 
    { 
     return BitConverter.ToString(ba).Replace("-", ""); 
    } 

    public static byte[] StringToByteArray(string hex) 
    { 
     return Enumerable.Range(0, hex.Length) 
         .Where(x => x % 2 == 0) 
         .Select(x => Convert.ToByte(hex.Substring(x, 2), 16)) 
         .ToArray(); 
    } 

    public static string DecodeAndDecrypt(string cipherText) 
    { 
     string DecodeAndDecrypt = AesDecrypt(StringToByteArray(cipherText)); 
     return (DecodeAndDecrypt); 
    } 

    public static string EncryptAndEncode(string plaintext) 
    { 
     return ByteArrayToHexString(AesEncrypt(plaintext)); 
    } 

    public static string AesDecrypt(Byte[] inputBytes) 
    { 
     Byte[] outputBytes = inputBytes; 

     string plaintext = string.Empty; 

     using (MemoryStream memoryStream = new MemoryStream(outputBytes)) 
     { 
      using (CryptoStream cryptoStream = new CryptoStream(memoryStream, GetCryptoAlgorithm().CreateDecryptor(keyAndIvBytes, keyAndIvBytes), CryptoStreamMode.Read)) 
      { 
       using (StreamReader srDecrypt = new StreamReader(cryptoStream)) 
       { 
        plaintext = srDecrypt.ReadToEnd(); 
       } 
      } 
     } 

     return plaintext; 
    } 

    public static byte[] AesEncrypt(string inputText) 
    { 
     byte[] inputBytes = UTF8Encoding.UTF8.GetBytes(inputText);//AbHLlc5uLone0D1q 

     byte[] result = null; 
     using (MemoryStream memoryStream = new MemoryStream()) 
     { 
      using (CryptoStream cryptoStream = new CryptoStream(memoryStream, GetCryptoAlgorithm().CreateEncryptor(keyAndIvBytes, keyAndIvBytes), CryptoStreamMode.Write)) 
      { 
       cryptoStream.Write(inputBytes, 0, inputBytes.Length); 
       cryptoStream.FlushFinalBlock(); 

       result = memoryStream.ToArray(); 
      } 
     } 

     return result; 
    } 


    private static RijndaelManaged GetCryptoAlgorithm() 
    { 
     RijndaelManaged algorithm = new RijndaelManaged(); 
     //set the mode, padding and block size 
     algorithm.Padding = PaddingMode.PKCS7; 
     algorithm.Mode = CipherMode.CBC; 
     algorithm.KeySize = 128; 
     algorithm.BlockSize = 128; 
     return algorithm; 
    } 
} 

Назвать это легко:

string crypt = "blahblahblah"; 
string EncryptAndEncode = EncryptionHelper.EncryptAndEncode(crypt);    
Console.WriteLine(EncryptAndEncode); 

Console.WriteLine(EncryptionHelper.DecodeAndDecrypt(EncryptAndEncode)); 

Console.ReadLine(); 
+0

Спасибо Мо, ключ находится в файле web.config и будет зашифрован на более позднем этапе, я просто жестко запрограммирован для отправки. Я сейчас работаю и буду рассматривать ваш пост, чтобы посмотреть на улучшения. –

+1

Использование одного и того же IV для каждой зашифрованной строки - это ** ДЕЙСТВИТЕЛЬНО ** плохая идея. Особенно с меньшим размером блока. Если вы зашифруете две строки длиной более 16 байт, но первые 16 байт будут идентичны, зашифрованный текст также будет иметь первые 16 байтов. Вот почему люди придумали вектор инициализации (IV) - если вы используете случайную для каждой строки (и храните ее вместе с зашифрованным текстом), этого не произойдет. – JanHudecek

+0

@JanHudecek Я полностью согласен. Я не уверен, что SagePay делает с точки зрения того, как он расшифровывает шифрованный текст, это может быть не вариант в их протоколе. Таким образом, этот пример - это просто * исправить * код, который был опубликован.Но я определенно согласен с тем, что вы не должны использовать тот же IV для зашифрованных строк, если это вообще возможно. – nerdybeardo