2013-07-07 196 views
4

我正在使用SagePay Forms,目前正在將它們的VB示例轉換爲c#。我已經取得了很好的進展,所以我的項目的加密部分工作正常(SagePay可以解密它)。c#AES解密

我遇到的問題是,當我試圖解密字符串時,它變成垃圾。如果有人已經這樣做了,我將非常感謝我的解密代碼的一些幫助。我已經包含了可用的加密代碼,前兩行是安裝程序和另一種方法的調用。

我還沒有添加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

感謝Greg,你的最新評論現在已經產生了一個可讀的字符串,儘管在任何原因結束時仍然有些廢話。現在我想到的很明顯,但看不到它。我會給它另一個解析字符串,看看我如何繼續。非常感謝,史蒂夫。 –

回答

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

感謝Moe,關鍵是在web.config中,並且會在稍後階段加密,我只是爲了發佈而硬編碼。我現在已經開始工作了,並會根據你的帖子進行審查,看看有哪些改進。 –

+1

對每個加密的字符串使用相同的IV是一個**真的不好主意。特別是對於較小的塊大小。如果你加密兩個長度超過16字節的字符串,但是它們的前16個字節是相同的,那麼加密文本也將具有相同的前16個字節。這就是爲什麼人們想出了初始化向量(IV) - 如果您爲每個字符串使用隨機的字符串(並將其與加密文本一起存儲),這不會發生。 – JanHudecek

+0

@JanHudecek我完全同意。但我不確定SagePay在解密密文方面做了什麼,它可能不是他們協議中的一個選項。所以這個例子只是爲了修復發佈的代碼。但我絕對同意,如果可能的話,您不應該對加密字符串使用相同的IV。 – nerdybeardo