【问题标题】:C# Bad PKCS7 PaddingC# 错误的 PKCS7 填充
【发布时间】:2016-05-22 07:00:22
【问题描述】:

我在尝试实现 DES 加密和解密时遇到了上述错误(尽管我的代码允许不同的实现)

我对此进行了大量研究,并在 Stack Overflow 上发现了几个类似的问题,但是他们提供的答案是确保密钥和 IV 在加密和解密过程中相同,我似乎已经有了实现了这一点,所以问题的根源似乎在其他地方。

以下是我的代码,在#164行抛出异常

namespace xNFCE
{
    public class Crypto
    {

        public enum cryptype
        {
            DES,
            THREEDES,
            AES
        };

        // Variables for the file input, output and the password to encrypt the file
        string _input, _output;
        byte[] _password;
        cryptype _type;

        /// <summary>
        /// Initializes a new instance of the <see cref="xNFCE.Crypto"/> class.
        /// </summary>
        /// <param name="input">Input.</param>
        /// <param name="output">Output.</param>
        /// <param name="password">Password.</param>
        public Crypto(string input, string output, string password, cryptype type = cryptype.AES)
        {
            // Set the properties for the encryption
            _input = input;
            _output = output;
            _password = hash(password);
            _type = type;
        }


        /// <summary>
        /// Run the appropriate encryption function
        /// </summary>
        public void Encrypt()
        {
            switch (_type)
            {
                case cryptype.DES:
                    DESenc();
                    break;
                case cryptype.THREEDES:
                    // TODO Implement
                    throw new NotImplementedException();
                case cryptype.AES:
                    // TODO Implement
                    throw new NotImplementedException();
            }
        }


        /// <summary>
        /// Run the appropriate decryption function
        /// </summary>
        public void Decrypt()
        {
            switch (_type)
            {
                case cryptype.DES:
                    DESdec();
                    break;
                case cryptype.THREEDES:
                    // TODO Implement
                    throw new NotImplementedException();
                case cryptype.AES:
                    // TODO Implement
                    throw new NotImplementedException();
            }
        }


        /// <summary>
        /// Hash the password and return it as a byte array
        /// </summary>
        /// <param name="pwd">Pwd.</param>
        byte[] hash(String pwd)
        {
            // System.Text provides .GetBytes() this converts a string to the series of bytes
            // Convert the password string to an array of bytes
            byte[] bytes = Encoding.ASCII.GetBytes(pwd);
            // Create an instance of Managed SHA256
            SHA256Managed hashman = new SHA256Managed();
            // Hash the array of bytes
            byte[] hash = hashman.ComputeHash(bytes);
            return hash;
        }

         /// <summary>
         /// This function is called when the user wants to encrypt a file
         /// </summary>
        void DESenc()
        {   
            // Create file streams for the input and output of the files
            FileStream fileInput = new FileStream(_input, FileMode.Open, FileAccess.Read);
            // Append the xNFCE extension to the output
            FileStream fileEncrypted = new FileStream(_output + GlobalValues.fextension, FileMode.Create, FileAccess.Write);

            // Declare an insrance of the DESCryptoServiceProvider class
            // This represents the actual encryption and decryption technology that is used on the files
            // Other cryptographic techniques can be used here
            // TODO implement other encryption techniques
            DESCryptoServiceProvider DES = new DESCryptoServiceProvider();

            // Each cryptographic technique takes a different syze key, DES takes a 64Bit key which is 8 Bytes (8 Characters)
            // If we do not provide a key and IV here, they are randomly generated, meaning we cannot decrypt the file
            // Take the first 8 bytes from the password
            DES.Key = _password.Take(8).ToArray();
            DES.IV =  _password.Take(8).ToArray();

            // Cretae an instance of the CryptoStream class by using the cryptographic prover to obtain an encrypting object
            // and the existing output filestream as part of the constructor.
            ICryptoTransform desencrypt = DES.CreateEncryptor();
            CryptoStream cryptostream = new CryptoStream(fileEncrypted, desencrypt, CryptoStreamMode.Write);

            // Read in the input file and write to the output file while passing through the crypto stream object using the password provided
            byte[] bytearrayinput = new byte[fileInput.Length - 1];
            fileInput.Read(bytearrayinput, 0, bytearrayinput.Length);
            cryptostream.Write(bytearrayinput, 0, bytearrayinput.Length);
        }


        /// <summary>
        /// This function is called when the user wants to decrypt a file
        /// </summary>
        void DESdec()
        {
            // This function has two key differences from the encrypt function
            // CreateDecryptor is used instead of CreateEncryptor to create the crypto stream object
            // When the decrypted text is written to the destination file, the CryptoStream object is now the source isntead of the destination stream
            DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
            // Take the first 8 bytes from the password
            DES.Key = _password.Take(8).ToArray();
            DES.IV =  _password.Take(8).ToArray();

            // Create the file stream to read the encrypted file back
            FileStream fileInput = new FileStream(_input, FileMode.Open, FileAccess.Read);
            // Create a DES decryptor
            ICryptoTransform desdecrypt = DES.CreateDecryptor();
            // Create a crypto stream set to read and do a decryption transform on incoming bytes
            CryptoStream cryptostream = new CryptoStream(fileInput, desdecrypt, CryptoStreamMode.Read);

            // Print the contents of the decrypted file
            FileInfo fi = new FileInfo(_output);
            string writename = Path.Combine(fi.DirectoryName, Path.GetFileNameWithoutExtension(_output));
            StreamWriter fsDecrypted = new StreamWriter(writename);
            fsDecrypted.Write(new StreamReader(cryptostream).ReadToEnd());
            fsDecrypted.Flush();
            fsDecrypted.Close();
        }

    }
}

注意:我为此使用 Xamarin.Android,但我认为它不相关

谢谢! :)

【问题讨论】:

  • 不要使用DES,它不安全,即使是3DES也不应该在新工作中使用,使用AES。也不要为密钥和 iv 使用相同的值,iv 不需要是秘密的,通常不是,密钥确实需要是秘密的。那就是“网上研究很多,不良信息很多,你要知道信息来源是知情的”的问题。

标签: c# android .net encryption xamarin


【解决方案1】:

问题是加密文件将是空的,因此您随后尝试解密一个空字符串会失败。

该文件为空,因为 CryptoStream 从未刷新到磁盘。

这与您没有处理任何东西的事实有关,您需要返回并将using () {} 子句添加到实现IDisposable 的任何东西(为CryptoStream 执行此操作将正确刷新它)。

作为最低

using (CryptoStream cryptostream = new CryptoStream(fileEncrypted, desencrypt, CryptoStreamMode.Write))
{
    // Read in the input file and write to the output file while passing through the crypto stream object using the password provided
    byte[] bytearrayinput = new byte[fileInput.Length - 1];
    fileInput.Read(bytearrayinput, 0, bytearrayinput.Length);

    cryptostream.Write(bytearrayinput, 0, bytearrayinput.Length);
}

将导致您的程序按预期运行。 (但仍然在其他地方泄漏)。

(不要对 key 和 iv 使用相同的值)

【讨论】:

  • 谢谢!这阻止了抛出异常,尽管输出文件似乎是输入文件大小的两倍并且不可读。怀疑这与这个问题有关。再次感谢!
  • 编辑:有什么替代方法可以不使用 key 和 iv 相同的值?我只希望用户必须输入一个密码,我应该采用哈希的不同部分吗?
猜你喜欢
  • 2014-07-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-15
  • 1970-01-01
  • 2011-05-29
  • 1970-01-01
相关资源
最近更新 更多