using System; using System.Collections.Generic; using System.Text; using System.Security.Cryptography; using System.IO; namespace Server { public class DataCryption { public static byte[] PolyAESEncrypt(byte[] plainText, string Key) { byte[] salt; SymmetricAlgorithm algo = new RijndaelManaged(); RNGCryptoServiceProvider rngAlgo = new RNGCryptoServiceProvider(); algo.Mode = CipherMode.CBC; byte[] key = System.Text.Encoding.ASCII.GetBytes(Key); algo.GenerateIV(); salt = new byte[32]; rngAlgo.GetBytes(salt); Rfc2898DeriveBytes pwDeriveAlg = new Rfc2898DeriveBytes(key, salt, 2000); algo.Key = pwDeriveAlg.GetBytes(32); ICryptoTransform encTransform = algo.CreateEncryptor(); byte[] enced = encTransform.TransformFinalBlock(plainText, 0, plainText.Length); int origLength = enced.Length; Array.Resize(ref enced, enced.Length + salt.Length); Buffer.BlockCopy(salt, 0, enced, origLength, salt.Length); origLength = enced.Length; Array.Resize(ref enced, enced.Length + algo.IV.Length); Buffer.BlockCopy(algo.IV, 0, enced, origLength, algo.IV.Length); return enced; } public static byte[] PolyAESDecrypt(byte[] cipherText, string Key) { try { byte[] salt; SymmetricAlgorithm algo = new RijndaelManaged(); algo.Mode = CipherMode.CBC; RNGCryptoServiceProvider rngAlgo = new RNGCryptoServiceProvider(); byte[] key = System.Text.Encoding.ASCII.GetBytes(Key); byte[] cipherTextWithSalt = new byte[1]; byte[] encSalt = new byte[1]; byte[] origCipherText = new byte[1]; byte[] encIv = new byte[1]; Array.Resize(ref encIv, 16); Buffer.BlockCopy(cipherText, (int)(cipherText.Length - 16), encIv, 0, 16); Array.Resize(ref cipherTextWithSalt, (int)(cipherText.Length - 16)); Buffer.BlockCopy(cipherText, 0, cipherTextWithSalt, 0, (int)(cipherText.Length - 16)); Array.Resize(ref encSalt, 32); Buffer.BlockCopy(cipherTextWithSalt, (int)(cipherTextWithSalt.Length - 32), encSalt, 0, 32); Array.Resize(ref origCipherText, (int)(cipherTextWithSalt.Length - 32)); Buffer.BlockCopy(cipherTextWithSalt, 0, origCipherText, 0, (int)(cipherTextWithSalt.Length - 32)); algo.IV = encIv; salt = encSalt; Rfc2898DeriveBytes pwDeriveAlg = new Rfc2898DeriveBytes(key, salt, 2000); algo.Key = pwDeriveAlg.GetBytes(32); ICryptoTransform decTransform = algo.CreateDecryptor(); byte[] plainText = decTransform.TransformFinalBlock(origCipherText, 0, origCipherText.Length); return plainText; } catch (CryptographicException e) { throw e; } } static string strRC2Encryption(string strInput, string strKey, string strIV) { try { byte[] byteInput = Encoding.UTF8.GetBytes(strInput); byte[] byteKey = Encoding.ASCII.GetBytes(strKey); byte[] byteIV = Encoding.ASCII.GetBytes(strIV); MemoryStream MS = new MemoryStream(); RC2CryptoServiceProvider CryptoMethod = new RC2CryptoServiceProvider(); CryptoStream CS = new CryptoStream(MS, CryptoMethod.CreateEncryptor(byteKey, byteIV), CryptoStreamMode.Write); CS.Write(byteInput, 0, byteInput.Length); CS.FlushFinalBlock(); return Convert.ToBase64String(MS.ToArray()); } catch (Exception up) { throw up; //YUCK! ;D } } static string strRC2Decryption(string strInput, string strKey, string strIV) { try { byte[] byteInput = Convert.FromBase64String(strInput); byte[] byteKey = Encoding.ASCII.GetBytes(strKey); byte[] byteIV = Encoding.ASCII.GetBytes(strIV); MemoryStream MS = new MemoryStream(); RC2CryptoServiceProvider RC2 = new RC2CryptoServiceProvider(); CryptoStream CS = new CryptoStream(MS, RC2.CreateDecryptor(byteKey, byteIV), CryptoStreamMode.Write); CS.Write(byteInput, 0, byteInput.Length); CS.FlushFinalBlock(); return Encoding.UTF8.GetString(MS.ToArray()); } catch (Exception up) { throw up; //YUCK! ;D } } public static byte[] EncryptFromByte(byte[] plainByte, string Key, string IV) { //KEY AND IV MUST BE 8CHARS (1Byte if ((Key.Length + IV.Length) == 16) { //Van string na bytes, dan een randompass generate geencrypt in RC2 //met de Client/Server Pass&IV. Encryptie van pass en van AES DATA //encrypt na een base dan weer na bytes om daarna te kunnen worden //gesplit in Decrypt(). string plainPass = RandomPassword.Generate(32); string encPass = strRC2Encryption(plainPass, Key, IV); string encByte = Convert.ToBase64String(PolyAESEncrypt(plainByte, plainPass)); return Encoding.Default.GetBytes(encByte + "$" + encPass); } else throw new Exception("Error in IV or Key Size."); } public static byte[] DecryptToByte(byte[] encData, string Key, string IV) { //Data is samengevoegd met een $, AES = 0, PASS = 1. string[] splitData = Encoding.Default.GetString(encData).Split('$'); string plainPass = strRC2Decryption(splitData[1], Key, IV); byte[] aesData = Convert.FromBase64String(splitData[0]); byte[] plainByte = PolyAESDecrypt(aesData, plainPass); return plainByte; } public static byte[] EncryptFromText(string plainTxt, string Key, string IV) { //KEY AND IV MUST BE 8CHARS (1Byte if ((Key.Length + IV.Length) == 16) { //Van string na bytes, dan een randompass generate geencrypt in RC2 //met de Client/Server Pass&IV. Encryptie van pass en van AES DATA //encrypt na een base dan weer na bytes om daarna te kunnen worden //gesplit in Decrypt(). byte[] plainByte = Encoding.Default.GetBytes(plainTxt); string plainPass = RandomPassword.Generate(32); string encPass = strRC2Encryption(plainPass, Key, IV); string encByte = Convert.ToBase64String(PolyAESEncrypt(plainByte, plainPass)); return Encoding.Default.GetBytes(encByte + "$" + encPass); } else throw new Exception("Error in IV or Key Size."); } public static string DecryptToString(byte[] encData, string Key, string IV) { //Data is samengevoegd met een $, AES = 0, PASS = 1. string[] splitData = Encoding.Default.GetString(encData).Split('$'); string plainPass = strRC2Decryption(splitData[1], Key, IV); byte[] aesData = Convert.FromBase64String(splitData[0]); byte[] plainByte = PolyAESDecrypt(aesData, plainPass); return Encoding.Default.GetString(plainByte); } static public string EncodeTo64(string toEncode) { byte[] toEncodeAsBytes = Encoding.Default.GetBytes(toEncode); return Convert.ToBase64String(toEncodeAsBytes); } static public string DecodeFrom64(string encodedData) { byte[] encodedDataAsBytes = Convert.FromBase64String(encodedData); return Encoding.Default.GetString(encodedDataAsBytes); } public class RandomPassword { // Define default min and max password lengths. private static int DEFAULT_MIN_PASSWORD_LENGTH = 8; private static int DEFAULT_MAX_PASSWORD_LENGTH = 10; // Define supported password characters divided into groups. // You can add (or remove) characters to (from) these groups. private static string PASSWORD_CHARS_LCASE = "abcdefgijkmnopqrstwxyz"; private static string PASSWORD_CHARS_UCASE = "ABCDEFGHJKLMNPQRSTWXYZ"; private static string PASSWORD_CHARS_NUMERIC = "23456789"; private static string PASSWORD_CHARS_SPECIAL = "*-+?_&=!%{}/"; /// /// Generates a random password. /// /// /// Randomly generated password. /// /// /// The length of the generated password will be determined at /// random. It will be no shorter than the minimum default and /// no longer than maximum default. /// public static string Generate() { return Generate(DEFAULT_MIN_PASSWORD_LENGTH, DEFAULT_MAX_PASSWORD_LENGTH); } /// /// Generates a random password of the exact length. /// /// /// Exact password length. /// /// /// Randomly generated password. /// public static string Generate(int length) { return Generate(length, length); } /// /// Generates a random password. /// /// /// Minimum password length. /// /// /// Maximum password length. /// /// /// Randomly generated password. /// /// /// The length of the generated password will be determined at /// random and it will fall with the range determined by the /// function parameters. /// public static string Generate(int minLength, int maxLength) { // Make sure that input parameters are valid. if (minLength <= 0 || maxLength <= 0 || minLength > maxLength) return null; // Create a local array containing supported password characters // grouped by types. You can remove character groups from this // array, but doing so will weaken the password strength. char[][] charGroups = new char[][] { PASSWORD_CHARS_LCASE.ToCharArray(), PASSWORD_CHARS_UCASE.ToCharArray(), PASSWORD_CHARS_NUMERIC.ToCharArray(), PASSWORD_CHARS_SPECIAL.ToCharArray() }; // Use this array to track the number of unused characters in each // character group. int[] charsLeftInGroup = new int[charGroups.Length]; // Initially, all characters in each group are not used. for (int i = 0; i < charsLeftInGroup.Length; i++) charsLeftInGroup[i] = charGroups[i].Length; // Use this array to track (iterate through) unused character groups. int[] leftGroupsOrder = new int[charGroups.Length]; // Initially, all character groups are not used. for (int i = 0; i < leftGroupsOrder.Length; i++) leftGroupsOrder[i] = i; // Because we cannot use the default randomizer, which is based on the // current time (it will produce the same "random" number within a // second), we will use a random number generator to seed the // randomizer. // Use a 4-byte array to fill it with random bytes and convert it then // to an integer value. byte[] randomBytes = new byte[4]; // Generate 4 random bytes. RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider(); rng.GetBytes(randomBytes); // Convert 4 bytes into a 32-bit integer value. int seed = (randomBytes[0] & 0x7f) << 24 | randomBytes[1] << 16 | randomBytes[2] << 8 | randomBytes[3]; // Now, this is real randomization. Random random = new Random(seed); // This array will hold password characters. char[] password = null; // Allocate appropriate memory for the password. if (minLength < maxLength) password = new char[random.Next(minLength, maxLength + 1)]; else password = new char[minLength]; // Index of the next character to be added to password. int nextCharIdx; // Index of the next character group to be processed. int nextGroupIdx; // Index which will be used to track not processed character groups. int nextLeftGroupsOrderIdx; // Index of the last non-processed character in a group. int lastCharIdx; // Index of the last non-processed group. int lastLeftGroupsOrderIdx = leftGroupsOrder.Length - 1; // Generate password characters one at a time. for (int i = 0; i < password.Length; i++) { // If only one character group remained unprocessed, process it; // otherwise, pick a random character group from the unprocessed // group list. To allow a special character to appear in the // first position, increment the second parameter of the Next // function call by one, i.e. lastLeftGroupsOrderIdx + 1. if (lastLeftGroupsOrderIdx == 0) nextLeftGroupsOrderIdx = 0; else nextLeftGroupsOrderIdx = random.Next(0, lastLeftGroupsOrderIdx); // Get the actual index of the character group, from which we will // pick the next character. nextGroupIdx = leftGroupsOrder[nextLeftGroupsOrderIdx]; // Get the index of the last unprocessed characters in this group. lastCharIdx = charsLeftInGroup[nextGroupIdx] - 1; // If only one unprocessed character is left, pick it; otherwise, // get a random character from the unused character list. if (lastCharIdx == 0) nextCharIdx = 0; else nextCharIdx = random.Next(0, lastCharIdx + 1); // Add this character to the password. password[i] = charGroups[nextGroupIdx][nextCharIdx]; // If we processed the last character in this group, start over. if (lastCharIdx == 0) charsLeftInGroup[nextGroupIdx] = charGroups[nextGroupIdx].Length; // There are more unprocessed characters left. else { // Swap processed character with the last unprocessed character // so that we don't pick it until we process all characters in // this group. if (lastCharIdx != nextCharIdx) { char temp = charGroups[nextGroupIdx][lastCharIdx]; charGroups[nextGroupIdx][lastCharIdx] = charGroups[nextGroupIdx][nextCharIdx]; charGroups[nextGroupIdx][nextCharIdx] = temp; } // Decrement the number of unprocessed characters in // this group. charsLeftInGroup[nextGroupIdx]--; } // If we processed the last group, start all over. if (lastLeftGroupsOrderIdx == 0) lastLeftGroupsOrderIdx = leftGroupsOrder.Length - 1; // There are more unprocessed groups left. else { // Swap processed group with the last unprocessed group // so that we don't pick it until we process all groups. if (lastLeftGroupsOrderIdx != nextLeftGroupsOrderIdx) { int temp = leftGroupsOrder[lastLeftGroupsOrderIdx]; leftGroupsOrder[lastLeftGroupsOrderIdx] = leftGroupsOrder[nextLeftGroupsOrderIdx]; leftGroupsOrder[nextLeftGroupsOrderIdx] = temp; } // Decrement the number of unprocessed groups. lastLeftGroupsOrderIdx--; } } // Convert password characters into a string and return the result. return new string(password); } } } }