AES 256-bit encryption/decryption

Published:

This time around, I had a little project with a friend which involved cryptography. So we decided to implement an AES-256 encryption/decryption. That is way above top secret (lol). I googled around looking for information and reading more on cryptography and found this http://www.chapleau.info/blog/2011/01/06/usingsimplestringkeywithaes256encryptioninc.html. There is couple of thing which I don't like regarding the implementation but it is a good start for now.

Well, there are only two actually.

  1. I want my key to be 32 characters in total. I don't need to generate the key.
  2. I don't like concatenating IV into Key as IV supposed to be unique everytime you encrypt/decrypt. This way, you will have same cipher because the IV is the same and to go around that, you will have to generate new key everytime.
  3. Since I need to support 32-char key, the code obviously won't work for me out of the bag.

IV relationship with Cipher Text

Basically, IV just create randomness in the cipher text. To decrypt you would also need to know the IV (I didn't actually know about this requirement). Since I have the key already, I would just need to pass the IV portion together with the cipher text. IV does not need to be encrypted, if you encrypt IV then technically it requires other IV, thus inception lol. IV can be public as long as the the private key is private. This is how I implement it.

Encryption

1
    [16 bytes of IV] + [x bytes of cipher text]

We generate a random IV everytime we encrypt to ensure randomness. The link I gave you just now did not actually do this, it encrypts based on the IV sliced from the Key. I concatenate the IV into the cipher text (encrypted text) and encode into base64 for readability. IV can be public and known to sniffer, as long as the key stays private.

Decryption

To decrypt, I need to retrieve the first 16 bytes to get the IV and set it into the algorithm and the remaining part should be the part for decryption.

I thought I can just skip the IV and decrypt the remaining part, but turned out that part of the message will turn out to be rubbish.

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
    static void Main(string[] args)
    {
        var text = "Hello there human, all your bases belong to us.";
        Console.WriteLine("Original Text: {0}", text);
        const int keySize = 256;
        const string completeEncodedKey = "3925841d02dc09fbdc118597196a0b32";

        Console.WriteLine("Using complete key '{0}'", completeEncodedKey);
        string encryptedText = Encrypt(text, completeEncodedKey, keySize);
        Console.WriteLine("Encrypted Text: {0}", encryptedText);
        string decrypted = Decrypt(encryptedText, completeEncodedKey, keySize);
        Console.WriteLine("Decrypted Text: {0}", decrypted);

        Console.Read();
    }

    private static string Encrypt(string text, string completeEncodedKey, int keySize)
    {
        var aesEncryption = new RijndaelManaged
            {
                KeySize = keySize,
                BlockSize = 128,
                Mode = CipherMode.CBC,
                Padding = PaddingMode.PKCS7
            };

        aesEncryption.GenerateIV();
        aesEncryption.Key = Encoding.UTF8.GetBytes(completeEncodedKey);
        var plainText = Encoding.UTF8.GetBytes(text);
        var crypto = aesEncryption.CreateEncryptor();
       
        var cipherText = crypto.TransformFinalBlock(plainText, 0, plainText.Length);
        var cipherWithIv = new byte[aesEncryption.IV.Length + cipherText.Length];

        Array.Copy(aesEncryption.IV, cipherWithIv, aesEncryption.IV.Length);
        Array.Copy(cipherText, 0, cipherWithIv, aesEncryption.IV.Length, cipherText.Length);

        return Convert.ToBase64String(cipherWithIv);
    }

    private static string Decrypt(string encryptedText, string completeEncodedKey, int keySize)
    {
        var aesEncryption = new RijndaelManaged
            {
                KeySize = keySize,
                BlockSize = 128,
                Mode = CipherMode.CBC,
                Padding = PaddingMode.PKCS7
            };

        var cipherWithIv = Convert.FromBase64String(encryptedText);
        aesEncryption.IV = cipherWithIv.Take(16).ToArray();
        aesEncryption.Key = Encoding.UTF8.GetBytes(completeEncodedKey);
        var decrypto = aesEncryption.CreateDecryptor();
        var encryptedBytes = cipherWithIv.Skip(16).ToArray();

        return Encoding.UTF8.GetString(decrypto.TransformFinalBlock(encryptedBytes, 0, encryptedBytes.Length));
    }