/// <summary> /// Initializes a new instance of the <see cref="RijndaelEncryptor"/> class using the user supplied key and initial vector arrays. /// NOTE: these arrays will be validated for use with the <see cref="RijndaelManaged"/> cypher. /// </summary> /// <param name="encryptedKey"></param> /// <param name="encryptedIV"></param> public RijndaelEncryptor(byte[] encryptedKey, byte[] encryptedIV) { if (encryptedKey == null) { throw new ArgumentNullException("encryptedKey"); } if (encryptedIV == null) { throw new ArgumentNullException("encryptedIV"); } //Verify encrypted key length is valid for this cryptor algo. int keylen = encryptedKey.Length << 3; if (!_crypt.ValidKeySize(keylen)) { string errmsg = "Encryption key length(" + keylen.ToString() + ") is not for this algorithm:" + _crypt.GetType().Name; throw new ApplicationException(errmsg); } //Verify encrypted iv length is valid for this cryptor algo. int len = encryptedIV.Length << 3; if (len != _crypt.BlockSize) { string errmsg = "Encryption key length(" + len.ToString() + ") is not for this algorithm:" + _crypt.GetType().Name; throw new ApplicationException(errmsg); } EncryptKey = encryptedKey; EncryptIV = encryptedIV; }
static bool IsValidKey(byte[] key) { using (var rijndael = new RijndaelManaged()) { var bitLength = key.Length * 8; return(rijndael.ValidKeySize(bitLength)); } }
static bool IsValidKey(byte[] key) { using (var rijndael = new RijndaelManaged()) { var bitLength = key.Length * 8; var maxValidKeyBitLength = rijndael.LegalKeySizes.Max(keyLength => keyLength.MaxSize); if (bitLength < maxValidKeyBitLength) { Log.WarnFormat("Encryption key is {0} bits which is less than the maximum allowed {1} bits. Consider using a {1}-bit encryption key to obtain the maximum cipher strength", bitLength, maxValidKeyBitLength); } return(rijndael.ValidKeySize(bitLength)); } }
/// <summary> /// Given an open registry key and a site key value, read the site parameters from /// the registry and return a SiteParameters object. /// </summary> /// <param name="registryKey">An open registry key</param> /// <param name="siteKey">A site key string</param> /// <returns>A SiteParameters object, or null on failure</returns> public static SiteParameters ReadFromRegistry(RegistryKey registryKey, string siteKey) { // Asbestos underpants: try { // This only works if the registry key is open and the site key is // something meaningful: if (registryKey != null && !String.IsNullOrEmpty(siteKey)) { // Look for the site key value in the registry key and convert it from // Base64 to a byte array: byte[] encryptedParams = (byte[])registryKey.GetValue(siteKey); // Set up our decryption engine. Create the Rijndael object, its // encryption key, and its initialization vector. RijndaelManaged rijndael = new RijndaelManaged(); if (rijndael.ValidKeySize(256)) { rijndael.KeySize = 256; } rijndael.Padding = PaddingMode.PKCS7; byte[] cryptKey = GenerateEncryptionKey(siteKey); byte[] iv = GenerateIV(rijndael.BlockSize / 8, siteKey); // Decrypt the raw bytes read from the registry: ICryptoTransform decryptor = rijndael.CreateDecryptor(cryptKey, iv); MemoryStream ms = new MemoryStream(encryptedParams); CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read); byte[] decryptedBytes = new byte[encryptedParams.Length]; cs.Read(decryptedBytes, 0, decryptedBytes.Length); cs.Close(); ms.Close(); // Reset the memory stream to read the raw bytes and use a binary // formatter to deserialize the object: ms = new MemoryStream(decryptedBytes); BinaryFormatter bf = new BinaryFormatter(); SiteParameters sp = (SiteParameters)bf.Deserialize(ms); return(sp); } // If the registry key wasn't open or the site key wasn't meaningful, there's // nothing to do: else { return(null); } } // If anything blows up, don't return anything we can use: catch { return(null); } }
/// <summary> /// Given an open registry key, save this set of site parameters as a subkey under /// that registry, encrypting the data as we go. /// </summary> /// <param name="registryKey">The parent registry key</param> /// <returns>True for success, false for failure</returns> public bool SaveToRegistry(RegistryKey registryKey) { // This only makes sense if the registry key exists, i.e. it is open: if (registryKey != null) { // Asbestos underpants: try { // Serialize the parameters binary data: BinaryFormatter bf = new BinaryFormatter(); MemoryStream ms = new MemoryStream(); bf.Serialize(ms, this); ms.Close(); byte[] serializedParams = ms.ToArray(); // Generate the Rijndael object, encryption key and initialization vector: RijndaelManaged rijndael = new RijndaelManaged(); if (rijndael.ValidKeySize(256)) { rijndael.KeySize = 256; } rijndael.Padding = PaddingMode.PKCS7; byte[] cryptKey = GenerateEncryptionKey(Key); byte[] iv = GenerateIV(rijndael.BlockSize / 8, Key); // Encrypt the site parameters: ICryptoTransform encryptor = rijndael.CreateEncryptor(cryptKey, iv); ms = new MemoryStream(); CryptoStream cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write); cs.Write(serializedParams, 0, serializedParams.Length); cs.FlushFinalBlock(); cs.Close(); ms.Close(); // Now convert the data to Base64 and save it to the registry using the // generated key registryKey.SetValue(Key, ms.ToArray(), RegistryValueKind.Binary); return(true); } // If anything failed, let the user know: catch { return(false); } } // If the registry key wasn't open, there's no use continuing: else { return(false); } }
public static bool ValidateKeySize(EncryptionAlgorithm algID, int Lenght) { switch (algID) { case EncryptionAlgorithm.DES: DES des = new DESCryptoServiceProvider(); return(des.ValidKeySize(Lenght)); case EncryptionAlgorithm.Rc2: RC2 rc = new RC2CryptoServiceProvider(); return(rc.ValidKeySize(Lenght)); case EncryptionAlgorithm.Rijndael: Rijndael rj = new RijndaelManaged(); return(rj.ValidKeySize(Lenght)); case EncryptionAlgorithm.TripleDes: TripleDES tDes = new TripleDESCryptoServiceProvider(); return(tDes.ValidKeySize(Lenght)); default: throw new CryptographicException("Algorithm " + algID + " Not Supported!"); } }
/// <summary> /// Encrypt the specified data and write it out to the specified file name /// </summary> /// <param name="filename">A string containing the path to the file to create. If the file /// already exists, it will be overwritten.</param> /// <param name="data">A byte array containing the data to encrypt</param> /// <param name="passphrase">A string containing the passphrase which will encrypt /// the data</param> /// <param name="iv">A byte array containing the initialization vector (IV) which will /// encrypt the data</param> public static void Write(string filename, byte[] data, string passphrase, byte[] iv) { try { // Create the output file stream. It may seem a bit odd to do this first, before we // have any data to write, but this will ensure we throw any file access exceptions // before we get to the expensive compression/encryption stuff. FileStream output = new FileStream(filename, FileMode.Create); // The first thing we have to do is append the header to the data. If we don't, we // can't guarantee later that the passphrase used to decrypt the data is the same as // the passphrase used to encrypt it. So convert the header string to bytes and stick // those bytes to the beginning of the data. byte[] headerBytes = utf8.GetBytes(header); byte[] dataWithHeader = new byte[data.Length + headerBytes.Length]; Array.Copy(headerBytes, dataWithHeader, headerBytes.Length); Array.Copy(data, 0, dataWithHeader, headerBytes.Length, data.Length); // First we want to compress the data. Create a memory stream to write to, then wrap // a GZipStream around that. Write the data bytes to the compressed stream. Make // sure to close the streams before doing anything with the data itself. MemoryStream compressedStream = new MemoryStream(); GZipStream zipper = new GZipStream(compressedStream, CompressionMode.Compress); zipper.Write(dataWithHeader, 0, dataWithHeader.Length); zipper.Close(); compressedStream.Close(); // Now we need to get the compressed data back out and into a byte array we can feed // to the encryptor: byte[] compressedData = compressedStream.ToArray(); // Create a new Rijndael instance and set its key size to 256-bits, the highest // we can go. Also set our padding mode to PKCS #7, which will make it easier for // us to tell where the data ends and the padding begins when we decrypt this later. // Finally, create a crypto transform using that instance and feed it the hashed // password and derived IV. if (rijndael.ValidKeySize(256)) { rijndael.KeySize = 256; } rijndael.Padding = PaddingMode.PKCS7; ICryptoTransform encryptor = rijndael.CreateEncryptor(HashPassphrase(passphrase), iv); // Next, encrypt the data. We'll reuse the memory stream we had before and create a // crypto stream to wrap around it. Write the compressed data into the encryption // stream. Again, close the streams before reading the data; this is important here // so the padding gets done correctly. compressedStream = new MemoryStream(); CryptoStream cs = new CryptoStream(compressedStream, encryptor, CryptoStreamMode.Write); cs.Write(compressedData, 0, compressedData.Length); cs.FlushFinalBlock(); cs.Close(); compressedStream.Close(); // Get the newly encrypted, compressed data back into byte array form: byte[] encryptedData = compressedStream.ToArray(); // Now that we have the encrypted data, write it to the file and close up shop: output.Write(encryptedData, 0, encryptedData.Length); output.Flush(); output.Close(); } #region Catching Exceptions catch (UnauthorizedAccessException) { throw new SecureFileException("You do not have the necessary permissions to access " + "the file " + filename); } catch (System.Security.SecurityException) { throw new SecureFileException("You do not have the necessary permissions to access " + "the file " + filename); } catch (ArgumentException) { throw new SecureFileException("The specified file path was empty or contained " + "invalid characters"); } catch (IOException) { throw new SecureFileException("An I/O error occurred while trying to write to " + "the file " + filename); } // A generic catch-all, just in case: catch (Exception ex) { throw new SecureFileException(ex.Message); } #endregion }