using System; using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; using System.Security.Cryptography; using System.IO; //using System.Windows.Forms; using System.Collections.ObjectModel; namespace CrossProduct.Core { /// /// Text Encryption Types that are Supported by the PerSeCryptography class. /// internal enum PerSeTextEncryptionTypes { Code, Filename, Text } /// /// The PerSeCryptography class contains functionality to perform /// custom PerSe cryptography routines /// public class PerSeCryptography { #region Member Variables private const string KeyEncryptionString = "7:i#t~QzV_BMF4u3!" + "XH;/)=(8dhEUnD.OJ6%0@G2&rNfqSv\\ja[LxYK$]l9"; private const string ValidCodeCharacters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; private const string ValidFilenameCharacters = "!#$%&'()-0123456789@ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "^_`{}~ƒ¡¢£¥ª°±²µ·º»¼½¿ÄÅÆÇÉÑÖÜß÷"; private const string ValidTextCharacters = "!#$%&()-0123456789@ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "^_`{}~ƒ¡¢£¥ª°±²µ·º»¼½¿ÄÅÆÇÉÑÖÜß÷ ;:\",.*/\\<>?|+="; private const int KeyStringLength = 5; private const int MaxExtraEncryptionCharacters = 7; private const int SplitKeyIndex = 4; private const int InvalidStringCharacters = 50; private const int EncryptionKeyBitMask = 15; private const int EncryptionKeyShift = 4; private const int EncryptionKeyMaxUnchangedCount = 10; private const int EncryptionKeySkipKeys = 5; private const int EncryptionKeySeed = 32767; private const int RandomNumberBitMask = 65535; private const int RandomNumberMultiplier = 17405; private const int RandomNumberExtraValue = 196; private const float RandomNumberDivisor = 65536.0f; private int _currentRandomNumber; private Random _randomNumGen; #endregion /// /// Initializes a new instance of the class. /// /// Change Made On: 6/23/2009 /// Change Made By: Shane.Calhoun /// ============================================== public PerSeCryptography() { _randomNumGen = new Random(); _currentRandomNumber = _randomNumGen.Next() & RandomNumberBitMask; } /// /// Decrypts a String with an Embedded Key /// /// encrypted text string to decrypt /// the decrypted text string public string DecryptText(string encryptedText) { return Decrypt(encryptedText, PerSeTextEncryptionTypes.Text); } /// /// Decrypts a Text string using a key /// /// text string to decrypt /// key to use to decrypt the string /// decrypted text public string DecryptText(string encryptedText, int key) { return Decrypt(encryptedText, key, PerSeTextEncryptionTypes.Text); } /// /// Encrypts a String to Binary /// /// text to encrypt /// encrypted text public string EncryptBinaryString(string decryptedText) { try { return DataEncryption.EncryptString(decryptedText); } catch (Exception ex) { throw new Exception("Error Encrypting binary String", ex); } } /// /// Decrypts a text string from binary to text /// /// The encrypted text. /// decrypted text public string DecryptBinaryString(string encryptedText) { try { return DataEncryption.DecryptString(encryptedText); } catch (Exception ex) { throw new Exception("Error Decrypting Binary String", ex); } } /// /// Encrypts a Text string using a key and industry standard encryption modes - Rijndael will be default which is the same as AES 256 bit encryption. /// /// text string to encrypt /// key to use to encrypt the string /// Mode of encryption of choice - "DES" or "RC2" or "Rijndael" or "TripleDES" - Default will be "Rijndael" /// the text encrypted public string EncryptText(string text, string key, string encryptionMode) { byte[] encryptedData = Encrypt(text, key, encryptionMode); return Convert.ToBase64String(encryptedData); } /// /// Decrypts a Text string using a key and industry standard encryption modes - Rijndael will be default which is the same as AES 256 bit encryption. /// /// text string to decrypt /// key to use to decrypt the string /// Mode of encryption of choice - "DES" or "RC2" or "Rijndael" or "TripleDES" - Default will be "Rijndael" /// decrypted text public string DecryptText(string text, string key, string encryptionMode) { string decryptedData = string.Empty; decryptedData = Decrypt(Convert.FromBase64String(text), key, encryptionMode); return decryptedData; } /// /// Encrypts Key Text /// /// key text /// key to use when encrypting the key /// public string EncryptText(string text, int key) { return Encrypt(text, key, PerSeTextEncryptionTypes.Text); } /// /// Encrypts text /// /// Text to encrypt /// the text encrypted public string EncryptText(string text) { string strEncryptValue; strEncryptValue = Encrypt(text, PerSeTextEncryptionTypes.Text); return strEncryptValue; //return Encrypt( text, PerSeTextEncryptionTypes.Text ); } /// /// Encrypts text /// /// Text to encrypt /// the text encrypted public string EncryptText(string text, bool EnsureUniqueKey, string assemblyname) { string strEncryptValue; strEncryptValue = Encrypt(text, PerSeTextEncryptionTypes.Text); if (EnsureUniqueKey && !String.IsNullOrEmpty(assemblyname)) strEncryptValue = SimpleStringBinaryConverter.GetString(strEncryptValue, assemblyname); return strEncryptValue; //return Encrypt( text, PerSeTextEncryptionTypes.Text ); } /// /// Encrypts the text. /// /// The text. /// /// Change Made On: 7/15/2010 /// Change Made By: Shane.Calhoun /// ============================================== public ReadOnlyCollection EncryptText(ReadOnlyCollection text) { List result = new List(); foreach (string value in text) { result.Add(Encrypt(value, PerSeTextEncryptionTypes.Text)); } ReadOnlyCollection temp = new ReadOnlyCollection(result); return temp; } /// /// Decrypts a Text string using an Embedded key /// /// encrypted text to decrypt /// /// decrypted text string private string Decrypt(string encryptedText, PerSeTextEncryptionTypes encryptionType) { try { StringBuilder decryptedText = new StringBuilder(); int key = GetEmbeddedKey(encryptedText); int index = 0; if (key != -1) { index = encryptedText.Length - (KeyStringLength - SplitKeyIndex) + 1; if (index >= (SplitKeyIndex + 1)) { string encryptedTextWithoutKey = encryptedText.Substring(SplitKeyIndex, (index - SplitKeyIndex - 1)); decryptedText.Append(Decrypt(encryptedTextWithoutKey, key, encryptionType)); } } else { for (index = 0; index < InvalidStringCharacters; index++) { int charIndex = RandomNumber(ValidTextCharacters.Length); decryptedText.Append(ValidTextCharacters[charIndex]); } } return decryptedText.ToString(); } catch (Exception ex) { throw new Exception("Error Decrypting string", ex); } } /// /// Decrypts a text string /// /// Encrypted Text to decrypt /// key to use when decrypting the text /// the type of text to decrypt /// the encrypted string decrypted private string Decrypt(string encryptedText, int key, PerSeTextEncryptionTypes encryptionType) { try { string validCharacters; string encryptionCodeCharacters; int extraCharacerOdds; int extraCharacters; int realCharacters; int originalKey; encryptionCodeCharacters = GenerateEncryptionCode(key, encryptionType); originalKey = _currentRandomNumber; _currentRandomNumber = key; switch (encryptionType) { case PerSeTextEncryptionTypes.Code: { validCharacters = ValidCodeCharacters; extraCharacters = 0; realCharacters = encryptedText.Length; extraCharacerOdds = 0; break; } case PerSeTextEncryptionTypes.Filename: { validCharacters = ValidFilenameCharacters; extraCharacters = 0; realCharacters = encryptedText.Length; extraCharacerOdds = 0; break; } default: // Text { validCharacters = ValidTextCharacters; extraCharacters = RandomNumber(MaxExtraEncryptionCharacters + 1); realCharacters = encryptedText.Length - extraCharacters; if (realCharacters > 0) extraCharacerOdds = (int)Decimal.Truncate((decimal)((50 * extraCharacters) / realCharacters)); else extraCharacerOdds = 0; break; } } int index = 0; int characterPositionIndex; StringBuilder decryptedText = new StringBuilder(); bool isFilename = (encryptionType == PerSeTextEncryptionTypes.Filename); while (realCharacters > 0) { if (extraCharacters > 0) { if (extraCharacerOdds >= (RandomNumber(100) + 1)) { RandomNumber(0); // Need (unused) call here to keep in synch with encrypt side index++; --extraCharacters; } } characterPositionIndex = encryptionCodeCharacters.IndexOf(encryptedText[index]); if (characterPositionIndex < 0) { decryptedText.Append(encryptedText[index]); } else { characterPositionIndex = characterPositionIndex - RandomNumber(validCharacters.Length) - 1; while (characterPositionIndex < 0) { characterPositionIndex += validCharacters.Length; } decryptedText.Append(validCharacters[characterPositionIndex]); } // Since all subdirectories of a directory path need to be encrypted/decrypted // identically, we reset the seed value whenever we start a new subdirectory. if (isFilename && (encryptedText[index] == '\\')) { _currentRandomNumber = key; } index++; realCharacters--; } _currentRandomNumber = originalKey; return decryptedText.ToString(); } catch (Exception ex) { throw new Exception("Error decrypting string", ex); } } /// /// Decrypts an encrypted key /// /// The encrypted key. /// the key in it's original integer form private int DecryptKey(string encryptedKey) { try { int count; int index; int maxIndex; int tempKey; int decryptedKey; int value; maxIndex = KeyEncryptionString.Length; tempKey = 0; for (count = 1; count < encryptedKey.Length; count++) { index = KeyEncryptionString.IndexOf(encryptedKey[count]); value = index - KeyEncryptionString.IndexOf(encryptedKey[count - 1]); if (value < 0) { value += maxIndex; } if (value == 16) { value = 0; } tempKey = (tempKey << EncryptionKeyShift) + (value & EncryptionKeyBitMask); } decryptedKey = 0; for (count = 0; count < (16 / 4); count++) { decryptedKey = (decryptedKey << EncryptionKeyShift) | (tempKey & EncryptionKeyBitMask); tempKey = tempKey >> EncryptionKeyShift; } return decryptedKey; } catch (Exception ex) { throw new Exception("Error decrypting key", ex); } } /// /// Retrieves the embedded key out of Encrypted Text /// /// the encrypted text to retrieve the embedded key from /// embedded encrypted key private int GetEmbeddedKey(string encryptedText) { int index; int decryptedKey; string encryptedKey; decryptedKey = -1; index = encryptedText.Length - (KeyStringLength - SplitKeyIndex) + 1; if (index >= (SplitKeyIndex + 1)) { encryptedKey = encryptedText.Substring(0, SplitKeyIndex) + encryptedText.Substring(index - 1); decryptedKey = DecryptKey(encryptedKey); } return decryptedKey; } /// /// Generates a valid Encryption Key /// /// encryption key private int GenerateEncryptionKey() { string charString; string codeString; int key; int identicalCharacterCount; bool isKeyValid = false; do { for (int i = 0; i < EncryptionKeySkipKeys; i++) { RandomNumber(EncryptionKeySeed); } key = _currentRandomNumber; codeString = GenerateEncryptionCode(key); charString = ValidTextCharacters; identicalCharacterCount = 0; for (int i = 0; i < codeString.Length; i++) { if (codeString[i] == charString[i]) { identicalCharacterCount++; } } isKeyValid = ((identicalCharacterCount < EncryptionKeyMaxUnchangedCount) && (key != -1)); } while (!isKeyValid); return key; } /// /// Encrypts text for the specified encryption type /// /// text to encrypt /// encryption type to perform /// the text encrypted private string Encrypt(string decryptedText, PerSeTextEncryptionTypes encryptionType) { int decryptedKey; string encryptedKey = string.Empty; decryptedKey = GenerateEncryptionKey(); encryptedKey = EncryptKey(decryptedKey); string encryptedText = Encrypt(decryptedText, decryptedKey, encryptionType); encryptedText = encryptedKey.Substring(0, SplitKeyIndex) + encryptedText + encryptedKey.Substring(SplitKeyIndex, encryptedKey.Length - SplitKeyIndex); return encryptedText; } /// /// Encrypts text for the specified encryption type /// /// text to encrypt /// key to use for encryption /// type of encryption to perform /// decrypted text encrypted private string Encrypt(string decryptedText, int key, PerSeTextEncryptionTypes encryptionType) { try { string charString = string.Empty; string codeString = string.Empty; int extraCharacterOdds; int extraCharacters; int posIndex; int originalKey; StringBuilder encryptedText = new StringBuilder(); codeString = GenerateEncryptionCode(key); originalKey = _currentRandomNumber; _currentRandomNumber = key; charString = ValidTextCharacters; extraCharacters = RandomNumber(MaxExtraEncryptionCharacters + 1); if (decryptedText.Length > 0) { extraCharacterOdds = (50 * extraCharacters) / decryptedText.Length; } else { extraCharacterOdds = 0; } if (decryptedText.Length > 0) { for (int i = 0; i < decryptedText.Length; i++) { if (extraCharacters > 0) { if (extraCharacterOdds >= (RandomNumber(100) + 1)) { posIndex = RandomNumber(codeString.Length) + 1; if (posIndex >= codeString.Length) { posIndex = codeString.Length - 1; } encryptedText.Append(codeString[posIndex]); extraCharacters--; } } posIndex = charString.IndexOf(decryptedText[i]); if (posIndex < 0) { encryptedText.Append(decryptedText[i]); } else { posIndex = ((posIndex + RandomNumber(codeString.Length) + 1) % codeString.Length); encryptedText.Append(codeString[posIndex]); } } } while (extraCharacters > 0) { posIndex = RandomNumber(codeString.Length) + 1; if (posIndex >= codeString.Length) { posIndex = codeString.Length - 1; } encryptedText.Append(codeString[posIndex]); extraCharacters--; } _currentRandomNumber = originalKey; return encryptedText.ToString(); } catch (Exception ex) { throw new Exception("Error Encrypting key", ex); } } /// /// Encrypts a Key /// /// key to encrypt /// encrypted key private string EncryptKey(int decryptedKey) { int count; int index; int maxIndex; StringBuilder encryptedKey = new StringBuilder(); int value; maxIndex = KeyEncryptionString.Length; index = RandomNumber(maxIndex); encryptedKey.Append(KeyEncryptionString[index]); for (count = 0; count < (16 / 4); count++) { value = decryptedKey & EncryptionKeyBitMask; if (value == 0) { value = 16; } decryptedKey >>= EncryptionKeyShift; index = ((index + value) % maxIndex); encryptedKey.Append(KeyEncryptionString[index]); } return encryptedKey.ToString(); } /// /// Generates a Random number based on the Value, seeds and other custom inhouse /// values /// /// random number seed /// private int RandomNumber(int seed) { float newValue; int newRandomNumber; _currentRandomNumber = ((_currentRandomNumber * RandomNumberMultiplier) + RandomNumberExtraValue) & RandomNumberBitMask; newValue = _currentRandomNumber / RandomNumberDivisor; newRandomNumber = (int)Decimal.Truncate((decimal)(seed * newValue)); return newRandomNumber; } /// /// Generates an Encryption Code String based on the Seed /// /// seed to build the encryption code string for /// encryption code string private string GenerateEncryptionCode(int seed) { return GenerateEncryptionCode(seed, PerSeTextEncryptionTypes.Text); } /// /// Generates an Encryption Code String based on the Seed and Encryption Type /// /// seed to build the encryption code string for /// Encryption type to build the encryption code string for /// encryption code string private string GenerateEncryptionCode(int seed, PerSeTextEncryptionTypes encryptionType) { try { StringBuilder encryptionCodeString = new StringBuilder(); StringBuilder validEncryptionCharacters = new StringBuilder(); switch (encryptionType) { case PerSeTextEncryptionTypes.Code: validEncryptionCharacters.Append(ValidCodeCharacters); break; case PerSeTextEncryptionTypes.Filename: validEncryptionCharacters.Append(ValidFilenameCharacters); break; default: // Text validEncryptionCharacters.Append(ValidTextCharacters); break; } int index; int originalKey = _currentRandomNumber; _currentRandomNumber = seed; while (validEncryptionCharacters.Length > 0) { index = RandomNumber(validEncryptionCharacters.Length); encryptionCodeString.Append(validEncryptionCharacters[index]); validEncryptionCharacters.Remove(index, 1); } _currentRandomNumber = originalKey; return encryptionCodeString.ToString(); } catch (Exception ex) { throw new Exception("Error Generating Encryption code", ex); } } /// /// Encrypts the specified text. /// /// The text. /// The key. /// The encryption mode. /// /// Change Made On: 5/6/2009 /// Change Made By: Shane.Calhoun /// ============================================== private byte[] Encrypt(string text, string key, string encryptionMode) { SymmetricAlgorithm cryptoObj = null; cryptoObj = GetEncryptionProviderObject(encryptionMode); byte[] bytIn = Encoding.ASCII.GetBytes(text); // create a MemoryStream so that the process can be done without I/O files MemoryStream ms = new MemoryStream(); // set the private key cryptoObj.Key = GetLegalKey(key, encryptionMode); cryptoObj.IV = GetLegalVectorSize(key, encryptionMode); // create an Encryptor from the Provider Service instance ICryptoTransform encrypto = cryptoObj.CreateEncryptor(); // create Crypto Stream that transforms a stream using the encryption CryptoStream cs = new CryptoStream(ms, encrypto, CryptoStreamMode.Write); // write out encrypted content into MemoryStream cs.Write(bytIn, 0, bytIn.Length); cs.FlushFinalBlock(); cs.Close(); return ms.ToArray(); } /// /// Decrypts the specified ciphertext. /// /// The ciphertext. /// The key. /// The encryption mode. /// /// Change Made On: 5/6/2009 /// Change Made By: Shane.Calhoun /// ============================================== private string Decrypt(byte[] ciphertext, string key, string encryptionMode) { SymmetricAlgorithm deCryptoObj = null; deCryptoObj = GetEncryptionProviderObject(encryptionMode); // create a MemoryStream with the input MemoryStream ms = new MemoryStream(ciphertext, 0, ciphertext.Length); // set the private key deCryptoObj.Key = GetLegalKey(key, encryptionMode); deCryptoObj.IV = GetLegalVectorSize(key, encryptionMode); // create a Decryptor from the Provider Service instance ICryptoTransform encrypto = deCryptoObj.CreateDecryptor(); // create Crypto Stream that transforms a stream using the decryption CryptoStream cs = new CryptoStream(ms, encrypto, CryptoStreamMode.Read); // read out the result from the Crypto Stream StreamReader sr = new StreamReader(cs); return sr.ReadToEnd(); } /// /// Gets the encryption provider object. /// /// The encryption mode. /// /// Change Made On: 5/6/2009 /// Change Made By: Shane.Calhoun /// ============================================== private SymmetricAlgorithm GetEncryptionProviderObject(string encryptionMode) { SymmetricAlgorithm tmpCryptoObj = null; switch (encryptionMode) { case "DES": tmpCryptoObj = new DESCryptoServiceProvider(); break; case "RC2": tmpCryptoObj = new RC2CryptoServiceProvider(); break; case "Rijndael": tmpCryptoObj = new RijndaelManaged(); break; case "TripleDES": tmpCryptoObj = new TripleDESCryptoServiceProvider(); break; default: tmpCryptoObj = new RijndaelManaged(); break; } return tmpCryptoObj; } /// /// Gets the legal key. /// /// The key. /// The encryption mode. /// /// Change Made On: 5/6/2009 /// Change Made By: Shane.Calhoun /// ============================================== private byte[] GetLegalKey(string Key, string encryptionMode) { string sTemp = Key; switch (encryptionMode) { case "DES": case "RC2": if (Key.Length > 8) { sTemp = Key.Substring(0, 8); } break; case "TripleDES": if (Key.Length > 16) { sTemp = Key.Substring(0, 16); } break; case "Rijndael": default: if (Key.Length > 32) { sTemp = Key.Substring(0, 32); } break; } // convert the secret key to byte array return ASCIIEncoding.ASCII.GetBytes(sTemp); } /// /// Gets the size of the legal vector. /// /// The key. /// The encryption mode. /// /// Change Made On: 5/6/2009 /// Change Made By: Shane.Calhoun /// ============================================== private byte[] GetLegalVectorSize(string Key, string encryptionMode) { string sTemp = Key; switch (encryptionMode) { case "DES": case "RC2": if (Key.Length > 8) { sTemp = Key.Substring(0, 8); } break; case "TripleDES": if (Key.Length > 8) { sTemp = Key.Substring(0, 8); } break; case "Rijndael": default: if (Key.Length > 16) { sTemp = Key.Substring(0, 16); } break; } // convert the secret key to byte array return ASCIIEncoding.ASCII.GetBytes(sTemp); } } }