///////////////////////////////////////////////////////////////////////////////////////////////
//
// This File is Part of the CallButler Open Source PBX (http://www.codeplex.com/callbutler
//
// Copyright (c) 2005-2008, Jim Heising
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or
// other materials provided with the distribution.
//
// * Neither the name of Jim Heising nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific prior
// written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////////////////////////
using System;
using System.Security.Cryptography;
using System.Text;
using System.Globalization;
using System.IO;
namespace WOSI.Utilities
{
///
/// Summary description for CryptoUtils.
///
public class CryptoUtils
{
public static byte[] Encrypt(byte[] clearData, byte[] Key, byte[] IV)
{
// Create a MemoryStream to accept the encrypted bytes
MemoryStream ms = new MemoryStream();
// Create a symmetric algorithm.
// We are going to use Rijndael because it is strong and
// available on all platforms.
// You can use other algorithms, to do so substitute the
// next line with something like
// TripleDES alg = TripleDES.Create();
Rijndael alg = Rijndael.Create();
// Now set the key and the IV.
// We need the IV (Initialization Vector) because
// the algorithm is operating in its default
// mode called CBC (Cipher Block Chaining).
// The IV is XORed with the first block (8 byte)
// of the data before it is encrypted, and then each
// encrypted block is XORed with the
// following block of plaintext.
// This is done to make encryption more secure.
// 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;
// Create a CryptoStream through which we are going to be
// pumping our data.
// CryptoStreamMode.Write means that we are going to be
// writing data to the stream and the output will be written
// in the MemoryStream we have provided.
CryptoStream cs = new CryptoStream(ms,
alg.CreateEncryptor(), CryptoStreamMode.Write);
// Write the data and make it do the encryption
cs.Write(clearData, 0, clearData.Length);
// Close the crypto stream (or do FlushFinalBlock).
// This will tell it that we have done our encryption and
// there is no more data coming in,
// and it is now a good time to apply the padding and
// finalize the encryption process.
cs.Close();
// Now get the encrypted data from the MemoryStream.
// Some people make a mistake of using GetBuffer() here,
// which is not the right way.
byte[] encryptedData = ms.ToArray();
return encryptedData;
}
// Encrypt a string into a string using a password
// Uses Encrypt(byte[], byte[], byte[])
public static string Encrypt(string clearText, string Password)
{
// First we need to turn the input string into a byte array.
byte[] clearBytes =
System.Text.Encoding.Unicode.GetBytes(clearText);
// Then, we need to turn the password into Key and IV
// We are using salt to make it harder to guess our key
// using a dictionary attack -
// trying to guess a password by enumerating all possible words.
PasswordDeriveBytes pdb = new PasswordDeriveBytes(Password,
new byte[] {0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d,
0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76});
// 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.
byte[] encryptedData = Encrypt(clearBytes,
pdb.GetBytes(32), pdb.GetBytes(16));
// Now we need to turn the resulting byte array into a string.
// A common mistake would be to use an Encoding class for that.
//It does not work because not all byte values can be
// represented by characters.
// We are going to be using Base64 encoding that is designed
//exactly for what we are trying to do.
return Convert.ToBase64String(encryptedData);
}
// Encrypt bytes into bytes using a password
// Uses Encrypt(byte[], byte[], byte[])
public static byte[] Encrypt(byte[] clearData, string Password)
{
// We need to turn the password into Key and IV.
// We are using salt to make it harder to guess our key
// using a dictionary attack -
// trying to guess a password by enumerating all possible words.
PasswordDeriveBytes pdb = new PasswordDeriveBytes(Password,
new byte[] {0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d,
0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76});
// 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));
}
// Encrypt a file into another file using a password
public static void Encrypt(string fileIn,
string fileOut, string Password)
{
// First we are going to open the file streams
FileStream fsIn = new FileStream(fileIn,
FileMode.Open, FileAccess.Read);
FileStream fsOut = new FileStream(fileOut,
FileMode.OpenOrCreate, FileAccess.Write);
// Then we are going to derive a Key and an IV from the
// Password and create an algorithm
PasswordDeriveBytes pdb = new PasswordDeriveBytes(Password,
new byte[] {0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d,
0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76});
Rijndael alg = Rijndael.Create();
alg.Key = pdb.GetBytes(32);
alg.IV = pdb.GetBytes(16);
// Now create a crypto stream through which we are going
// to be pumping data.
// Our fileOut is going to be receiving the encrypted bytes.
CryptoStream cs = new CryptoStream(fsOut,
alg.CreateEncryptor(), CryptoStreamMode.Write);
// Now will will initialize a buffer and will be processing
// the input file in chunks.
// This is done to avoid reading the whole file (which can
// be huge) into memory.
int bufferLen = 4096;
byte[] buffer = new byte[bufferLen];
int bytesRead;
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
// this will also close the unrelying fsOut stream
cs.Close();
fsIn.Close();
}
}
}