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.
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:
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. Some of the major improvements over the article are:
- Proper creation of a key
- Current algorithm (AES 256-bit key)
- Random IV
- Buffered file access instead of reading/writing the entire file in one chunk
- Wrapping all the disposable objects in
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. 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). 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. The purpose of a random IV is so the same plaintext file will encrypt into a different encrypted file every time you run it.
The Main
method here demonstrates encryption with a random key. 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.