【问题标题】:c# AES Decryptionc# AES解密
【发布时间】:2013-08-13 12:03:37
【问题描述】:

我正在使用 SagePay Forms,目前正在将他们必须的 VB 示例转换为 c#。我已经取得了很好的进展,所以我的项目的加密部分工作正常(SagePay 可以解密)。

我遇到的问题是,当我尝试解密字符串时,它变成了垃圾。如果有人在我之前做过这件事,我将非常感谢我的解密代码的一些帮助。我已经包含了有效的加密代码,前两行是另一种方法的设置和调用。

我还没有添加 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;
    }

【问题讨论】:

  • 你在哪里找到的规格?也许您可以包含指向它们的链接。
  • 如果你在做解密也许你应该使用AES.CreateDecryptor而不是AES.CreateEncryptor
  • 感谢 Greg,您的最后一条评论现在生成了一个可读的字符串,尽管无论出于何种原因,最后仍然有些废话。有点明显,现在我想了想,但看不到它。我会再去解析字符串,看看我是怎么做的。非常感谢,史蒂夫。
  • 当然你最后有“废话”。如果使用 PKCS#7 填充机制填充纯文本,则您忘记了纯文本比密文。您不应忽略 Read 方法返回的长度。
  • 您正在跳过不必要的障碍。您可以通过一次调用 TransformFinalBlock 来替换所有加密流代码。

标签: c# encryption aes opayo


【解决方案1】:

您的代码实际上存在多个问题。首先在您的解密方法中,您要创建一个加密器,它应该是一个解密器。其次,当您进行解密时,您正在读取整个块,包括将算法填充到缓冲区中。下面是一个固定项目的类,应该返回正确的结果。但是,我确实建议您找到一种更好的方法来存储密钥,放入您的代码并按照您的方式生成它,这是不行的。您应该使用 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();

【讨论】:

  • 谢谢 Moe,密钥在 web.config 中,稍后会被加密,我只是为了发布而硬编码。我现在可以使用它,并将根据您的帖子进行审核以查看改进情况。
  • 对每个加密字符串使用相同的 IV 是一个真正的坏主意。特别是对于较小的块大小。如果您加密两个长度超过 16 个字节的字符串,但它们的前 16 个字节将相同,则加密文本的前 16 个字节也将相同。这就是人们提出初始化向量 (IV) 的原因 - 如果您为每个字符串使用一个随机向量(并将其与加密文本一起存储),这将不会发生。
  • @JanHudecek 我完全同意。我不确定 SagePay 在解密密文的方式方面做了什么,这可能不是他们协议中的一个选项。所以这个例子只是为了修复发布的代码。但我绝对同意,如果可能的话,您不应该对加密字符串使用相同的 IV。
  • @nerdybeardo 谢谢你,这正是我想要的:)
猜你喜欢
  • 1970-01-01
  • 2023-03-23
  • 2013-04-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-24
  • 2013-08-12
  • 2013-08-11
相关资源
最近更新 更多