简体   繁体   English

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

[英]C# DES File Decryption Breaking Non-Text Files

I have these two methods which are pretty much copy+pastes from http://support.microsoft.com/kb/307010 . 我有这两种方法,几乎​​是来自http://support.microsoft.com/kb/307010的复制+粘贴。

When I decrypt the files, if they are any type of text file such as .txt, .xml, .html, etc. I can open them up and everything is fine. 当我解密文件时,如果它们是任何类型的文本文件,如.txt,.xml,.html等,我可以打开它们,一切都很好。 Any type of file not just text, such as .exe, .jpg, .pdf, etc. all break when decrypted. 任何类型的文件,不仅仅是文本,如.exe,.jpg,.pdf等,都会在解密时中断。 Is there anything I am doing wrong? 有什么我做错了吗? Are these methods using binary to encrypt/decrypt the files? 这些方法是否使用二进制来加密/解密文件? If not is there a way I can make it binary? 如果没有,我有办法让它二进制吗?

Any help is greatly appreciated! 任何帮助是极大的赞赏!

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();
    }

I don't know what the guy that wrote that article was smoking, but: 我不知道写那篇文章的人是吸烟的,但是:

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

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

will not get you a valid key. 不会给你一个有效的钥匙。 At least one problem is the fact that the key you use to encrypt is not the same key that you're using to decrypt, because you can't convert bytes to ASCII and back like that. 至少有一个问题是,您用于加密的密钥与您用于解密的密钥不同,因为您无法将字节转换为ASCII并返回。

If you want to treat the key as a string, what you probably want is: 如果您想将密钥视为字符串,您可能需要的是:

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

Then when you want to turn it back into bytes, instead of ASCIIEncoding.ASCII.GetBytes , you'll do: 然后当你想把它变成字节而不是ASCIIEncoding.ASCII.GetBytes ,你会做:

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

EDIT 编辑

There's a ton more wrong with that article too. 这篇文章也有更多错误。 I'd say ignore that one and find a better example. 我会说忽略那一个并找到一个更好的例子。

EDIT 编辑

Here's a very clean basic AES working example that I use for my standard encryption needs. 这是我用于标准加密需求的非常干净的基本AES工作示例。 Some of the major improvements over the article are: 本文的一些主要改进是:

  • Proper creation of a key 正确创建密钥
  • Current algorithm (AES 256-bit key) 当前算法(AES 256位密钥)
  • Random IV 随机IV
  • Buffered file access instead of reading/writing the entire file in one chunk 缓冲文件访问,而不是在一个块中读/写整个文件
  • Wrapping all the disposable objects in using using包裹所有一次性物体

Aside from that, it's the same basic idea. 除此之外,它是相同的基本想法。

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);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

Because the IV is random, you'll see another small difference in technique. 因为IV是随机的,你会看到技术上的另一个小差异。 When encrypting the file, you first write the IV to the encrypted file (it's not a secret, so you just write it straight out). 在加密文件时,首先将IV写入加密文件(这不是秘密,所以你只需直接写出来)。 When decrypting the file, you read the first few bytes to retrieve the IV, then the rest of the file contains the actual encrypted data. 解密文件时,读取前几个字节以检索IV,然后文件的其余部分包含实际的加密数据。 The purpose of a random IV is so the same plaintext file will encrypt into a different encrypted file every time you run it. 随机IV的目的是每次运行时,相同的纯文本文件都会加密成不同的加密文件。

The Main method here demonstrates encryption with a random key. 此处的Main方法使用随机密钥演示加密。 If you want to use a password, it's a little more work, but you can implement PBKDF2 with maybe a dozen or so extra lines of code. 如果你想使用密码,那就更多了,但你可以用十几个额外的代码行来实现PBKDF2。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM