Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Applied Cryptography Part 1: Simple tool to enrcypt/decrypt e-mail messages

30 Jun 2004 1  
There is a lot of .NET cryptography articles but not many sample applications using it. This article (part 1) introduces an application that enables to send secure messages via email.

Sample image

Introduction

Have you ever wondered if your e-mails are secure and secret? Does your network administrator have possibility to read all your correspondence? Do you value your privacy?

If any of the answers is "yes", this article can help you keep your private emails private.

Sample encrypted message looks like this:

-== Begin encryption ==-
9wZO1XjCVP5EwbuOCKP397LW77ar+pwJRhAX+7cRL2LVhstfN4qS4aPAJqeh
CM6rtubeEOj+W04vYymeqA/i/8UOMF/ajiLrH+HpqkfdqumcN2oWpN4PI+50
8K0kAnJqxsOnu7rcjg877yX9XECSlsaKPLZb7RoER+koJ9CRJhQhVusu53+b
rKmUksEBAcKeA4qP0AEsA2ii4LB0JsE/1FXhez8VFSX74Ij36C0/fC7aJgc7
FDNQKRxuE551Z6ERfRrFF/OyxCZxEJe/lsyibf2xMpiCrtCj6h7+d+h8njkc
+CdsB94qAzf9WHoNjQNDuhmVygWiw+M4RUE/L9c4EOJUUD8T52XohF+Y1HzF
Bm0=
-== End encryption ==-

The Application

MailCryptNet is a tool that enables to encrypt any message you want to send via email. Encryption uses Rijndael algorithm and RijndaelManaged class from System.Security.Cryptography namespace. Only thing you have to do is to give your friends a copy of MailCryptNet and prepare passwords for them.

You may ask "why should I bother preparing any passwords? Isn't it enough to give the tool to my friends?". It prevents the case when other people (including your hated admin) downloads the tool and decrypts your messages. Creating secret passwords for your friends ensures you that no one else can read your message.

Creating passwords and keys

Password creation is a bit complicated because Rijndael is a symmetric algorithm which uses the same key to encrypt and decrypt data. In such cases, all your friends (including you) would have to use the same password. But nobody likes to share his password (as it is no longer secret).

But there is a solution to use symmetric algorithm and different passwords. The trick is that there are two levels of passwords. First level is common to all trusted clients, and second level is user-specific and is used to encrypt the first-level one.

For example, all trusted clients (you and your friends) use first level password like that: "oh fishy fishy fishy fish!" (or any other weird and twisted text), then every user creates his own private password to encrypt the first-level one. This is a second-level password.

The algorithm - RijndaelManaged

Why RijndaelManaged? Because it is strong, fast and managed that ensures to run on every machine with .NET framework installed.

Base64 encoding

E-mail messages are sent with pure text format. Encrypted data is a binary format. Therefore, it is necessary to do some conversion between those formats. Base64 is a well known and broadly used method to send binary data as pure text. To do it, Microsoft implemented very useful methods called ToBase64String and FromBase64String located in Convert namespace.

Application

What does MailCryptNet do:

  • on startup, it reads .config file in order to find encrypted keys.
  • if stored keys are empty, it enables to create new encryption keys.
  • when .config contains encrypted key, it is decrypted using your private (second level) password.
  • decrypted keys are used by Rijndael algorithm.
  • any message typed in RichEdit is encrypted (including RTF formatting) and placed on Clipboard.
  • encrypted message can be restored from Clipboard and after decrypting is placed in RichEdit.

Preparing passwords

Default password is "secret". You can test it by copying encrypted message from the beginning of the article and pressing "decrypt" button. To change the password, do the following:

  • remove Key and IV values from .config file.
  • run MailCryptNet.
  • enter first-level password (common for all friends).
  • enter second-level password - your private password.
  • copy generated keys into .config file.
  • restart application.

Usage

Normal usage usually involves following steps:

  • type the message.
  • click the "Encrypt to Clipboard" button.
  • create new email (in your email application).
  • paste text from Clipboard.
  • send email.

When receiving encrypted email, do the following:

  • copy email text to Clipboard.
  • in MailCryptNet, click "Decrypt from Clipboard" button.
  • read a message.

The code

Using PasswordDeriveBytes function:

    void getKeysFromPassword(string pass, 
               out byte[] rijnKey, out byte[] rijnIV)
    {

        byte[] salt = 
          System.Text.Encoding.ASCII.GetBytes("some text to give it a bit salt");
        PasswordDeriveBytes pb = new PasswordDeriveBytes(pass,salt);

        //generate key and iv

        rijnKey = pb.GetBytes(32);
        rijnIV = pb.GetBytes(16);

    }

Converting to Base64 blocks:

    string makeBlocksFromString(string s)
    {
        System.Text.StringBuilder sb = new System.Text.StringBuilder();

        sb.Append("-== Begin encryption ==-\r\n");

        int lineLength = 0;
        for (int i=0;i<s.Length;i++)
        {
            char z = s[i];
            sb.Append(z);
            lineLength++;
            //add "new line" when block width met

            if (lineLength == blockLength)
            {
                lineLength = 0;
                sb.Append("\r\n");
            }
        }
        //if the last line shorter than block width - add new line

        if (lineLength > 0)
            sb.Append("\r\n");
        sb.Append("-== End encryption ==-\r\n");
        return sb.ToString();
    }
    string makeStringFromBlocks(string s)
    {
        char[]seps = new char[] {'\r','\n'};
        string[] tab = s.Split(seps);
        System.Text.StringBuilder sb = new System.Text.StringBuilder();
        bool wasBegin = false;
        for (int i=0;i<tab.Length;i++)
        {
            if (tab[i] == "-== Begin encryption ==-")
            {
                wasBegin = true;
                continue;
            }
        
            if (wasBegin)
            {
                if (tab[i] == "-== End encryption ==-")
                {
                    return sb.ToString();
                }
                else
                    sb.Append(tab[i]);
            }
        }
        throw new 
          CryptographicException("missing begin block - end block definitions");
    }

Rijndael encryption:

EncryptData method is used to encode message to be secret.

    private  byte[] EncryptData(byte[] dataToEncrypt, 
                                      byte[] rijnKey, byte[] rijnIV)
    {
        RijndaelManaged rijn = new RijndaelManaged();
        //Get an encryptor.

        ICryptoTransform encryptor = rijn.CreateEncryptor(rijnKey, rijnIV);
        
        //Encrypt the data.

        MemoryStream msEncrypt = new MemoryStream();
        CryptoStream csEncrypt = new CryptoStream(msEncrypt, 
                             encryptor, CryptoStreamMode.Write);

        //Write all data to the crypto stream and flush it.

        csEncrypt.Write(dataToEncrypt, 0, dataToEncrypt.Length);
        csEncrypt.FlushFinalBlock();

        //Get encrypted array of bytes.

        return msEncrypt.ToArray();
    }

Rijndael decryption:

DecryptData method is used to decode secret message.

    private  byte[] DecryptData(byte[] dataToDecrypt, 
                                     byte[] rijnKey, byte[] rijnIV)
    {
        RijndaelManaged rijn = new RijndaelManaged();
        //Get a decryptor.

        ICryptoTransform decryptor = 
               rijn.CreateDecryptor(rijnKey, rijnIV);
        
        //Now decrypt the message

        MemoryStream msDecrypt = new MemoryStream(dataToDecrypt);
        CryptoStream csDecrypt = new CryptoStream(msDecrypt, 
                               decryptor, CryptoStreamMode.Read);

        byte[] fromEncrypt = new byte[dataToDecrypt.Length];

        //Read the data out of the crypto stream.

        int len = csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length);

        byte[] decrypted = new byte[len];
        Array.Copy( fromEncrypt,decrypted,len);

        return decrypted;
    }

Button and Clipboard handlers:

    private void btnEncrypt_Click(object sender, System.EventArgs e)
    {
        string toEncrypt = richTextBox1.Rtf;
        byte[] toEncryptBuf = System.Text.Encoding.ASCII.GetBytes(toEncrypt);

        //Rijndael encryption

        try
        {
            byte[] encryptedBuf = 
              EncryptData(toEncryptBuf,cryptoKey,cryptoIV);
            string encryptedString = 
              makeBlocksFromString(Convert.ToBase64String(encryptedBuf));
            Clipboard.SetDataObject(encryptedString,true);
        }
        catch (FormatException ex)
        {
            MessageBox.Show(ex.Message);
            return;
        }
        catch (CryptographicException ex)
        {
            MessageBox.Show(ex.Message);
            return;
        }

    }
    private void btnDecrypt_Click(object sender, System.EventArgs e)
    {
        IDataObject iData = Clipboard.GetDataObject();
        if (iData.GetDataPresent(DataFormats.Text))
        {
          //Rijndael decryption

          try
          {
            string encryptedString = 
              makeStringFromBlocks(iData.GetData(DataFormats.Text).ToString());

            byte[] encryptedBuf = Convert.FromBase64String(encryptedString);
            byte[] decryptedBuf = DecryptData(encryptedBuf, 
                                                    cryptoKey,cryptoIV);
            string plainText = 
                   System.Text.Encoding.ASCII.GetString(decryptedBuf);
            richTextBox1.Rtf = plainText;

          }
          catch (FormatException ex)
          {
            MessageBox.Show(ex.Message);
            return;
          }
          catch (CryptographicException ex)
          {
            MessageBox.Show(ex.Message);
            return;
          }
        }
    }

Future enhancements

There are some features that could be added to this software:

  • Isolated Storage support - for multiple users to use the application with separate passwords. Instead of .config file, user passwords can be stored in Isolated Storage.
  • Some text formatting while typing message - at the moment, formatting is possible only when you paste formatted text into MailCryptNet edit window. "Reset" button removes the formatting.
  • Some integration with email applications for automatic message encoding/decoding while sending emails.

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