简体   繁体   English

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

[英]“Padding is invalid and cannot be removed” when decrypting with Rijndael

I'm trying to decrypt a string crypted with Rijndael algorythm. 我正在尝试解密用Rijndael algorythm加密的字符串。 This type of cryptation apply a padding with "#" on the right of the Key and IV, if they are less than 16 characters long. 如果长度小于16个字符,则此类型的加密在Key和IV的右侧应用带“#”的填充。 The string to decrypt is received from a Webservice that sends it, and the Key, to me in XML SOAP Format. 要解密的字符串是从发送它的Web服务接收的,而密钥是以XML SOAP格式发送给我的。 The IV is the Mac Address of my machine (that the server use as IV to encrypt the string). IV是我的机器的Mac地址(服务器使用IV来加密字符串)。 When i try to decrypt the received string, my program crash at this instruction: 当我尝试解密收到的字符串时,我的程序在此指令崩溃:

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

and it give to me this error "Padding is not valid and it cannot be removed". 它给我这个错误“填充无效,无法删除”。 I've searched this error on MSDN, and it says that it happen when the IV used to encrypt is different from the IV used to decrypt, but, i repeat, the IV is the MacAddress and it is the same everytime. 我在MSDN上搜索过这个错误,它说当用于加密的IV与用于解密的IV不同时会发生这种情况,但是,我再说一遍,IV是MacAddress,每次都是相同的。

This is the sourcecode of Encrypt and Decrypt functions: 这是加密和解密功能的源代码:

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);
        }
    }

} }

Works fine for me with test code below - are you sure you're passing in the encrypted string for decryption ? 使用下面的测试代码可以正常工作 - 您确定要传入加密字符串进行解密吗?

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;
    }

Padding is probably Pkcs#5. 填充可能是Pkcs#5。 Instead of #, pad with a byte value that is the number of bytes to pad. 而不是#,填充一个字节值,即填充的字节数。

So if you have 5 bytes to pad, padding bytes will be 0505050505 , if you need to pad 2 bytes, padding will be 0202 . 因此,如果你有5个字节要填充,填充字节将是0505050505 ,如果你需要填充2个字节,填充将是0202

I don't think that the IV is the issue. 我不认为IV是问题。 It's the password itself. 这是密码本身。 I suspect that the password used by the server to encrypt is not the password being used by the client to decrypt. 我怀疑服务器用来加密的密码不是客户端用来解密的密码。

The only way I could reproduce the crash the OP was reporting was by passing in an incorrect password to the Decrypt() method. 我可以重现OP报告崩溃的唯一方法是将错误的密码传递给Decrypt()方法。 Passing in an IV that was just slightly incorrect wouldn't throw an exception. 传入一个稍微不正确的IV不会引发异常。 For example, I encrypted with the IV as a MAC address in caps and using colons, and then decrypted with the IV as the same MAC address in lower case and using dashes. 例如,我用IV作为MAC地址加密并使用冒号进行加密,然后用IV作为相同的MAC地址解密,并使用短划线。 -- first few bytes were scrambled, but by about byte 16 everything was started matching up with the plain text original. - 前几个字节被加扰,但大约字节16开始所有内容都与纯文本原始文件匹配。

Are you using the same character encoding as the original string at the time of encryption? 您是否在加密时使用与原始字符串相同的字符编码?

I had a similar issue... the difference, in the end, was how i was passing the data (string) to be encrypted. 我有一个类似的问题......最后,差异在于我如何传递要加密的数据(字符串)。 If I copy/pasted into a textbox, the encryption was different than if i hardcoded into the program. 如果我复制/粘贴到文本框中,加密方式与我硬编码到程序中的方式不同。 So in short... the encoding of the original data makes a big difference. 简而言之......原始数据的编码会产生很大的不同。 While the characters may look the same, in reality they could be represented quite differently (8 bytes, 16 bytes, etc). 虽然字符看起来可能相同,但实际上它们的表示方式可能完全不同(8字节,16字节等)。

Find out how the original string was encoded prior to the encryption algorithm (maybe check on the IV parameter encodings as well. 了解在加密算法之前如何编码原始字符串(也可以检查IV参数编码)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM