C#DES文件解密破坏非文本文件

时间:2013-10-18 22:46:38

标签: c# encryption des

我有两种方法,几乎​​是来自http://support.microsoft.com/kb/307010的复制+粘贴。

当我解密文件时,如果它们是任何类型的文本文件,如.txt,.xml,.html等,我可以打开它们,一切都很好。任何类型的文件,不仅仅是文本,如.exe,.jpg,.pdf等,都会在解密时中断。有什么我做错了吗?这些方法是否使用二进制来加密/解密文件?如果没有,我可以把它变为二进制吗?

非常感谢任何帮助!

public static void EncryptFile(string sInputFilename,
       string sOutputFilename,
       string sKey)
    {
        FileStream fsInput = new FileStream(sInputFilename,
           FileMode.Open,
           FileAccess.Read);

        FileStream fsEncrypted = new FileStream(sOutputFilename,
           FileMode.Create,
           FileAccess.Write);
        DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
        DES.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
        DES.IV = ASCIIEncoding.ASCII.GetBytes(sKey);
        ICryptoTransform desencrypt = DES.CreateEncryptor();
        CryptoStream cryptostream = new CryptoStream(fsEncrypted,
           desencrypt,
           CryptoStreamMode.Write);

        byte[] bytearrayinput = new byte[fsInput.Length];
        fsInput.Read(bytearrayinput, 0, bytearrayinput.Length);
        cryptostream.Write(bytearrayinput, 0, bytearrayinput.Length);
        cryptostream.Close();
        fsInput.Close();
        fsEncrypted.Close();
    }

    public static void DecryptFile(string sInputFilename,
       string sOutputFilename,
       string sKey)
    {
        DESCryptoServiceProvider DES = new DESCryptoServiceProvider();
        //A 64 bit key and IV is required for this provider.
        //Set secret key For DES algorithm.
        DES.Key = ASCIIEncoding.ASCII.GetBytes(sKey);
        //Set initialization vector.
        DES.IV = ASCIIEncoding.ASCII.GetBytes(sKey);

        //Create a file stream to read the encrypted file back.
        FileStream fsread = new FileStream(sInputFilename,
           FileMode.Open,
           FileAccess.Read);
        //Create a DES decryptor from the DES instance.
        ICryptoTransform desdecrypt = DES.CreateDecryptor();
        //Create crypto stream set to read and do a 
        //DES decryption transform on incoming bytes.
        CryptoStream cryptostreamDecr = new CryptoStream(fsread,
           desdecrypt,
           CryptoStreamMode.Read);
        //Print the contents of the decrypted file.
        StreamWriter fsDecrypted = new StreamWriter(sOutputFilename);
        fsDecrypted.Write(new StreamReader(cryptostreamDecr).ReadToEnd());
        fsDecrypted.Flush();
        fsDecrypted.Close();
        fsread.Close();
        cryptostreamDecr.Close();
    }

1 个答案:

答案 0 :(得分:3)

我不知道写那篇文章的人吸烟了,但是:

DESCryptoServiceProvider desCrypto =
   (DESCryptoServiceProvider)DESCryptoServiceProvider.Create();

return ASCIIEncoding.ASCII.GetString(desCrypto.Key);

不会为您提供有效密钥。至少有一个问题是,您用于加密的密钥与您用于解密的密钥不同,因为您无法将字节转换为ASCII并将其转换回来。

如果您想将密钥视为字符串,您可能需要的是:

string keyAsString = Convert.ToBase64String(desCrypto.Key);

然后当你想把它变回字节而不是ASCIIEncoding.ASCII.GetBytes时,你会做:

byte[] key = Convert.FromBase64String(keyAsString);

修改

这篇文章也有更多错误。我会说忽略那一个并找到一个更好的例子。

修改

这是我用于标准加密需求的非常干净的基本AES工作示例。本文的一些主要改进是:

  • 正确创建密钥
  • 当前算法(AES 256位密钥)
  • Random IV
  • 缓冲文件访问,而不是在一个块中读/写整个文件
  • using
  • 中包装所有一次性物品

除此之外,它的基本理念相同。

using System;
using System.IO;
using System.Security.Cryptography;

namespace ConsoleApplication12
{
    class Program
    {
        private const int KEY_SIZE_BYTES = 32;
        private const int IV_SIZE_BYTES = 16;

        static void Main(string[] args)
        {
            var rand = new Random();
            using (var fs = File.Open(@"C:\temp\input.bin", FileMode.Create, FileAccess.Write, FileShare.None))
            {
                byte[] buffer = new byte[10000];
                for (int i = 0; i < 100; ++i)
                {
                    rand.NextBytes(buffer);
                    fs.Write(buffer, 0, buffer.Length);
                }
            }
            string key = GenerateRandomKey();
            Encrypt(@"C:\temp\input.bin", @"C:\temp\encrypted.bin", key);
            Decrypt(@"C:\temp\encrypted.bin", @"C:\temp\decyrypted.bin", key);
        }

        static string GenerateRandomKey()
        {
            byte[] key = new byte[KEY_SIZE_BYTES];
            using (var rng = RandomNumberGenerator.Create())
            {
                rng.GetBytes(key);
            }
            return Convert.ToBase64String(key);
        }

        static void Encrypt(string inputFile, string outputFile, string key)
        {
            const int BUFFER_SIZE = 8192;
            byte[] buffer = new byte[BUFFER_SIZE];
            byte[] keyBytes = Convert.FromBase64String(key);
            byte[] ivBytes = new byte[IV_SIZE_BYTES];
            using (var rng = RandomNumberGenerator.Create())
            {
                rng.GetBytes(ivBytes);
            }
            using (var inputStream = File.Open(inputFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                using (var outputStream = File.Open(outputFile, FileMode.Create, FileAccess.Write, FileShare.None))
                {
                    outputStream.Write(ivBytes, 0, ivBytes.Length);
                    using (var cryptoAlgo = Aes.Create())
                    {
                        using (var encryptor = cryptoAlgo.CreateEncryptor(keyBytes, ivBytes))
                        {
                            using (var cryptoStream = new CryptoStream(outputStream, encryptor, CryptoStreamMode.Write))
                            {
                                int count;
                                while ((count = inputStream.Read(buffer, 0, buffer.Length)) > 0)
                                {
                                    cryptoStream.Write(buffer, 0, count);
                                }
                            }
                        }
                    }
                }
            }
        }

        static void Decrypt(string inputFile, string outputFile, string key)
        {
            const int BUFFER_SIZE = 8192;
            byte[] buffer = new byte[BUFFER_SIZE];
            byte[] keyBytes = Convert.FromBase64String(key);
            byte[] ivBytes = new byte[IV_SIZE_BYTES];
            using (var inputStream = File.Open(inputFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                inputStream.Read(ivBytes, 0, ivBytes.Length);
                using (var outputStream = File.Open(outputFile, FileMode.Create, FileAccess.Write, FileShare.None))
                {
                    using (var cryptoAlgo = Aes.Create())
                    {
                        using (var decryptor = cryptoAlgo.CreateDecryptor(keyBytes, ivBytes))
                        {
                            using (var cryptoStream = new CryptoStream(inputStream, decryptor, CryptoStreamMode.Read))
                            {
                                int count;
                                while ((count = cryptoStream.Read(buffer, 0, buffer.Length)) > 0)
                                {
                                    outputStream.Write(buffer, 0, count);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

因为IV是随机的,所以你会发现技术上的另一个小差异。在加密文件时,首先将IV写入加密文件(它不是秘密,所以你直接写出来)。解密文件时,读取前几个字节以检索IV,然后文件的其余部分包含实际的加密数据。随机IV的目的是每次运行时,相同的纯文本文件都会加密成不同的加密文件。

此处的Main方法使用随机密钥演示加密。如果你想使用密码,它可以做更多的工作,但你可以用十几个额外的代码行来实现PBKDF2。