Click here to Skip to main content
Licence 
First Posted 4 Jul 2004
Views 29,489
Bookmarked 27 times

Applied cryptography Part 2: a tool to encrypt files on your HDD

By | 4 Jul 2004 | Article
There is a lot of .NET cryptography articles but not many sample applications using it. This article (part 2) introduces an application to encrypt files on your hard disk to keep them secret and unreadable to others.

CryptoSafe main window

Introduction

Do you need to keep some of your files unreadable to others? Do you want to be sure that when you leave your workplace your files are secure?

CryptoSafe is a tool that enables you to encrypt your private files so that no one else can read them.

Key features of CryptoSafe:

  • Rijndael encryption algorithm.
  • Secure key creation from given password using PasswordDeriveBytes method.
  • Using Isolated Storage for storing per-user configuration.
  • Extracting icons associated with files, using Win32 shell.

The algorithm - RijndaelManaged

Why RijndaelManaged? As written in part 1: because it is strong, fast, and managed, what ensures to run on every machine with .NET framework installed.

The Application

There are very few steps you have to do for using CryptoSafe:

  • Enter password for encryption.
  • Define folders you want to protect (in Folders tab).
  • Select active folder to work with.
  • Encrypt files selected in left listbox by clicking "move right" button.
  • Decrypt files by clicking "move left" (or double clicking) encrypted files in right listbox.

You can refresh file list by clicking "re" button if necessary (when folder contents change).

The Code

Creating file list with proper icons

void refreshFileList()
{
    listView1.Items.Clear();
    listView2.Items.Clear();

    if (workingDirectory == null || workingDirectory.Length == 0)
        return;
    this.Cursor = Cursors.WaitCursor;
    try
    {
        string[] files = Directory.GetFiles(workingDirectory);
        int imageIndex = 0;
        imageList1.Images.Clear();
        SHFILEINFO shinfo = new SHFILEINFO();
        listView1.BeginUpdate();
        listView2.BeginUpdate();
        foreach (string s in files)
        {
            FileInfo fi = new FileInfo(s);
            if (fi.Extension.ToLower() == ".enc")
            {
                ListViewItem lvi = new ListViewItem(fi.Name);
                lvi.SubItems.Add(fi.Length.ToString());
                lvi.Tag = fi.FullName;
                lvi.ImageIndex = 0;
                listView2.Items.Add(lvi);
            }
            else
            {
                //extract file icon
                IntPtr hImgSmall = MyShell.SHGetFileInfo(s, 0, 
                    ref shinfo,(uint)Marshal.SizeOf(shinfo),
                    MyShell.SHGFI_ICON |
                    MyShell.SHGFI_SMALLICON);
                //The icon is returned in the hIcon member of the shinfo
                //struct
                System.Drawing.Icon myIcon = 
                    System.Drawing.Icon.FromHandle(shinfo.hIcon);
                imageList1.Images.Add(myIcon);

                ListViewItem lvi = new ListViewItem(fi.Name);
                lvi.ImageIndex = imageIndex++;
                lvi.SubItems.Add(fi.Length.ToString());
                lvi.Tag = fi.FullName;
                listView1.Items.Add(lvi);
            }
        }
        listView1.EndUpdate();
        listView2.EndUpdate();
    }
    catch(IOException ex)
    {
        MessageBox.Show("refreshFileList IOexception: "+ex.Message);
    }
    finally
    {
        this.Cursor = Cursors.Arrow;
    }}

Save settings in isolated storage

void saveSettings()
{
    // Retrieve an IsolatedStorageFile
    // for the current Domain and Assembly.
    try
    {
        IsolatedStorageFile isoFile = 
          IsolatedStorageFile.GetStore(IsolatedStorageScope.User |
          IsolatedStorageScope.Assembly |
          IsolatedStorageScope.Domain , null,null);

        IsolatedStorageFileStream fs = new 
          IsolatedStorageFileStream("cryptoSettings.txt", 
          FileMode.Create,FileAccess.Write);
        StreamWriter sw = new StreamWriter(fs);
        foreach (string fname in lbFolders.Items)
            sw.WriteLine(fname);
        sw.Close();
        isoFile.Close();
        
    }
    catch (IsolatedStorageException ex)
    {
        MessageBox.Show(ex.Message);
    }
    catch (IOException ex)
    {
        MessageBox.Show(ex.Message);
    }
}

Load settings from isolated storage

void loadSettings()
{
    // Retrieve an IsolatedStorageFile for the current Domain and Assembly.
    try
    {
        lbFolders.Items.Clear();
        IsolatedStorageFile isoFile = 
          IsolatedStorageFile.GetStore(IsolatedStorageScope.User |
          IsolatedStorageScope.Assembly |
          IsolatedStorageScope.Domain , null,null);

        IsolatedStorageFileStream fs = new 
          IsolatedStorageFileStream("cryptoSettings.txt", 
          FileMode.Open,FileAccess.Read);
        StreamReader sr = new StreamReader(fs);
        while (true)
        {
            string l = sr.ReadLine();
            if (l == null)
                break;
            lbFolders.Items.Add(l);
        }

        sr.Close();
        isoFile.Close();
        
    }
    catch (FileNotFoundException)
    {
        MessageBox.Show("application settings" + 
          " file not found - please set working folders");
    }
    catch (IsolatedStorageException ex)
    {
        MessageBox.Show(ex.Message);
    }
    catch (IOException ex)
    {
        MessageBox.Show(ex.Message);
    }
}

File encryption

public  void EncryptData(String inName, 
        String outName, byte[] rijnKey, byte[] rijnIV)
{    
    FileStream fin = null;
    FileStream fout = null;
    CryptoStream encStream = null;

    try
    {
        //Create the file streams to handle the input and output files.
        fin = new FileStream(inName, FileMode.Open, FileAccess.Read);
        fout = new FileStream(outName, FileMode.Create, FileAccess.Write);
        //fout.SetLength(0);

        //Create variables to help with read and write.

        //This is intermediate storage for the encryption.
        byte[] bin = new byte[bufLen];
        //This is the total number of bytes written.
        long rdlen = 0;
        //This is the total length of the input file.
        long totlen = fin.Length;
        //This is the number of bytes to be written at a time.
        int len;

        RijndaelManaged rijn = new RijndaelManaged();
        encStream = new CryptoStream(fout, 
          rijn.CreateEncryptor(rijnKey, rijnIV), 
          CryptoStreamMode.Write);
        
        fireMessage("Rijndael encrypting...");

        //encrypt test header
        encStream.Write(testHeader,0,testHeader.Length);

        //Read from the input file, then encrypt 
        //and write to the output file.
        while(true)
        {
            len = fin.Read(bin, 0, bufLen);
            if (len == 0)
                break;
            encStream.Write(bin, 0, len);
            rdlen += len;
            fireMessage(inName,(int)totlen,(int)rdlen);
        }
        fireMessage(string.Format("{0} - {1} bytes processed", 
                                                 inName ,rdlen));
    }
    finally
    {
        if (encStream != null)
            encStream.Close();  
        if (fout != null)
            fout.Close();
        if (fin != null)
            fin.Close();                   
    }
}

File decryption

public bool DecryptData(String inName, 
          String outName, byte[] rijnKey, byte[] rijnIV)
{    
    //Create the file streams to handle the input and output files.
    FileStream fin = null;
    FileStream fout = null;
    CryptoStream decStream = null;
    
    try
    {
        fin = new FileStream(inName, FileMode.Open, FileAccess.Read);

        //Create variables to help with read and write.

        //This is intermediate storage for the encryption.
        byte[] bin = new byte[bufLen];
        //This is the total number of bytes written.
        long rdlen = 0;
        //This is the total length of the input file.
        long totlen = fin.Length;
        //This is the number of bytes to be written at a time.
        int len;

        RijndaelManaged rijn = new RijndaelManaged();
        
        decStream = new CryptoStream(fin, 
          rijn.CreateDecryptor(rijnKey, rijnIV), 
          CryptoStreamMode.Read);

        fireMessage("Rijndael decrypting...");

        //decrypt test header
        byte[]test = new byte[testHeader.Length];
        decStream.Read(test,0,testHeader.Length);
        if (BitConverter.ToString(test) != testHeaderString)
        {
            decStream.Clear();
            decStream = null;
            fireMessage("error while decrypting file "+inName);
            return false;
        }

        //create output file
        fout = new FileStream(outName, 
                     FileMode.Create, FileAccess.Write);

        //Read from the encrypted file and write dercypted data
        while(true)
        {
            len = decStream.Read(bin,0,bufLen);
            if (len == 0)
                break;
            fout.Write(bin,0,len);
            rdlen += len;
            fireMessage(inName,(int)totlen,(int)rdlen);
        }
        fireMessage(string.Format("{0} - {1} bytes processed", 
                                                  inName ,rdlen));

        return true;
    }
    finally
    {
        if (decStream != null)
            decStream.Close();
        if (fout != null)
            fout.Close();
        if (fin != null)
            fin.Close();                   
    }
}

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Marcin Cuprjak

Architect

Poland Poland

Member



Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
GeneralGood job, Draculea Pinmembera codeproject fan22:12 11 Aug '09  
QuestionExtending the Capability/ Making it Simpler Pinmemberaj4k56:01 1 May '08  
Dear Friend, this is   wonderful piece of architecture that u have created here. Atleast i have found this to be the best application in this section at codeproject. I don't have much knowledge about the platform that u have worked upon but I have few suggestions/Queries to make it better from the user's point of view.
 
1. At the first usage, since it does not have a default value for the folder it throws an exception which needs to be dealt with/ a default value for the folder can be assigned.

2. if somehow the directory/ Folder Structure can be displayed in the view, it would become much more easier for the user to navigate through and work upon.
 
3. The password can be provided at the time of Clicking the cmd_button to encrypt rather than providing it at the time of start of application. similarly it should prompt for password when the file decryption starts.
 
4. how about extending the capability to encrypt folder/drive.
 
If all these features are inculcated i strongly believe that ur application can contest with the commercially available ones.
 
Regards and Best of LUCK !
MAK
NewsTwo other related encryption articles in CodeProject ... PinmemberTony Selke7:12 27 Sep '07  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web04 | 2.5.120529.1 | Last Updated 5 Jul 2004
Article Copyright 2004 by Marcin Cuprjak
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid