user1307346
user1307346

Reputation: 765

Encrypt a file using File.Encrypt and then Decrypt it to memory stream

I need to implement a simple file encryption and then decrypt it, when needed, to a memory stream. The easiest way seems to do this with File.Encrypt, but is it possible to decrypt the file to memory stream, instead of decrypting the file before reading it to memory stream, and thus exposing it for a while?

And if File.Encrypt is not the best way for this scenario, what would you recommend?

Upvotes: 6

Views: 22087

Answers (3)

Immortal Blue
Immortal Blue

Reputation: 1700

This was the first encryption code I wrote - be warned, although a good starting point to understand what's going on, static passwords and static salts are a bad idea! (thanks for highlighting this CodesInChaos)

You can decrypt to any stream you like, including straight to a memory stream...

FileInfo file = new FileInfo("SomeFile");
using (FileStream inFs = file.OpenRead())
{
    using (MemoryStream outMs = new MemoryStream())
    {
        encryption.Decrypt(inFs, outMs);                    

        BinaryFormatter bf = new BinaryFormatter();
        targetType target= bf.Deserialize(outMs) as targetType;
    }
}

where encryption is one of these:

public class EncryptionHelper
{        
    static SymmetricAlgorithm encryption; 
    static string password = "password";
    static string salt = "this is my salt. There are many like it, but this one is mine.";

    static EncryptionHelper()
    {
        encryption = new RijndaelManaged();
        Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(password, Encoding.ASCII.GetBytes(salt));

        encryption.Key = key.GetBytes(encryption.KeySize / 8);
        encryption.IV = key.GetBytes(encryption.BlockSize / 8);
        encryption.Padding = PaddingMode.PKCS7;
    }

    public void Encrypt(Stream inStream, Stream OutStream)
    {
        ICryptoTransform encryptor = encryption.CreateEncryptor();
        inStream.Position = 0;
        CryptoStream encryptStream = new CryptoStream(OutStream, encryptor, CryptoStreamMode.Write);
        inStream.CopyTo(encryptStream);
        encryptStream.FlushFinalBlock();

    }


    public void Decrypt(Stream inStream, Stream OutStream)
    {
        ICryptoTransform encryptor = encryption.CreateDecryptor();
        inStream.Position = 0;
        CryptoStream encryptStream = new CryptoStream(inStream, encryptor, CryptoStreamMode.Read);
        encryptStream.CopyTo(OutStream);
        OutStream.Position = 0;  
    }
}

Upvotes: 1

sircodesalot
sircodesalot

Reputation: 11439

File.Encrypt is an OS feature but it sounds like really you want to control how the encryption is done.

http://msdn.microsoft.com/en-us/library/system.io.file.encrypt.aspx

// This is where the data will be written do.
MemoryStream dataStream = new MemoryStream();

// The encryption vectors
byte[] key = {145,12,32,245,98,132,98,214,6,77,131,44,221,3,9,50};
byte[] iv  = {15,122,132,5,93,198,44,31,9,39,241,49,250,188,80,7};

// Build the encryption mathematician
using (TripleDESCryptoServiceProvider encryption = new TripleDESCryptoServiceProvider())
using (ICryptoTransform transform = encryption.CreateEncryptor(key, iv))
using (Stream encryptedOutputStream = new CryptoStream(dataStream, transform, CryptoStreamMode.Write))
using (StreamWriter writer = new StreamWriter(encryptedOutputStream))
{
    // In this block, you do your writing, and it will automatically be encrypted
    writer.Write("This is the encrypted output data I want to write");
}

Encryption is not for the faint of heart. Be forewarned though, you really should have a strong sense of regular IO and data streams before you attempt this though.

Upvotes: 2

jbtule
jbtule

Reputation: 31799

Implementing Crypto deceptively easy, and actually rather tedious, there are a lot of details, and the details wrong are usually what's exploited security wise. The best practice is to use a high level encryption framework that hides these details ivs, salts, mac, comparisons, padding, key rotation, and while it's not improbable for high level frameworks to have the details wrong, when they do, they get found and fixed, the code snippets on stack overflow generally do not.

I have been porting the Google Keyczar framework so such a high level library would exist for C#.

Keyczar-dotnet

And it is usable for encrypting and decrypting io streams.

Install in your project with nuget

PM> Install-Package Keyczar -Pre

Then create your key set. (by having a separate key set file, it gives you the ability to rotating keys in the future and prevents you from accidentally hard coding something that should not ever be hard coded.)

PM> KeyczarTool.exe create --location=path_to_key_set --purpose=crypt
PM> KeyczarTool.exe addkey --location=path_to_key_set --status=primary

Then in your code you can use any IO stream you want for both encryption:

using(var encrypter = new Encrypter("path_to_key_set"))
{
     encrypter.Encrypt(plaintextStream, ciphertextStream);
}

and decryption:

using(var crypter = new Crypter("path_to_key_set"))
{
     crypter.Decrypt(ciphertextStream, plaintextStream);
}

Upvotes: 1

Related Questions