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

21,450

Solution 1

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.

Solution 2

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);
}

Solution 3

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;  
    }
}
Share:
21,450

Related videos on Youtube

user1307346
Author by

user1307346

Updated on September 11, 2020

Comments

  • user1307346
    user1307346 over 3 years

    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?

    • SLaks
      SLaks about 11 years
      What are you trying to defend against?
    • John Saunders
      John Saunders about 11 years
      I have edited your title. Please see, "Should questions include “tags” in their titles?", where the consensus is "no, they should not".
    • CodesInChaos
      CodesInChaos about 11 years
      I think File.Encrypt sets a file system level flag. So if you call File.Encrypt on an empty file, and then write to it, the plaintext is probably never written to the disk.
  • sircodesalot
    sircodesalot about 11 years
    Heh, I like your salt comment. Speaking of which, how does a salt work? I get what it's purpose is, but can you point me in the direction of a resource that explains how it functions?
  • CodesInChaos
    CodesInChaos about 11 years
    Mistakes 1) A per application salt, instead of a per-encryption salt 2) A static password 3) No MAC => Padding oracles 4) constant IV (wouldn't be a problem if you used a proper salt, but you don't)
  • Immortal Blue
    Immortal Blue about 11 years
    @CodesInChaos, you are exactly correct (apart from I think I am setting an IV?) this is the first encryption code I ever wrote, so I thought it would be a useful start.
  • CodesInChaos
    CodesInChaos about 11 years
    You should never reuse a (key, iv) pair. Since your salt is constant, a password will generate the (key, iv) pair deterministically, so your IV is useless. If you use a random salt, then keys will be unique, and thus the IV isn't really necessary anymore.
  • Immortal Blue
    Immortal Blue about 11 years
    Also, didn't know you could nest usings like that!
  • Immortal Blue
    Immortal Blue about 11 years
    @CodesInChaos, I've updated my answer to reflect what you've said here
  • CodesInChaos
    CodesInChaos about 11 years
    You should use a random IV for each encryption, and I'd prefer AES of 3DES. You also forgot using a MAC.
  • sircodesalot
    sircodesalot about 11 years
    Brilliant. Obviously you know encryption really well. Where can I go to learn more about this?
  • Immortal Blue
    Immortal Blue about 11 years
    What do you want to learn, concepts or specific implementations? If concepts, just follow links in the wikipedia article, as for specific things, I've pretty much put everything I know about it up already ;)
  • sircodesalot
    sircodesalot about 11 years
    Yeah, I get encryption conceptually, but I lack a detailed understanding. Definitely would like to learn though.
  • jbtule
    jbtule about 11 years
    Dan Boneh's Coursea Crypto I Course is free and very very good.
  • Immortal Blue
    Immortal Blue about 11 years
    To the negative poster, please leave a comment.