We help IT Professionals succeed at work.

C# Encrypting Files

xtstech
xtstech used Ask the Experts™
on
I am using Visual Studio 2008 Team Suite, and I'm trying to get the encryption implementation provided in the answer for http://www.experts-exchange.com/Programming/Languages/C_Sharp/Q_25079604.html to encrypt/decrypt files.  How can I do that?  Thanks

PS: This is C# 2008, and I'd like it to work with the code found in the link provided by the answer in the above question.
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
if
http://tsells.servehttp.com/host/Files/Tools/MyEncrypt.zip

is not what you are looking for - could you please be more specific.

There is an example project in there.

Author

Commented:
Yes. I currently have that project working with encrypting the strings from text boxes, but how can I make it encrypt files on the desktop, or specific folders?

Commented:
am  getting this right: you want to encrypt the file's content.
Are there any binary files or are we talking about more or lest plain text files?
You can
1.) read the while files content
2.) use the provided string encoder from the class you are using
3.) write the encoded content back to this or an copy of the file

you said you want to encrypt whole directories, also.
do you expect a single file as a result of this process that is encrypted and get the directory structure with all it's files back if you decrypt it?

If it is meant to be decrypted by the encrypting user only, you can use the given methods of system.io.file to do so, but be aware - only the user encrypting it is able to decrypt it again.

Maybe you should get a little more specific on what you plan

Author

Commented:
Binary data will be included in the encrypted content, and whole directories should be able to either individually encrypt each file individually, or create an encrypted archive of the directory with the structure intact.  If you have a working example solution for this, then that would be perfect.  Thanks

Do you need any more info?

Commented:
that was good info.
But some further info is prefered: does anyone using your tool need to be able to decrypt, or just the (windows-)user that encrypted it?
Maybe it might be enough to encrypt a archive.. I have to think about that a little time.
I am not at home tonight - maybe I can code a sample tomorrow or another ee-member might.

Author

Commented:
It should be anyone who knows the AES password.
Commented:
ok,
here is a sample - hope it helps.
You have a basic RijndaelManaged Implementation (AES).

There are some public methods that can be used to encrypt / decrypt a file or a directory. Not all mentioned in the sample, but in the sample-source.

To archive the directory I use this nice CodePlex-Zip implementation:
http://www.codeplex.com/DotNetZip
! You have to download it by yourself, because I was not able to attach it within the archive... EE did block the DLL.


//----------------------------------------
//Call - simple file
  EncryptDecryptRijndaelManaged enc = new EncryptDecryptRijndaelManaged("MyPassword");
  enc.EncryptFile(@"c:\test.txt", @"c:\test.enc");
  enc.DecryptFile(@"c:\test.enc", @"c:\test.txt");

//Call - directory
 EncryptDecryptRijndaelManaged enc = new EncryptDecryptRijndaelManaged("MyPassword");
  enc.EncryptDirectory(@"c:\test", "");

  enc.DecryptDirectory(@"c:\test\test.zip", @"c:\testExtract");
//----------------------------------------


using System;
using System.Text;
using System.Security.Cryptography;
using System.IO;
using Ionic.Zip;

namespace RijndaelManagedEncoderDecoder
{
    internal class EncryptDecryptRijndaelManaged
    {
        public string password { get; private set; }
        public string salt { get; private set; }

        private byte[] saltBytes;        
        private RijndaelManaged aes;

        /// <summary>
        /// Constructor - just password - salt is set in class
        /// </summary>
        /// <param name="password">the passwort</param>
        public EncryptDecryptRijndaelManaged(string password)
        {
            this.password = password;
            this.salt = "PryratesAkaRZAownsYou";
            Init();
        }

        /// <summary>
        /// Constructor - password and salt is required
        /// </summary>
        /// <param name="password">the passwort</param>
        /// <param name="salt">the salt</param>
        public EncryptDecryptRijndaelManaged(string password, string salt) 
        {
            this.password = password;
            this.salt = salt;
            Init();
        }

        private void Init()
        {
            aes = new RijndaelManaged();
            saltBytes = Encoding.ASCII.GetBytes(this.salt);
            Rfc2898DeriveBytes key = new Rfc2898DeriveBytes(this.password, saltBytes);
            aes.Key = key.GetBytes(aes.KeySize / 8);
            aes.IV = key.GetBytes(aes.BlockSize / 8);
        }


        /// <summary>
        /// Encryp file - replaces existing file
        /// </summary>
        /// <param name="file">full path including name to file that needs to be ENcrypted</param>
        /// <returns>true if success</returns>
        public bool EncryptFile(string file)
        {
            if (!File.Exists(file))
                throw new Exception(string.Concat("File does not exist", System.Environment.NewLine, file));

            string tmp_file = string.Concat(file, ".tmp");

            FileStream fIn = new FileStream(file, FileMode.Open, FileAccess.Read);
            FileStream fOut = new FileStream(tmp_file, FileMode.OpenOrCreate, FileAccess.Write);

            byte[] fileData = new byte[fIn.Length];
            fIn.Read(fileData, 0, (int)fIn.Length);
            ICryptoTransform encryptor = aes.CreateEncryptor();
            CryptoStream encryptStream = new CryptoStream(fOut, encryptor, CryptoStreamMode.Write);
            encryptStream.Write(fileData, 0, fileData.Length);
            encryptStream.Close();
            fIn.Close();
            fOut.Close();

            File.Delete(file);
            if(File.Exists(file))
                throw new Exception(string.Concat("Unable to remove file", System.Environment.NewLine, file));
            File.Move(tmp_file, file);

            return true;
        }

        /// <summary>
        /// Encryp file
        /// </summary>
        /// <param name="file">full path including name to file that needs to be ENcrypted</param>
        /// <param name="destination_file">full path including name to store encrypted file</param>
        /// <returns>true if success</returns>
        public bool EncryptFile(string file, string destination_file)
        {
            if (!File.Exists(file))
                throw new Exception(string.Concat("File does not exist", System.Environment.NewLine, file));
            
            if (file.Equals(destination_file, StringComparison.InvariantCultureIgnoreCase))
                throw new Exception("File names are equal. Use other method or change filename");

            FileStream fIn = new FileStream(file, FileMode.Open, FileAccess.Read);
            FileStream fOut = new  FileStream(destination_file, FileMode.OpenOrCreate, FileAccess.Write);
            
            byte[] fileData = new byte[fIn.Length];
            fIn.Read(fileData, 0, (int)fIn.Length);
            ICryptoTransform encryptor = aes.CreateEncryptor();
            CryptoStream encryptStream = new CryptoStream(fOut, encryptor, CryptoStreamMode.Write);
            encryptStream.Write(fileData, 0, fileData.Length);
            encryptStream.Close();
            fIn.Close();
            fOut.Close();
            return true;
        }


        /// <summary>
        /// Decrypt file - replaces existing file
        /// </summary>
        /// <param name="file">full path to file that needs to be DEcrypted</param>
        /// <returns>true if success</returns>
        public bool DecryptFile(string file)
        {
            if (!File.Exists(file))
                throw new Exception(string.Concat("File does not exist", System.Environment.NewLine, file));

            string tmp_file = string.Concat(file, ".tmp");

            FileStream fIn = new FileStream(file, FileMode.Open, FileAccess.Read);
            FileStream fOut = new FileStream(tmp_file, FileMode.OpenOrCreate, FileAccess.Write);

            byte[] fileData = new byte[fIn.Length];
            fIn.Read(fileData, 0, (int)fIn.Length);
            ICryptoTransform decryptor = aes.CreateDecryptor();
            CryptoStream decryptStream = new CryptoStream(fOut, decryptor, CryptoStreamMode.Write);
            decryptStream.Write(fileData, 0, fileData.Length);
            decryptStream.Close();
            fIn.Close();
            fOut.Close();

            File.Delete(file);
            if (File.Exists(file))
                throw new Exception(string.Concat("Unable to remove file", System.Environment.NewLine, file));
            File.Move(tmp_file, file);

            return true;
        }

        /// <summary>
        /// Decrypt file
        /// </summary>
        /// <param name="file">full path to file that needs to be DEcrypted</param>
        /// <param name="destination_file">full path including name to store decrypted file</param>
        /// <returns></returns>
        public bool DecryptFile(string file, string destination_file)
        {
            if (!File.Exists(file))
                throw new Exception(string.Concat("File does not exist", System.Environment.NewLine, file));

            if (file.Equals(destination_file, StringComparison.InvariantCultureIgnoreCase))
                throw new Exception("File names are equal. Use other method or change filename");

            FileStream fIn = new FileStream(file, FileMode.Open, FileAccess.Read);
            FileStream fOut = new FileStream(destination_file, FileMode.OpenOrCreate, FileAccess.Write);

            byte[] fileData = new byte[fIn.Length];
            fIn.Read(fileData, 0, (int)fIn.Length);
            ICryptoTransform decryptor = aes.CreateDecryptor();
            CryptoStream decryptStream = new CryptoStream(fOut, decryptor, CryptoStreamMode.Write);
            decryptStream.Write(fileData, 0, fileData.Length);
            decryptStream.Close();
            fIn.Close();
            fOut.Close();
            return true;
        }


        /// <summary>
        /// Encrypt a whole directories content
        /// </summary>
        /// <param name="directory">directory to be encrypted</param>
        /// <param name="zip_destination">full path including name and extension to the zipped archive. Folder MUST exist. If empty string is generated automatically and stored in encrypted folder</param>
        /// <returns>true if success</returns>
        public bool EncryptDirectory(string directory, string zip_destination)
        {
            if (!Directory.Exists(directory))
                throw new Exception(string.Concat("Directory does not exist", System.Environment.NewLine, directory));
            
            string tmpDirectory = string.Concat(directory, ".tmpdir");

            if (Directory.Exists(tmpDirectory))
            {
                Directory.Delete(tmpDirectory, true);
                if (Directory.Exists(tmpDirectory))
                    throw new Exception(string.Concat("Temp directory can not be deleted", System.Environment.NewLine, tmpDirectory));
            }

            CopyDirectory(directory, tmpDirectory);

            if (!Directory.Exists(tmpDirectory))
                throw new Exception(string.Concat("Temp directory could not be created", System.Environment.NewLine, tmpDirectory));

            EncryptDirectoryRecursive(tmpDirectory);
            
            string zipName = zip_destination;
            if(zip_destination == "")            
                zipName = string.Concat(directory, "\\", new DirectoryInfo(directory).Name, ".zip");

            //http://www.codeplex.com/DotNetZip
            using (ZipFile zip = new ZipFile())
            {
                zip.UseUnicodeAsNecessary = true;
                zip.CompressionLevel = Ionic.Zlib.CompressionLevel.BestCompression;
                zip.AddDirectory(tmpDirectory);
                zip.Comment = "This is an encrypted file";
                zip.Save(zipName);
            }

            if (Directory.Exists(tmpDirectory))
            {
                Directory.Delete(tmpDirectory, true);
                if (Directory.Exists(tmpDirectory))
                    throw new Exception(string.Concat("Temp directory can not be deleted", System.Environment.NewLine, tmpDirectory));
            }
            return true;
        }

        /// <summary>
        /// Decrypt an encrypted zip-archive
        /// </summary>
        /// <param name="archive_name">full path to the archive - including filename and extension</param>
        /// <param name="destination_directory">directory where the archive will be extracted to - directory must exist</param>
        /// <returns></returns>
        public bool DecryptDirectory(string archive_name, string destination_directory)
        {
            if (!File.Exists(archive_name))
                throw new Exception(string.Concat("Zipfile des not exist", System.Environment.NewLine, archive_name));
            
            if (!Directory.Exists(destination_directory))
                throw new Exception(string.Concat("Destination directory does not exist", System.Environment.NewLine, destination_directory));

            //http://www.codeplex.com/DotNetZip
            using (ZipFile zip = ZipFile.Read(archive_name))
            {
                foreach (ZipEntry z in zip)
                {
                    z.Extract(destination_directory, ExtractExistingFileAction.OverwriteSilently);
                }
            }

            DecryptDirectoryRecursive(destination_directory);

            return true;
        }


        #region internal helpers
        private void CopyDirectory(string src, string dest)
        {             
            if (!dest.EndsWith("\\"))
                dest = string.Concat(dest, "\\");

            if (!Directory.Exists(dest))
                Directory.CreateDirectory(dest);

            foreach (string elem in Directory.GetFileSystemEntries(src))
            {
                if (elem != dest)
                {
                    if (Directory.Exists(elem))
                        CopyDirectory(elem, string.Concat(dest, Path.GetFileName(elem)));
                    else
                        File.Copy(elem, string.Concat(dest, Path.GetFileName(elem)), true);
                }
            }
        }


        private void EncryptDirectoryRecursive(string src)
        {
            foreach (string elem in Directory.GetFileSystemEntries(src))
            {
                if (Directory.Exists(elem))
                    EncryptDirectoryRecursive(elem);
                else
                    EncryptFile(elem);                
            }
        }


        private void DecryptDirectoryRecursive(string src)
        {
            foreach (string elem in Directory.GetFileSystemEntries(src))
            {
                if (Directory.Exists(elem))
                    DecryptDirectoryRecursive(elem);
                else
                    DecryptFile(elem);
            }
        }

        #endregion

    }
}

Open in new window

RijndaelManagedEncoderDecoder.zip

Author

Commented:
Thanks. I'll let you know if it works.

Commented:
If there is are any problems, don't hesitate to ask :)

Author

Commented:
Will do?  Will this code allow me to encrypt byte arrays?

Commented:
it encrypts files and folders - neither arrays nor strings or any other types.
I think that will be another story for itself.
You can serialize your array to a file and then encrypt
/ decrypt and deserialize the file back to a bytearray.

Author

Commented:
How can I make it not crash when you use the wrong password, or try to decrypt a non encrypted file?

Author

Commented:
it crashes at this line:
decryptStream.Close();

Author

Commented:
Fixed it with a try/catch. Thanks again

Commented:
huh. at what line does it crash?

Commented:
if password is wrong there is little you can do. there should be an exception thrown - exception handling is not very robust in the sample lib. that would have counter blown the source even more ;-).

same as not encrypted file... to be honest - didn't try that *duck*