1

我有这两种方法,它们几乎是来自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();
    }
4

1 回答 1

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 位密钥)
  • 随机四
  • 缓冲文件访问,而不是在一个块中读取/写入整个文件
  • 把所有的一次性物品都包起来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。

于 2013-10-18T22:56:03.040 回答