C# Code that convert RijndaelCrypto from VB6 Version by Phil Fresle
using System; using ds.Common.Const; using ds.Common.Exceptional; using ds.Common.Resources; namespace ds.Common.Cryptography { public class RijndaelCrypto : ICryptography { private string _mykey = "Your-Secret-Key-Here"; public RijndaelCrypto() { } public RijndaelCrypto(string password){ this._mykey = password; } public CRYPTO_ALGORITHM Algorithm { get { return CRYPTO_ALGORITHM.RIJINDAEL; } } public string Encrypt(string pData) { try { string iv = _mykey.Substring(0, _mykey.Length / 2); return Rijndael.EncryptData(pData, _mykey, iv, Rijndael.BlockSize.Block256, Rijndael.KeySize.Key256, Rijndael.EncryptionMode.ModeECB, true); } catch (Exception ex) { throw new AppException(ERROR_CODE.DSAPP000MD00002001, CommonErrorResource.DSAPP000MD00002001, EXCEPTION_LEVEL.System, ex); } } public string Decrypt(string pData) { try { string iv = _mykey.Substring(0, _mykey.Length / 2); return Rijndael.DecryptData(pData, _mykey, iv, Rijndael.BlockSize.Block256, Rijndael.KeySize.Key256, Rijndael.EncryptionMode.ModeECB, true); } catch (Exception ex) { throw new AppException(ERROR_CODE.DSAPP000MD00002002, CommonErrorResource.DSAPP000MD00002002, EXCEPTION_LEVEL.System, ex); } } /// <summary> /// AUTHOR: Phil Fresle /// COPYRIGHT: Copyright 2001-2005 Phil Fresle /// EMAIL: phil@frez.co.uk /// WEB: http://www.frez.co.uk /// Implementation of the AES Rijndael Block Cipher, converted from my VB6 version. /// Inspired by Mike Scott's implementation in C. Permission for free direct or /// derivative use is granted subject to compliance with any conditions that the /// originators of the algorithm place on its exploitation. /// /// The Rijndael home page is here:- /// http://www.iaik.tu-graz.ac.at/research/krypto/AES/old/~rijmen/rijndael/ /// /// NOTE: All string conversions assume strings are Unicode; this may yield different /// results from other implementations if the other implementations are based /// on Ascii strings. Unicode is a 2-byte character set, and means that the routines /// will work just fine on, for instance, Japanese text. /// /// MODIFICATION HISTORY: /// 16-Feb-2001 Phil Fresle Initial VB6 Version /// 03-Apr-2001 Phil Fresle Added EncryptData and DecryptData functions to /// VB6 version. /// 19-Apr-2001 Phil Fresle Thanks to Paolo Migliaccio for finding a bug /// with 256 bit key in VB6 version. /// 11-Jul-2005 Phil Fresle Initial C# version. /// </summary> /// internal class Rijndael { public enum BlockSize { Block128, Block192, Block256 }; public enum KeySize { Key128, Key192, Key256 }; public enum EncryptionMode { ModeECB, ModeCBC }; public enum CharacterSet { CharsUnicode, CharsAscii }; private static byte[] InCo = { 0xB, 0xD, 0x9, 0xE }; private static byte[] fbsub = new byte[256]; private static byte[] rbsub = new byte[256]; private static byte[] ptab = new byte[256]; private static byte[] ltab = new byte[256]; private static uint[] ftable = new uint[256]; private static uint[] rtable = new uint[256]; private static uint[] rco = new uint[30]; private static int Nk, Nb, Nr; private static byte[] fi = new byte[24]; private static byte[] ri = new byte[24]; private static uint[] fkey = new uint[120]; private static uint[] rkey = new uint[120]; private static byte RotateLeft(byte valueToShift, int shiftBits) { // Rotate the bits in the byte return (byte)((valueToShift << shiftBits) | (valueToShift >> (8 - shiftBits))); } private static uint RotateLeft(uint valueToShift, int shiftBits) { // Rotate the bits in the integer return (valueToShift << shiftBits) | (valueToShift >> (32 - shiftBits)); } private static uint Pack(byte[] b) { uint temp = 0; for (byte i = 0; i <= 3; i++) temp |= ((uint)b[i] << (i * 8)); return temp; } private static uint PackFrom(byte[] b, int k) { uint temp = 0; for (byte i = 0; i <= 3; i++) temp |= ((uint)b[i + k] << (i * 8)); return temp; } private static void Unpack(uint a, byte[] b) { b[0] = (byte)a; b[1] = (byte)(a >> 8); b[2] = (byte)(a >> 16); b[3] = (byte)(a >> 24); } private static void UnpackFrom(uint a, byte[] b, int k) { b[0 + k] = (byte)a; b[1 + k] = (byte)(a >> 8); b[2 + k] = (byte)(a >> 16); b[3 + k] = (byte)(a >> 24); } private static byte xtime(byte a) { byte b; if ((a & 0x80) != 0) b = 0x1b; else b = 0; a <<= 1; a ^= b; return a; } private static byte bmul(byte x, byte y) { if (x != 0 && y != 0) return ptab[(ltab[x] + ltab[y]) % 255]; else return 0; } private static uint SubByte(uint a) { byte[] b = new byte[4]; Unpack(a, b); b[0] = fbsub[b[0]]; b[1] = fbsub[b[1]]; b[2] = fbsub[b[2]]; b[3] = fbsub[b[3]]; return Pack(b); } private static byte product(uint x, uint y) { byte[] xb = new byte[4]; byte[] yb = new byte[4]; Unpack(x, xb); Unpack(y, yb); return (byte)(bmul(xb[0], yb[0]) ^ bmul(xb[1], yb[1]) ^ bmul(xb[2], yb[2]) ^ bmul(xb[3], yb[3])); } private static uint InvMixCol(uint x) { uint y, m; byte[] b = new byte[4]; m = Pack(InCo); b[3] = product(m, x); m = RotateLeft(m, 24); b[2] = product(m, x); m = RotateLeft(m, 24); b[1] = product(m, x); m = RotateLeft(m, 24); b[0] = product(m, x); y = Pack(b); return y; } private static byte ByteSub(byte x) { byte y; y = ptab[255 - ltab[x]]; x = y; x = RotateLeft(x, 1); y ^= x; x = RotateLeft(x, 1); y ^= x; x = RotateLeft(x, 1); y ^= x; x = RotateLeft(x, 1); y ^= x; y ^= 0x63; return y; } public static void gentables() { byte y; byte[] b = new byte[4]; ltab[0] = 0; ptab[0] = 1; ltab[1] = 0; ptab[1] = 3; ltab[3] = 1; for (int i = 2; i <= 255; i++) { ptab[i] = (byte)(ptab[i - 1] ^ xtime(ptab[i - 1])); ltab[ptab[i]] = (byte)i; } fbsub[0] = 0x63; rbsub[0x63] = 0; for (int i = 1; i <= 255; i++) { y = ByteSub((byte)i); fbsub[i] = y; rbsub[y] = (byte)i; } y = 1; for (int i = 0; i <= 29; i++) { rco[i] = y; y = xtime(y); } for (int i = 0; i <= 255; i++) { y = fbsub[i]; b[3] = (byte)(y ^ xtime(y)); b[2] = y; b[1] = y; b[0] = xtime(y); ftable[i] = Pack(b); y = rbsub[i]; b[3] = bmul(InCo[0], y); b[2] = bmul(InCo[1], y); b[1] = bmul(InCo[2], y); b[0] = bmul(InCo[3], y); rtable[i] = Pack(b); } } public static void gkey(int nb, int nk, byte[] key) { int i, j, k, m, N; int C1, C2, C3; uint[] CipherKey = new uint[8]; Nb = nb; Nk = nk; if (Nb >= Nk) Nr = 6 + Nb; else Nr = 6 + Nk; C1 = 1; if (Nb < 8) { C2 = 2; C3 = 3; } else { C2 = 3; C3 = 4; } for (m = j = 0; j < nb; j++, m += 3) { fi[m] = (byte)((j + C1) % nb); fi[m + 1] = (byte)((j + C2) % nb); fi[m + 2] = (byte)((j + C3) % nb); ri[m] = (byte)((nb + j - C1) % nb); ri[m + 1] = (byte)((nb + j - C2) % nb); ri[m + 2] = (byte)((nb + j - C3) % nb); } N = Nb * (Nr + 1); for (i = j = 0; i < Nk; i++, j += 4) CipherKey[i] = PackFrom(key, j); for (i = 0; i < Nk; i++) fkey[i] = CipherKey[i]; for (j = Nk, k = 0; j < N; j += Nk, k++) { fkey[j] = fkey[j - Nk] ^ SubByte(RotateLeft(fkey[j - 1], 24)) ^ rco[k]; if (Nk <= 6) { for (i = 1; i < Nk && (i + j) < N; i++) fkey[i + j] = fkey[i + j - Nk] ^ fkey[i + j - 1]; } else { for (i = 1; i < 4 && (i + j) < N; i++) fkey[i + j] = fkey[i + j - Nk] ^ fkey[i + j - 1]; if ((j + 4) < N) fkey[j + 4] = fkey[j + 4 - Nk] ^ SubByte(fkey[j + 3]); for (i = 5; i < Nk && (i + j) < N; i++) fkey[i + j] = fkey[i + j - Nk] ^ fkey[i + j - 1]; } } for (j = 0; j < Nb; j++) rkey[j + N - Nb] = fkey[j]; for (i = Nb; i < (N - Nb); i += Nb) { k = N - Nb - i; for (j = 0; j < Nb; j++) rkey[k + j] = InvMixCol(fkey[i + j]); } for (j = (N - Nb); j < N; j++) rkey[j - N + Nb] = fkey[j]; } public static void encrypt(byte[] buff) { int i, j, k, m; uint[] a = new uint[8]; uint[] b = new uint[8]; uint[] x, y, t; for (i = j = 0; i < Nb; i++, j += 4) { a[i] = PackFrom(buff, j); a[i] ^= fkey[i]; } k = Nb; x = a; y = b; for (i = 1; i < Nr; i++) { for (m = j = 0; j < Nb; j++, m += 3) y[j] = fkey[k++] ^ ftable[(byte)x[j]] ^ RotateLeft(ftable[(byte)(x[fi[m]] >> 8)], 8) ^ RotateLeft(ftable[(byte)(x[fi[m + 1]] >> 16)], 16) ^ RotateLeft(ftable[x[fi[m + 2]] >> 24], 24); t = x; x = y; y = t; } for (m = j = 0; j < Nb; j++, m += 3) y[j] = fkey[k++] ^ (uint)fbsub[(byte)x[j]] ^ RotateLeft((uint)fbsub[(byte)(x[fi[m]] >> 8)], 8) ^ RotateLeft((uint)fbsub[(byte)(x[fi[m + 1]] >> 16)], 16) ^ RotateLeft((uint)fbsub[x[fi[m + 2]] >> 24], 24); for (i = j = 0; i < Nb; i++, j += 4) { UnpackFrom(y[i], buff, j); x[i] = y[i] = 0; } } public static void decrypt(byte[] buff) { int i, j, k, m; uint[] a = new uint[8]; uint[] b = new uint[8]; uint[] x, y, t; for (i = j = 0; i < Nb; i++, j += 4) { a[i] = PackFrom(buff, j); a[i] ^= rkey[i]; } k = Nb; x = a; y = b; for (i = 1; i < Nr; i++) { for (m = j = 0; j < Nb; j++, m += 3) y[j] = rkey[k++] ^ rtable[(byte)x[j]] ^ RotateLeft(rtable[(byte)(x[ri[m]] >> 8)], 8) ^ RotateLeft(rtable[(byte)(x[ri[m + 1]] >> 16)], 16) ^ RotateLeft(rtable[x[ri[m + 2]] >> 24], 24); t = x; x = y; y = t; } for (m = j = 0; j < Nb; j++, m += 3) y[j] = rkey[k++] ^ (uint)rbsub[(byte)x[j]] ^ RotateLeft((uint)rbsub[(byte)(x[ri[m]] >> 8)], 8) ^ RotateLeft((uint)rbsub[(byte)(x[ri[m + 1]] >> 16)], 16) ^ RotateLeft((uint)rbsub[x[ri[m + 2]] >> 24], 24); for (i = j = 0; i < Nb; i++, j += 4) { UnpackFrom(y[i], buff, j); x[i] = y[i] = 0; } } // ------------------------------------------------------------------------------------- // The code below are utility functions for calling the Rijndael code above // ------------------------------------------------------------------------------------- /// <summary>This version of EncryptData takes the message, password /// and IV as byte arrays and encrypts the message, returning the encrypted text /// as a byte array. /// /// NOTE: In this implementation I add four bytes to the start of the message and /// use that space to store the length of the message. Then the sister DecryptData /// function knows where to trim the message before returning it. Not all /// encryption routines will use this method. The only parts specified in the /// Rijndael standard are for use of the gentables, gkey, encrypt and decrypt /// functions. So if you have some data encrypted with another implementation /// of Rijndael, or you are encypting data that will be decrypted with another /// implementation, then you will need to know how they are recording the length of /// the message (if at all), and if you are encrypting/decrypting strings whether /// they based it on Ascii or Unicode (or some other character set). /// </summary> /// <param name="message">The encrypted message</param> /// <param name="password">The password/key to encrypt the message with</param> /// <param name="initialisationVector">The IV as a string</param> /// <param name="blockSize">The block size used to encrypt the message</param> /// <param name="keySize">The key size used to encrypt the message</param> /// <param name="cryptMode">The encryption mode, CBC or ECB, used to encrypt the message</param> public static byte[] EncryptData(byte[] message, byte[] password, byte[] initialisationVector, BlockSize blockSize, KeySize keySize, EncryptionMode cryptMode) { byte[] messageData, keyBlock, vectorBlock, dataBlock; int messageLength, encodedLength, nb, nk; // Dont do any work if message is empty messageLength = message.Length; if (messageLength <= 0) return message; // Set up arrays based on block size switch (blockSize) { case BlockSize.Block128: nb = 4; break; case BlockSize.Block192: nb = 6; break; default: // assume 256 nb = 8; break; } vectorBlock = new byte[nb * 4]; dataBlock = new byte[nb * 4]; for (int i = 0; i < (nb * 4); i++) { vectorBlock[i] = 0; dataBlock[i] = 0; } // Set up array based on key size switch (keySize) { case KeySize.Key128: nk = 4; break; case KeySize.Key192: nk = 6; break; default: // assume 256 nk = 8; break; } keyBlock = new byte[nk * 4]; for (int i = 0; i < (nk * 4); i++) { keyBlock[i] = 0; } // Key will be zero padded, or trimmed to correct size for (int i = 0; (i < password.Length) && (i < (nk * 4)); i++) keyBlock[i] = password[i]; // Vector will be zero padded, or trimmed to correct size for (int i = 0; (i < initialisationVector.Length) && (i < (nb * 4)); i++) vectorBlock[i] = initialisationVector[i]; // Prepare the key and tables using the Rijndael fuinctions gentables(); gkey(nb, nk, keyBlock); // Add 4 bytes to message to store message length, then make sure the length // is a Mod of the block size encodedLength = messageLength + 4; if ((encodedLength % (nb * 4)) != 0) encodedLength += ((nb * 4) - (encodedLength % (nb * 4))); messageData = new byte[encodedLength]; // Put message length on front of message messageData[0] = (byte)messageLength; messageData[1] = (byte)(messageLength >> 8); messageData[2] = (byte)(messageLength >> 16); messageData[3] = (byte)(messageLength >> 24); Array.Copy(message, 0, messageData, 4, messageLength); // Zero pad the end of the array for (int i = (messageLength + 4); i < encodedLength; i++) messageData[i] = 0; // Loop through the message encrypting it a block at a time for (int i = 0; i < encodedLength; i += (nb * 4)) { Array.Copy(messageData, i, dataBlock, 0, (nb * 4)); // Do some XORing if in CBC mode if (cryptMode == EncryptionMode.ModeCBC) for (int j = 0; j < (nb * 4); j++) dataBlock[j] ^= vectorBlock[j]; encrypt(dataBlock); if (cryptMode == EncryptionMode.ModeCBC) Array.Copy(dataBlock, 0, vectorBlock, 0, dataBlock.Length); Array.Copy(dataBlock, 0, messageData, i, (nb * 4)); } return messageData; } /// <summary>This version of EncryptData takes the message, password /// and IV as strings and encrypts the message, returning the encrypted text as a string. /// </summary> /// <param name="message">The plain text message</param> /// <param name="password">The password/key to encrypt the message with</param> /// <param name="initialisationVector">The IV as a string</param> /// <param name="blockSize">The block size used to encrypt the message</param> /// <param name="keySize">The key size used to encrypt the message</param> /// <param name="cryptMode">The encryption mode, CBC or ECB, used to encrypt the message</param> /// <param name="returnAsHex">Whether the encrypted message is to be returned as Hex</param> public static string EncryptData(string message, string password, string initialisationVector, BlockSize blockSize, KeySize keySize, EncryptionMode cryptMode, bool returnAsHex) { byte[] messageData, passwordData, vectorData; // If message is empty dont bother doing any work if (message.Length <= 0) return ""; System.Text.UnicodeEncoding encoderUnicode = new System.Text.UnicodeEncoding(); // Convert message, key and IV to byte arrays messageData = encoderUnicode.GetBytes(message); passwordData = encoderUnicode.GetBytes(password); vectorData = encoderUnicode.GetBytes(initialisationVector); // Return encrypted message as string (hex version of bytes if required) if (returnAsHex) return BytesToHex(EncryptData(messageData, passwordData, vectorData, blockSize, keySize, cryptMode)); else return encoderUnicode.GetString(EncryptData(messageData, passwordData, vectorData, blockSize, keySize, cryptMode)); } /// <summary>This version of DecryptData takes the encrypted message, password /// and IV as byte arrays and decrypts the message, returning the plain text as /// a byte array. /// </summary> /// <param name="message">The encrypted message</param> /// <param name="password">The password/key that was used to encrypt the message</param> /// <param name="initialisationVector">The IV</param> /// <param name="blockSize">The block size used in encrypting the message</param> /// <param name="keySize">The key size used in encrypting the message</param> /// <param name="cryptMode">The encryption mode, CBC or ECB, used in encrypting the message</param> public static byte[] DecryptData(byte[] message, byte[] password, byte[] initialisationVector, BlockSize blockSize, KeySize keySize, EncryptionMode cryptMode) { byte[] messageData, keyBlock, vectorBlock, dataBlock; int messageLength, encodedLength, nb, nk; // Dont do any work if message is empty encodedLength = message.Length; if (encodedLength <= 0) return message; // Set up arrays based on block size switch (blockSize) { case BlockSize.Block128: nb = 4; break; case BlockSize.Block192: nb = 6; break; default: // assume 256 nb = 8; break; } vectorBlock = new byte[nb * 4]; dataBlock = new byte[nb * 4]; for (int i = 0; i < (nb * 4); i++) { vectorBlock[i] = 0; dataBlock[i] = 0; } // Set up array based on key size switch (keySize) { case KeySize.Key128: nk = 4; break; case KeySize.Key192: nk = 6; break; default: // assume 256 nk = 8; break; } keyBlock = new byte[nk * 4]; for (int i = 0; i < (nk * 4); i++) { keyBlock[i] = 0; } // Key will be zero padded, or trimmed to correct size for (int i = 0; (i < password.Length) && (i < (nk * 4)); i++) keyBlock[i] = password[i]; // Vector will be zero padded, or trimmed to correct size for (int i = 0; (i < initialisationVector.Length) && (i < (nb * 4)); i++) vectorBlock[i] = initialisationVector[i]; // Prepare the key and tables using the Rijndael fuinctions gentables(); gkey(nb, nk, keyBlock); // Decrypt a block at a time for (int i = 0; i < encodedLength; i += (nb * 4)) { Array.Copy(message, i, dataBlock, 0, (nb * 4)); decrypt(dataBlock); // If CBC mode we need to do some extra XORing if (cryptMode == EncryptionMode.ModeCBC) { for (int j = 0; j < (nb * 4); j++) dataBlock[j] ^= vectorBlock[j]; Array.Copy(message, i, vectorBlock, 0, (nb * 4)); } Array.Copy(dataBlock, 0, message, i, (nb * 4)); } // Message length was originally put on front of message, so retrieve it messageLength = (int)message[0] | (((int)message[1]) << 8) | (((int)message[2]) << 16) | (((int)message[3]) << 24); // Get the original message from the clear text messageData = new byte[messageLength]; Array.Copy(message, 4, messageData, 0, messageLength); return messageData; } /// <summary>This version of DecryptData takes the encrypted message, password /// and IV as strings and decrypts the message, returning the plain text as a string. /// </summary> /// <param name="message">The encrypted message</param> /// <param name="password">The password/key that was used to encrypt the message</param> /// <param name="initialisationVector">The IV as a string</param> /// <param name="blockSize">The block size used in encrypting the message</param> /// <param name="keySize">The key size used in encrypting the message</param> /// <param name="cryptMode">The encryption mode, CBC or ECB, used in encrypting the message</param> /// <param name="messageAsHex">Whether the encrypted message was returned as Hex</param> public static string DecryptData(string message, string password, string initialisationVector, BlockSize blockSize, KeySize keySize, EncryptionMode cryptMode, bool messageAsHex) { byte[] messageData, passwordData, vectorData; // Dont do any work is the message is empty if (message.Length <= 0) return ""; System.Text.UnicodeEncoding encoderUnicode = new System.Text.UnicodeEncoding(); // Was message supplied in Hex or as simple string if (messageAsHex) messageData = HexToBytes(message); else messageData = encoderUnicode.GetBytes(message); // Convert key and IV to byte arrays passwordData = encoderUnicode.GetBytes(password); vectorData = encoderUnicode.GetBytes(initialisationVector); // Return the decrypted plain test as a string return encoderUnicode.GetString(DecryptData(messageData, passwordData, vectorData, blockSize, keySize, cryptMode)); } /// <summary>Utility function to convert a byte array to a string</summary> public static string BytesToString(byte[] message) { if (message.Length <= 0) return ""; System.Text.UnicodeEncoding encoderUnicode = new System.Text.UnicodeEncoding(); return encoderUnicode.GetString(message); } /// <summary>Utility function to convert a string to a byte array</summary> public static byte[] StringToBytes(string message) { if (message.Length <= 0) return new byte[0]; System.Text.UnicodeEncoding encoderUnicode = new System.Text.UnicodeEncoding(); return encoderUnicode.GetBytes(message); } /// <summary>Utility function to convert a byte array to a string of hex</summary> public static string BytesToHex(byte[] message) { System.Text.StringBuilder temp = new System.Text.StringBuilder(); // Convert each byte to hex and add to string for (int i = 0; i < message.Length; i++) temp.Append(string.Format("{0:X2}", message[i])); return temp.ToString(); } /// <summary>Utility function to convert a string of hex to a byte array</summary> public static byte[] HexToBytes(string message) { // Strip non hex message = System.Text.RegularExpressions.Regex.Replace(message.ToUpper(), "[^0-9A-F]", ""); // Prepare return array byte[] data = new byte[message.Length / 2]; // Convert hex character pairs to bytes for (int i = 0; i < message.Length; i += 2) { data[i / 2] = (Convert.ToByte(message.Substring(i, 2), 16)); } return data; } } } }
Reference
- http://stackoverflow.com/questions/20801952/converting-vb6-aes-rijndael-block-cipher-to-c-sharp-by-phil-fresle
- http://stackoverflow.com/questions/1679296/password-encryption-decryption-between-classic-asp-and-asp-net/14674957
- http://www.frez.co.uk/free
Discover more from naiwaen@DebuggingSoft
Subscribe to get the latest posts sent to your email.