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.
- I want my key to be 32 characters in total. I don't need to generate the key.
- I don't like concatenating
IV
intoKey
asIV
supposed to be unique everytime you encrypt/decrypt. This way, you will have same cipher because theIV
is the same and to go around that, you will have to generate new key everytime. - 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)); } |