Skip to content

Instantly share code, notes, and snippets.

@patsissons
Created September 9, 2014 02:37
Show Gist options
  • Save patsissons/a80fef566a4d55988f14 to your computer and use it in GitHub Desktop.
Save patsissons/a80fef566a4d55988f14 to your computer and use it in GitHub Desktop.
Extension methods to easily and efficiently convert a file to a compressed, password encrypted byte array (and back)
// I had a requirement to read a file from local storage, compress the content, the encrypt the data with a password.
// There are many ways to do this, but I wanted to do it the most efficient and elegant way possible.
// This method takes advantage of using Streams (which pipe data between streams), which gives us a clean and efficient solution.
// I am using all the generally accepted best practices to accomplish the task at hand.
// I have implemented the solution as an extension method to simplify usage.
public static partial class ExtensionMethods
{
#region File Encryption / Decryption
// WARN: this is an empty salt, create your own random salt using
// System.Security.Cryptography.RNGCryptoServiceProvider.GetNonZeroBytes(byte[])
private static readonly byte[] Salt = new byte[] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
public static byte[] GetEncryptedContent(this FileInfo source, string password, byte[] salt = null, int iterations = 1000)
{
byte[] buffer = null;
if (source != null)
{
source.Refresh();
if (source.Exists)
{
using (var ms = new MemoryStream())
using (var crypt = Rijndael.Create())
using (var pdb = new Rfc2898DeriveBytes(password, salt ?? DefaultSalt, iterations))
{
crypt.Key = pdb.GetBytes(32);
crypt.IV = pdb.GetBytes(16);
using (var crypts = new CryptoStream(ms, crypt.CreateEncryptor(), CryptoStreamMode.Write))
using (var gzip = new GZipStream(crypts, CompressionLevel.Optimal))
using (var fs = source.OpenRead())
{
fs.CopyTo(gzip);
}
buffer = ms.ToArray();
}
}
}
return buffer;
}
public static void SaveDecryptedContent(this FileInfo source, byte[] buffer, string password, byte[] salt = null, int iterations = 1000)
{
if (source != null && buffer != null && buffer.Length > 0)
{
using (var ms = new MemoryStream(buffer))
using (var crypt = Rijndael.Create())
using (var pdb = new Rfc2898DeriveBytes(password, salt ?? DefaultSalt, iterations))
{
crypt.Key = pdb.GetBytes(32);
crypt.IV = pdb.GetBytes(16);
using (var crypts = new CryptoStream(ms, crypt.CreateDecryptor(), CryptoStreamMode.Read))
using (var gzip = new GZipStream(crypts, CompressionMode.Decompress))
using (var fs = source.OpenWrite())
{
gzip.CopyTo(fs);
// set the end of the file at the current position (trim off what remains in the buffer from being written to the file)
fs.SetLength(fs.Position);
}
}
}
}
#endregion
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment