1

我正在尝试使用该Rijndael方法来加密和解密数据。它加密得很好,但是当我尝试解密它时,它会padding is invalid and cannot be removed 在方法的行cs.FlushFinalBlock();中给出private static byte[] DecryptString(byte[] cipherData, byte[] Key, byte[] IV)。我尝试了很多来源,比如

我知道这是一个常见问题,甚至可能是重复的。我从早上开始在网上搜索并没有找到解决方案。以下是我的代码。

    //clearText -> the string to be encrypted
    //passowrd -> encryption key
    public string EncryptString(string clearText, string Password)
    {
        // First we need to turn the input string into a byte array. 
        byte[] clearBytes =
            Encoding.Unicode.GetBytes(clearText);

        // Then, we need to turn the password into Key and IV 
        // We are using salt to make it harder to guess our key
        // using a dictionary attack - 
        // trying to guess a password by enumerating all possible words. 
        var pdb = new PasswordDeriveBytes(Password,
                                          new byte[]
                                              {
                                                  0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d,
                                                  0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76
                                              });

        // Now get the key/IV and do the encryption using the
        // function that accepts byte arrays. 
        // Using PasswordDeriveBytes object we are first getting
        // 32 bytes for the Key 
        // (the default Rijndael key length is 256bit = 32bytes)
        // and then 16 bytes for the IV. 
        // IV should always be the block size, which is by default
        // 16 bytes (128 bit) for Rijndael. 
        // If you are using DES/TripleDES/RC2 the block size is
        // 8 bytes and so should be the IV size. 
        // You can also read KeySize/BlockSize properties off
        // the algorithm to find out the sizes. 
        byte[] encryptedData = EncryptString(clearBytes,
                                             pdb.GetBytes(32), pdb.GetBytes(16));

        // Now we need to turn the resulting byte array into a string. 
        // A common mistake would be to use an Encoding class for that.
        //It does not work because not all byte values can be
        // represented by characters. 
        // We are going to be using Base64 encoding that is designed
        //exactly for what we are trying to do. 
        return Convert.ToBase64String(encryptedData);
    }
    //cipherText -> the string to be decrypted
    //passowrd -> decryption key
    public string DecryptString(string cipherText, string Password)
    {
        // First we need to turn the input string into a byte array. 
        // We presume that Base64 encoding was used 
        byte[] cipherBytes = Convert.FromBase64String(cipherText);

        // Then, we need to turn the password into Key and IV 
        // We are using salt to make it harder to guess our key
        // using a dictionary attack - 
        // trying to guess a password by enumerating all possible words. 
        var pdb = new PasswordDeriveBytes(Password,
                                          new byte[]
                                              {
                                                  0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65,
                                                  0x64, 0x76, 0x65, 0x64, 0x65, 0x76
                                              });

        // Now get the key/IV and do the decryption using
        // the function that accepts byte arrays. 
        // Using PasswordDeriveBytes object we are first
        // getting 32 bytes for the Key 
        // (the default Rijndael key length is 256bit = 32bytes)
        // and then 16 bytes for the IV. 
        // IV should always be the block size, which is by
        // default 16 bytes (128 bit) for Rijndael. 
        // If you are using DES/TripleDES/RC2 the block size is
        // 8 bytes and so should be the IV size. 
        // You can also read KeySize/BlockSize properties off
        // the algorithm to find out the sizes. 
        byte[] decryptedData = DecryptString(cipherBytes,
                                             pdb.GetBytes(32), pdb.GetBytes(16));

        // Now we need to turn the resulting byte array into a string. 
        // A common mistake would be to use an Encoding class for that.
        // It does not work 
        // because not all byte values can be represented by characters. 
        // We are going to be using Base64 encoding that is 
        // designed exactly for what we are trying to do. 
        return Encoding.Unicode.GetString(decryptedData);
    }

    // Encrypt a byte array into a byte array using a key and an IV 
    private static byte[] EncryptString(byte[] clearData, byte[] Key, byte[] IV)
    {
        // Create a MemoryStream to accept the encrypted bytes 
        var ms = new MemoryStream();

        // Create a symmetric algorithm. 
        // We are going to use Rijndael because it is strong and
        // available on all platforms. 
        // You can use other algorithms, to do so substitute the
        // next line with something like 
        //      TripleDES alg = TripleDES.Create(); 
        Rijndael alg = Rijndael.Create();

        // Now set the key and the IV. 
        // We need the IV (Initialization Vector) because
        // the algorithm is operating in its default 
        // mode called CBC (Cipher Block Chaining).
        // The IV is XORed with the first block (8 byte) 
        // of the data before it is encrypted, and then each
        // encrypted block is XORed with the 
        // following block of plaintext.
        // This is done to make encryption more secure. 

        // There is also a mode called ECB which does not need an IV,
        // but it is much less secure. 
        alg.Key = Key;
        alg.IV = IV;

        // Create a CryptoStream through which we are going to be
        // pumping our data. 
        // CryptoStreamMode.Write means that we are going to be
        // writing data to the stream and the output will be written
        // in the MemoryStream we have provided. 
        var cs = new CryptoStream(ms,
                                  alg.CreateEncryptor(), CryptoStreamMode.Write);

        // Write the data and make it do the encryption 
        cs.Write(clearData, 0, clearData.Length);

        // Close the crypto stream (or do FlushFinalBlock). 
        // This will tell it that we have done our encryption and
        // there is no more data coming in, 
        // and it is now a good time to apply the padding and
        // finalize the encryption process. 
        cs.FlushFinalBlock();

        // Now get the encrypted data from the MemoryStream.
        // Some people make a mistake of using GetBuffer() here,
        // which is not the right way. 
        byte[] encryptedData = ms.ToArray();

        return encryptedData;
    }

    private static byte[] DecryptString(byte[] cipherData,
                                        byte[] Key, byte[] IV)
    {
        // Create a MemoryStream that is going to accept the
        // decrypted bytes 
        var ms = new MemoryStream();

        // Create a symmetric algorithm. 
        // We are going to use Rijndael because it is strong and
        // available on all platforms. 
        // You can use other algorithms, to do so substitute the next
        // line with something like 
        //     TripleDES alg = TripleDES.Create(); 
        Rijndael alg = Rijndael.Create();

        // Now set the key and the IV. 
        // We need the IV (Initialization Vector) because the algorithm
        // is operating in its default 
        // mode called CBC (Cipher Block Chaining). The IV is XORed with
        // the first block (8 byte) 
        // of the data after it is decrypted, and then each decrypted
        // block is XORed with the previous 
        // cipher block. This is done to make encryption more secure. 
        // There is also a mode called ECB which does not need an IV,
        // but it is much less secure. 
        alg.Key = Key;
        alg.IV = IV;

        // Create a CryptoStream through which we are going to be
        // pumping our data. 
        // CryptoStreamMode.Write means that we are going to be
        // writing data to the stream 
        // and the output will be written in the MemoryStream
        // we have provided. 
        var cs = new CryptoStream(ms,
                                  alg.CreateDecryptor(), CryptoStreamMode.Write);

        // Write the data and make it do the decryption 
        cs.Write(cipherData, 0, cipherData.Length);

        // Close the crypto stream (or do FlushFinalBlock). 
        // This will tell it that we have done our decryption
        // and there is no more data coming in, 
        // and it is now a good time to remove the padding
        // and finalize the decryption process. 
        cs.FlushFinalBlock();

        // Now get the decrypted data from the MemoryStream. 
        // Some people make a mistake of using GetBuffer() here,
        // which is not the right way. 
        byte[] decryptedData = ms.ToArray();

        return decryptedData;
    }

非常感谢:) PS:我从网上获取了这段代码并进行了一些编辑以适合我的程序

4

1 回答 1

1

您需要克服异常,以便诊断正在发生的事情。为此,您需要将解密端设置为只期望没有填充。这将让它接受任何东西。完成此操作后,您可以查看解密中出现的内容并开始诊断故障。请注意,这不是解决方案,它是一种忽略异常的方法。无论导致异常的原因仍然存在。

看看出现了什么。都是垃圾吗?它是部分垃圾和部分原始明文吗?如果是混合的,垃圾出现在哪里:开始,结束,两者,中间某个地方?告诉我们您所看到的,我们可以为您指出问题的可能原因。

当一切正常时,将加密和解密都设置为 PKCS#7 填充。不要将无填充物留在原处。

于 2013-06-18T13:15:49.250 回答