C#Bad PKCS7填充

时间:2016-02-11 13:16:11

标签: c# android .net encryption xamarin

我在尝试实现DES加密和解密时遇到错误(虽然我的代码允许不同的实现)

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

以下是我的代码,#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,但我不相信它是相关的

谢谢! :)

1 个答案:

答案 0 :(得分:2)

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

该文件为空,因为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);
}

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

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