asp
For each of those, there is also a corresponding Decrypt function. The Main method is a simple
testing method that exercises some of those functions. The 2nd and the 3rd Encrypt functions
call into the 1st function, so you will need to carry the 1st one around if you are using the 2nd or
the 3rd. The last Encrypt function (the one that works with files) is standalone. I made it
operate in a stream-like manner, without reading the whole file into memory, which makes it
possible to encrypt/decrypt gigabytes of data without going out of memory space.
I am using Rijndael algorithm in this sample. The reason for this is that it is 100% implemented
in managed code in our libraries, so it does not rely on CryptoAPI or any encryption packs
and will work everywhere. If you need performance, I would suggest replacing it with TripleDES
(it is a one line change), and if you do, also do not forget to change the IV size to 8 bytes and the
Key size to 16 bytes.
I have tried to document the code well, and I would like to encourage you to read through it and
understand how it works, it should be pretty easy. You can also grab the whole thing, stick it into
a .cs file and it should compile. If you run it, you will see it make some test encryption/decryption
roundtrip; you can also provide a file name as a parameter, and it will encrypt the file into a
<name>.encrypted file and then decrypt it back into a <name>.decrypted.
Enjoy!
P.S. A crypto-related FAQ can be found here and there is a good chapter on how to use crypto in
"Writing Secure Code" by Michael Howard (2nd edition came out recently). For in depth
information on crypto in general, "Applied Cryptography" by Bruce Schneier is an excellent
resource.
Collapse
//
using System;
using System.IO;
using System.Security.Cryptography;
//
// Sample encrypt/decrypt functions
// Parameter checks and error handling
// are ommited for better readability
//
// There is also a mode called ECB which does not need an IV,
// but it is much less secure.
alg.Key = Key;
alg.IV = IV;
return encryptedData;
}
// Now get the key/IV and do the encryption using the function
// that accepts byte arrays.
// Using PasswordDeriveBytes object we are first getting
// 32 bytes for the Key
// (the default Rijndael key length is 256bit = 32bytes)
// and then 16 bytes for the IV.
// IV should always be the block size, which is by default
// 16 bytes (128 bit) for Rijndael.
// If you are using DES/TripleDES/RC2 the block size is 8
// bytes and so should be the IV size.
// You can also read KeySize/BlockSize properties off the
// algorithm to find out the sizes.
return Encrypt(clearData, pdb.GetBytes(32), pdb.GetBytes(16));
do {
// read a chunk of data from the input file
bytesRead = fsIn.Read(buffer, 0, bufferLen);
// encrypt it
cs.Write(buffer, 0, bytesRead);
} while(bytesRead != 0);
// close everything
return decryptedData;
}
// Decrypt a string into a string using a password
// Uses Decrypt(byte[], byte[], byte[])
alg.Key = pdb.GetBytes(32);
alg.IV = pdb.GetBytes(16);
do {
// read a chunk of data from the input file
bytesRead = fsIn.Read(buffer, 0, bufferLen);
// Decrypt it
cs.Write(buffer, 0, bytesRead);
} while(bytesRead != 0);
// close everything
cs.Close(); // this will also close the unrelying fsOut stream
fsIn.Close();
}
}
Need a Main method to make this code complete? Write your own (it's quite simple) or visit this
site, find this article there and grab it.
The encryption sample above had a very defined purpose - being extremely easy to read and
understand. While it explains how to use symmetric encryption classes and gives some ideas on
how to start implementing encryption in your applications, there are things you will have to do
before it becomes a shippable piece of code. One of them I have already mentioned in the
posting below - parameter checking and error handling. Check the parameters for being valid,
wrap calls that can potentially fail into try/catch blocks, use finally blocks to release
resources (close files) if something goes wrong, etc.
Some cryptography specific considerations should also be there. For example, the salt values in
PasswordDeriveBytes should better be random rather than hard coded (sometimes it is ok to
have them hard coded, for example, when encryption happens rarely and the code is not
accessible by attackers). If the salt is random and changed frequently, you don't even have to
keep it secret. Also, when possible, use byte[] keys as opposed to passwords. Because of the
human factor, password-based encryption is not the most secure way to protect information. In
order to get 128bit of key information out of a password, it has to be long. If you are using just
small letters that give you about 5 bits of information per character and your password will have
to be over 25 characters long to get to 128bit. If you are using capital letters and some symbols
you can get to about 7 bits per character and your password minimum length will have to be
around 18 characters (how long is your password? ;-)).