使用Rijndael进行解密时,“填充无效且无法删除”

时间:2012-05-17 08:08:09

标签: c# cryptography rijndael

我正在尝试解密用Rijndael algorythm加密的字符串。如果长度小于16个字符,则此类型的加密在Key和IV的右侧应用带“#”的填充。要解密的字符串是从发送它的Web服务接收的,而密钥是以XML SOAP格式发送给我的。 IV是我的机器的Mac地址(服务器使用IV来加密字符串)。当我尝试解密收到的字符串时,我的程序在此指令时崩溃:

while ((num5 = stream3.ReadByte()) != -1)

它给我这个错误“填充无效且无法删除”。 我在MSDN上搜索过这个错误,它说当用于加密的IV与用于解密的IV不同时会发生这种情况,但是,我再说一遍,IV是MacAddress,每次都是相同的。

这是加密和解密功能的源代码:

public static string Decrypt(string strInputString, string strKeyString, string myIV)
{
        if ((strInputString == null) || (strInputString.Length == 0))
        {
            return strInputString;
        }
        try
        {
            int num5;
            int keySize = 0x100;
            int blockSize = 0x100;
            int length = keySize / 0x10;
            if (strKeyString.Length > length)
            {
                strKeyString = strKeyString.Substring(0, length);
            }
            if (strKeyString.Length < length)
            {
                strKeyString = strKeyString.PadRight(length, '#');
            }
            Encoding.Unicode.GetBytes(strKeyString);
            if (myIV.Length > length)
            {
                myIV = myIV.Substring(0, length);
            }
            if (myIV.Length < length)
            {
                myIV = myIV.PadRight(length, '#');
            }
            Encoding.Unicode.GetBytes(myIV);
            byte[] bytes = Encoding.Unicode.GetBytes(strKeyString);
            byte[] rgbIV = Encoding.Unicode.GetBytes(myIV);
            RijndaelManaged managed = new RijndaelManaged {
                BlockSize = blockSize,
                KeySize = keySize
            };
            MemoryStream stream = new MemoryStream();
            for (int i = 0; i < strInputString.Length; i += 2)
            {
                stream.WriteByte(byte.Parse(strInputString.Substring(i, 2), NumberStyles.AllowHexSpecifier));
            }
            stream.Position = 0L;
            MemoryStream stream2 = new MemoryStream();
            CryptoStream stream3 = new CryptoStream(stream, managed.CreateDecryptor(bytes, rgbIV), CryptoStreamMode.Read);
            while ((num5 = stream3.ReadByte()) != -1)
            {
                stream2.WriteByte((byte) num5);
            }
            stream3.Close();
            stream2.Close();
            stream.Close();
            byte[] buffer3 = stream2.ToArray();
            return Encoding.Unicode.GetString(buffer3);
        }
        catch (Exception exception)
        {
            Log.Error(exception.Message);
        }
}

public static string Encrypt(string strInputString, string strKeyString, string myIV)
{
        if ((strInputString == null) || (strInputString.Length == 0))
        {
            return strInputString;
        }
        try
        {
            int num4;
            int keySize = 0x100;
            int blockSize = 0x100;
            int length = keySize / 0x10;
            if (strKeyString.Length > length)
            {
                strKeyString = strKeyString.Substring(0, length);
            }
            if (strKeyString.Length < length)
            {
                strKeyString = strKeyString.PadRight(length, '#');
            }
            Encoding.Unicode.GetBytes(strKeyString);
            if (myIV.Length > length)
            {
                myIV = myIV.Substring(0, length);
            }
            if (myIV.Length < length)
            {
                myIV = myIV.PadRight(length, '#');
            }
            Encoding.Unicode.GetBytes(myIV);
            byte[] bytes = Encoding.Unicode.GetBytes(strKeyString);
            byte[] rgbIV = Encoding.Unicode.GetBytes(myIV);
            string str = "";
            RijndaelManaged managed = new RijndaelManaged {
                BlockSize = blockSize,
                KeySize = keySize
            };
            MemoryStream stream = new MemoryStream(Encoding.Unicode.GetBytes(strInputString));
            MemoryStream stream2 = new MemoryStream();
            CryptoStream stream3 = new CryptoStream(stream2, managed.CreateEncryptor(bytes, rgbIV), CryptoStreamMode.Write);
            while ((num4 = stream.ReadByte()) != -1)
            {
                stream3.WriteByte((byte) num4);
            }
            stream3.Close();
            stream2.Close();
            stream.Close();
            foreach (byte num5 in stream2.ToArray())
            {
                str = str + num5.ToString("X2");
            }
            return str;
        }
        catch (Exception exception)
        {
            Log.Error(exception.Message);
        }
    }

}

4 个答案:

答案 0 :(得分:0)

使用下面的测试代码可以正常使用 - 您确定要传入加密字符串进行解密吗?

static void Main(string[] args)
    {

        string strInputString = "test";
        string strKeyString = "test123";
        string myIV = GetMacAddress();

        string encryptedString = Encrypt(strInputString, strKeyString, myIV);
        string decryptedString = Decrypt(encryptedString, strKeyString, myIV);

    }

    public static string Decrypt(string strInputString, string strKeyString, string myIV)
    {
        if ((strInputString == null) || (strInputString.Length == 0))
        {
            return strInputString;
        }

            int num5;
            int keySize = 0x100;
            int blockSize = 0x100;
            int length = keySize / 0x10;
            if (strKeyString.Length > length)
            {
                strKeyString = strKeyString.Substring(0, length);
            }
            if (strKeyString.Length < length)
            {
                strKeyString = strKeyString.PadRight(length, '#');
            }
            Encoding.Unicode.GetBytes(strKeyString);
            if (myIV.Length > length)
            {
                myIV = myIV.Substring(0, length);
            }
            if (myIV.Length < length)
            {
                myIV = myIV.PadRight(length, '#');
            }
            Encoding.Unicode.GetBytes(myIV);
            byte[] bytes = Encoding.Unicode.GetBytes(strKeyString);
            byte[] rgbIV = Encoding.Unicode.GetBytes(myIV);
            RijndaelManaged managed = new RijndaelManaged
            {
                BlockSize = blockSize,
                KeySize = keySize
            };
            MemoryStream stream = new MemoryStream();
            for (int i = 0; i < strInputString.Length; i += 2)
            {
                stream.WriteByte(byte.Parse(strInputString.Substring(i, 2), NumberStyles.AllowHexSpecifier));
            }
            stream.Position = 0L;
            MemoryStream stream2 = new MemoryStream();
            CryptoStream stream3 = new CryptoStream(stream, managed.CreateDecryptor(bytes, rgbIV), CryptoStreamMode.Read);
            while ((num5 = stream3.ReadByte()) != -1)
            {
                stream2.WriteByte((byte)num5);
            }
            stream3.Close();
            stream2.Close();
            stream.Close();
            byte[] buffer3 = stream2.ToArray();
            return Encoding.Unicode.GetString(buffer3);

    }

    public static string Encrypt(string strInputString, string strKeyString, string myIV)
    {
        if ((strInputString == null) || (strInputString.Length == 0))
        {
            return strInputString;
        }           
            int num4;
            int keySize = 0x100;
            int blockSize = 0x100;
            int length = keySize / 0x10;
            if (strKeyString.Length > length)
            {
                strKeyString = strKeyString.Substring(0, length);
            }
            if (strKeyString.Length < length)
            {
                strKeyString = strKeyString.PadRight(length, '#');
            }
            Encoding.Unicode.GetBytes(strKeyString);
            if (myIV.Length > length)
            {
                myIV = myIV.Substring(0, length);
            }
            if (myIV.Length < length)
            {
                myIV = myIV.PadRight(length, '#');
            }
            Encoding.Unicode.GetBytes(myIV);
            byte[] bytes = Encoding.Unicode.GetBytes(strKeyString);
            byte[] rgbIV = Encoding.Unicode.GetBytes(myIV);
            string str = "";
            RijndaelManaged managed = new RijndaelManaged
            {
                BlockSize = blockSize,
                KeySize = keySize
            };
            MemoryStream stream = new MemoryStream(Encoding.Unicode.GetBytes(strInputString));
            MemoryStream stream2 = new MemoryStream();
            CryptoStream stream3 = new CryptoStream(stream2, managed.CreateEncryptor(bytes, rgbIV), CryptoStreamMode.Write);
            while ((num4 = stream.ReadByte()) != -1)
            {
                stream3.WriteByte((byte)num4);
            }
            stream3.Close();
            stream2.Close();
            stream.Close();
            foreach (byte num5 in stream2.ToArray())
            {
                str = str + num5.ToString("X2");
            }
            return str;

    }

    private static string GetMacAddress()
    {
        string macAddresses = "";

        foreach (NetworkInterface nic in NetworkInterface.GetAllNetworkInterfaces())
        {
            if (nic.OperationalStatus == OperationalStatus.Up)
            {
                macAddresses += nic.GetPhysicalAddress().ToString();
                break;
            }
        }
        return macAddresses;
    }

答案 1 :(得分:0)

填充可能是Pkcs#5。而不是#,用一个字节值填充,这是要填充的字节数。

因此,如果要填充5个字节,填充字节将为0505050505,如果需要填充2个字节,填充将为0202

答案 2 :(得分:0)

我认为IV不是问题。这是密码本身。我怀疑服务器用来加密的密码不是客户端用来解密的密码。

我能够重现OP报告的崩溃的唯一方法是将错误的密码传递给Decrypt()方法。传入一个稍微不正确的IV不会引发异常。例如,我用IV作为MAC地址加密并使用冒号进行加密,然后用IV作为相同的MAC地址解密,并使用短划线。 - 前几个字节被加扰,但大约字节16开始所有内容都与纯文本原始文件匹配。

答案 3 :(得分:0)

您在加密时使用与原始字符串相同的字符编码吗?

我遇到了类似的问题......最后,差异在于我是如何传递要加密的数据(字符串)的。如果我复制/粘贴到文本框中,加密方式与我硬编码到程序中的方式不同。简而言之......原始数据的编码会产生很大的不同。虽然字符可能看起来相同,但实际上它们的表示方式可能完全不同(8字节,16字节等)。

了解原始字符串在加密算法之前是如何编码的(也可以检查IV参数编码。