-
Notifications
You must be signed in to change notification settings - Fork 19
Home
The project is split into four main areas
- Strings – Encryption/Decryption/Password and Salt generation
- Hash – Creation and verification of hashes using MD5, SHA1, SHA256, SHA384, SHA512.
- Digest – Creation and verification of digests (data + hash). Plus two handy ToString() and CreateFromString() functions which come in handy if you want to store data in a Cookie.
- Bytes – The core of the library. This uses the Rijndael algorithm and works at the byte[] level for most functions.
If you like or are using this project please give it a star. Thanks!
This is a static class with static functions.
string CreatePassword(int size, bool allowPunctuation)
Creates a password with the required length. You can specify if you want to allow punctuation characters in the returned password. For more information on punctuation characters, see http://msdn.microsoft.com/en-us/library/6w3ahtyy.aspx
string password = Strings.CreatePassword(10, true);
// password = eE6/k1beps
allowPunctuation = false;
password = Strings.CreatePassword(10, false);
// password = 6kyGMrKNF6string CreateSalt(int numChars)
Create a salt of exactly the number of characters required. Under the hood, it calls CreateSaltFull() and trims the string to the required length.
string salt = Strings.CreateSalt(30);
int length = salt.Length; // length will be 30 charactersstring CreateSaltFull(int numBytes)
Create a salt. The numBytes is the number of non-zero random bytes that will converted into a base-64 string. The resulting string length can be larger than numBytes.
string salt = Strings.CreateSaltFull(30);
int length = salt.Length; // length will be 40 charactersstring Encrypt(string clearString, byte[] key, byte[] iv) string Decrypt(string cipherString, byte[] key, byte[] iv)
string plainText = "My secret text";
byte[] key = Bytes.GenerateKey();
byte[] iv = Bytes.GenerateIV();
string encrypted = Strings.Encrypt(plainText, key, iv);
string decrypted = Strings.Decrypt(encrypted, key, iv);
Assert.AreEqual(plainText, decrypted);string Encrypt(string clearString, string password, string salt, string iv, Bytes.KeySize keySize) string Decrypt(string cipherString, string password, string salt, string iv, Bytes.KeySize keySize)
string password = "Hello world"; // Preferably generated
string salt = "saltsaltsalt"; // Preferably generated
string iv = string.Empty.PadLeft(32, '#');
string plainText = "My secret text";
string encrypted = Strings.Encrypt(plainText, password, salt, iv, Bytes.KeySize.Size256);
string decrypted = Strings.Decrypt(encrypted, password, salt, iv, Bytes.KeySize.Size256);
Assert.AreEqual(plainText, decrypted);This is a static class with 2 static functions.
A hash can help ensure authentication and integrity of data that may be modified when transmitted between two parties. The sharedKey is shared by the two parties who independently calculate the hash. The data is passed between parties together with the hash. The hash will be identical if the data is unmodified. Use a sharedKey that is sufficiently long and complex for the application see https://www.grc.com/passwords.htm - and share the sharedKey once over a secure channel. See http://en.wikipedia.org/wiki/Cryptographic_hash_function for more information.
Looking at the code you will see that the Hash function uses Lazy loading of the five main hash algorithms. This is for performance and means only the hash algorithm asked for is created and loaded into memory.
The algorithms are: MD5 (128 bit), SHA1 (160 bit), SHA256 (256 bit), SHA384 (384 bit), SHA512 (512 bit)
public static string Create(HashType hashType, string data, string sharedKey, bool showBytes)
With showBytes = true we get:
string md5 = Hash.Create(HashType.MD5, "Hello", "key", true);
// result = 6E721FFDDD9974CC99A10A3D04385B33
string sha1 = Hash.Create(HashType.SHA1, "Hello", "key", true);
// result = E483166C1BCA40E5A1289D6416C6DE1A271F2ACE
string sha256 = Hash.Create(HashType.SHA256, "Hello", "key", true);
// result = C63338687D9BC4E95350C465D392DB3518C777AE3A04284005B358350767A710
string sha384 = Hash.Create(HashType.SHA384, "Hello", "key", true);
// result = 584BE855D030A6E25C07909751D3762429C3C811935CB57A34AD686F82FDAFAF1F72594BBE38CA0C95EDD2DD81E9035A
string sha512 = Hash.Create(HashType.SHA512, "Hello", "key", true);
// result = ABCB5D5F7DE874D6AB172E69106FEE23B9957CF074DDE23CD0A9A29D8E56E4EC0D73C42F63C633FFB68C8E8955F2C220EA97FF65C12402DFC9B2911422062842With showBytes = false we get:
string md5 = Hash.Create(HashType.MD5, "Hello", "key", false);
// result = bnIf/d2ZdMyZoQo9BDhbMw==
string sha1 = Hash.Create(HashType.SHA1, "Hello", "key", false);
// result = 5IMWbBvKQOWhKJ1kFsbeGicfKs4=
string sha256 = Hash.Create(HashType.SHA256, "Hello", "key", false);
// result = xjM4aH2bxOlTUMRl05LbNRjHd646BChABbNYNQdnpxA=
string sha384 = Hash.Create(HashType.SHA384, "Hello", "key", false);
// result = WEvoVdAwpuJcB5CXUdN2JCnDyBGTXLV6NK1ob4L9r68fcllLvjjKDJXt0t2B6QNa
string sha512 = Hash.Create(HashType.SHA512, "Hello", "key", false);
// result = q8tdX33odNarFy5pEG/uI7mVfPB03eI80KminY5W5OwNc8QvY8Yz/7aMjolV8sIg6pf/ZcEkAt/JspEUIgYoQg==With no sharedKey (just showing MD5 for brevity) we get:
string a = Hash.Create(HashType.MD5, "Hello", string.Empty, true);
// result = 8B1A9953C4611296A827ABF8C47804D7
string b = Hash.Create(HashType.MD5, "Hello", string.Empty, false);
// result = ixqZU8RhEpaoJ6v4xHgE1w==public static bool Verify(HashType hashType, string data, string sharedKey, bool showBytes, string hash)
string hash = Hash.Create(HashType.MD5, "Hello", string.Empty, true);
// result = 8B1A9953C4611296A827ABF8C47804D7
bool ok = Hash.Verify(HashType.MD5, "Hello", string.Empty, true, hash);
// result = true
ok = Hash.Verify(HashType.MD5, "World", string.Empty, true, hash);
// result = falseThe digest basically stores the data and hash together.
public Digest(string data, string hash, HashType hashType)
Constructor where you can define all the properties.
public string Data
Returns the data.
public string Hash
Returns the pre-computed hash.
public HashType HashType
Returns the hash type used to generate the hash
public static Digest Create(HashType hashType, string data, string sharedKey)
Static function to create a Digest.
Digest digest1 = Digest.Create(HashType.SHA512, "Hello", "secretKey");
// Check its reversable
var digest1String = digest1.ToString();
var digest2 = Digest.CreateFromString(digest1String, "secretKey");
Assert.AreEqual(digest1.Data, digest2.Data);
Assert.AreEqual(digest1.Hash, digest2.Hash);public override string ToString()
Returns a string in the following format: XXYYYHD Where XX is the hashType, YYYY is the length of the hash, H* is the hash, and D* is the data. This can be handy for storing in a cookie for instance.
Digest md5 = Digest.Create(HashType.MD5, "Hello", "secretKey");
var md5String = md5.ToString();
// md5String = 0003274E5D61D5FEA40EA042E1C1954A4356EHello
Digest sha1 = Digest.Create(HashType.SHA1, "Hello", "secretKey");
var sha1String = sha1.ToString();
// sha1String = 0104012245A5A5C8CC2FD25A2745F2036B98C9308C112Hellopublic static Digest CreateFromString(string hashedData, string sharedKey)
This is the opposite of ToString(). It takes the data and re-creates the Digest. If the data passed in does not pass Hash validation, then null is returned.
The examples below will use the following data setup.
string _fileEncryptedData = @"C:\testEncrypted.txt");
string _filePlainData = @"C:\testPlain.txt");
byte[] _plainData = GetBytes("Lorem ipsum dolor sit amet, consectetur adipiscing elit.");
var _rijndaelManaged = new RijndaelManaged
{
KeySize = 256,
BlockSize = 256,
Padding = PaddingMode.ISO10126,
Mode = CipherMode.CBC
};public static byte[] GenerateKey()
Returns an encryption key to be used with the Rijndael algorithm
byte[] key = Bytes.GenerateKey();public static byte[] GenerateKey(string password, string salt, KeySize keySize, int iterationCount)
Returns an encryption key to be used with the Rijndael algorithm. This used the function Rfc2898DeriveBytes which is used to generate a password-based key derivation functionality, PBKDF2, by using a pseudo-random number generator based on HMACSHA1.
byte[] key = Bytes.GenerateKey("password", "saltsaltsalt", Bytes.KeySize.Size128, 12000);public static byte[] GenerateIV()
Returns the encryption IV to be used with the Rijndael algorithm
byte[] iv = Bytes.GenerateIV();public static byte[] Encrypt(byte[] clearData, byte[] key, byte[] iv)
public static byte[] Decrypt(byte[] cipherData, byte[] key, byte[] iv)
Encrypt/Decrypt byte array into a byte array using the given Key and an IV.
byte[] key = Bytes.GenerateKey();
byte[] iv = Bytes.GenerateIV();
var rng = new RNGCryptoServiceProvider();
var data = new byte[1024];
rng.GetBytes(data);
byte[] encrypted = Bytes.Encrypt(data, key, iv);
byte[] decrypted = Bytes.Decrypt(encrypted, key, iv);
Assert.AreEqual(data, decrypted);public static void Encrypt(Stream clearStreamIn, string encryptedFileOut, RijndaelManaged alg)
public static void Decrypt(Stream encryptedStreamIn, Stream clearStreamOut, RijndaelManaged alg)
Encrypt/Decrypt a file into another file.
// Encrypt file
using(var fsIn = new FileStream(_filePlainData, FileMode.Open, FileAccess.Read))
{
Bytes.Encrypt(fsIn, _fileEncryptedData, _rijndaelManaged);
}
// Decrypt file data
using(var memoryStream = new MemoryStream())
{
using(var fsIn = new FileStream(_fileEncryptedData, FileMode.Open, FileAccess.Read))
{
Bytes.Decrypt(fsIn, memoryStream, _rijndaelManaged);
}
// Verify
memoryStream.Seek(0, SeekOrigin.Begin);
Assert.AreEqual(_plainData.Length, memoryStream.Length);
foreach(var expected in _plainData)
{
var b = memoryStream.ReadByte();
Assert.AreEqual(expected, b);
}
}public static void Encrypt(string clearFileIn, string encryptedFileOut, byte[] key, byte[] iv)
public static void Decrypt(string encryptedFileIn, string clearFileOut, byte[] key, byte[] iv)
Encrypt/Decrypt a file into another file
byte[] key = Bytes.GenerateKey();
byte[] iv = Bytes.GenerateIV();
Bytes.Encrypt(_filePlainData, _fileEncryptedData, key, iv);
Bytes.Decrypt(_fileEncryptedData, _filePlainData, key, iv);
var decryptedData = File.ReadAllBytes(_filePlainData);
Assert.AreEqual(_plainData.Length, decryptedData.Length);
for(int i = 0; i < _plainData.Length; i++)
{
Assert.AreEqual(_plainData[i], decryptedData[i]);
}public static void Encrypt(Stream clearStreamIn, string encryptedFileOut, byte[] key, byte[] iv)
Encrypt a stream into a file. This is a wrapper function for Encrypt(Stream clearStreamIn, string encryptedFileOut, RijndaelManaged alg)
public static void Encrypt(string clearFileIn, string encryptedFileOut, out string key, out string iv)
public static void Decrypt(string encryptedFileIn, string clearFileOut, string key, string iv)
Encrypt/Decrypt a file into another file. The Key and an IV are automatically generated. These will be required when Decrypting the data.
string key, iv;
Bytes.Encrypt(_filePlainData, _fileEncryptedData, out key, out iv);
Bytes.Decrypt(_fileEncryptedData, _filePlainData, key, iv);
var decryptedData = File.ReadAllBytes(_filePlainData);
Assert.AreEqual(_plainData.Length, decryptedData.Length);
for(int i = 0; i < _plainData.Length; i++)
{
Assert.AreEqual(_plainData[i], decryptedData[i]);
}public static void Encrypt(Stream clearStreamIn, string encryptedFileOut, out string key, out string iv)
public static void Decrypt(string encryptedFileIn, Stream clearStreamOut, string key, string iv)
Encrypt/Decrypt a file into another file. The Key and an IV are automatically generated. These will be required when Decrypting the data.
// Encrypt file
string key, iv;
using(var fsIn = new FileStream(_filePlainData, FileMode.Open, FileAccess.Read))
{
Bytes.Encrypt(fsIn, _fileEncryptedData, out key, out iv);
}
// Decrypt file data
using(var memoryStream = new MemoryStream())
{
Bytes.Decrypt(_fileEncryptedData, memoryStream, key, iv);
// Verify
memoryStream.Seek(0, SeekOrigin.Begin);
Assert.AreEqual(_plainData.Length, memoryStream.Length);
foreach(var expected in _plainData)
{
var b = memoryStream.ReadByte();
Assert.AreEqual(expected, b);
}
}