/// <summary> /// Generates a symmetric encryption key of the given size and algorithm /// from a shared secret and optional cryptographic salt. /// </summary> /// <param name="algorithm">The algorithm name.</param> /// <param name="keySize">The desired key size in bits.</param> /// <param name="secret">The shared secret as a byta array.</param> /// <param name="salt">An optional array of at least 8 salt bytes or <c>null</c>.</param> /// <returns>The <see cref="SymmetricKey" />.</returns> /// <exception cref="ArgumentException">Thrown if <paramref name="salt" /> is not <c>null</c> and contains less than 8 bytes of salt.</exception> /// <remarks> /// <para> /// This method is useful for situations where two endpoints wish to communicate /// securely when they each know a shared secret such as a password or the hash /// of a password. /// </para> /// <note> /// Endpoints that wish to generate a key from a password string should use /// a text <see cref="Encoding"/> to convert the string into bytes. Note also /// that the endpoints will need to agree on the same salt bytes to make sure /// that the same key is generated on both ends. /// </note> /// <note> /// If <paramref name="salt" /> is passed as <c>null</c> then the class will use /// 8 bytes of built-in salt instead. /// </note> /// </remarks> public static SymmetricKey GenerateSymmetricKeyFromSecret(string algorithm, int keySize, byte[] secret, byte[] salt) { if (salt != null && salt.Length < 8) { throw new ArgumentException("At least eight bytes of cryptographic salt is required.", "salt"); } if (String.Compare(algorithm, CryptoAlgorithm.PlainText, StringComparison.OrdinalIgnoreCase) == 0) { return(new SymmetricKey(CryptoAlgorithm.PlainText, new byte[keySize], new byte[0])); } SymmetricAlgorithm symmetric = EncryptionConfig.CreateSymmetric(algorithm); Rfc2898DeriveBytes key; if (salt == null) { salt = new byte[] { 0x89, 0x55, 0x71, 0xEA, 0xD3, 0x16, 0x87, 0xFF } } ; key = new Rfc2898DeriveBytes(secret, salt, 3); try { symmetric.KeySize = keySize; return(new SymmetricKey(algorithm, key.GetBytes(symmetric.KeySize / 8), key.GetBytes(symmetric.BlockSize / 8))); } finally { symmetric.Clear(); } }
/// <summary> /// Generates a symmetric encryption key and initialization vector /// of a given size for the specified encryption algorithm. /// </summary> /// <param name="algorithm">The algorithm name.</param> /// <param name="keySize">The desired key size in bits.</param> /// <param name="key">Returns as the generated key.</param> /// <param name="IV">Returns as the generated initialization vector.</param> /// <remarks> /// The current supported cross platform encryption algorithms /// are: "DES", "RC2", "TripleDES", and "AES" (Rijndael). /// </remarks> public static void GenerateSymmetricKey(string algorithm, int keySize, out byte[] key, out byte[] IV) { if (String.Compare(algorithm, CryptoAlgorithm.PlainText, StringComparison.OrdinalIgnoreCase) == 0) { key = new byte[keySize]; IV = new byte[0]; return; } var symmetric = EncryptionConfig.CreateSymmetric(algorithm); try { symmetric.KeySize = keySize; symmetric.GenerateKey(); symmetric.GenerateIV(); key = symmetric.Key; IV = symmetric.IV; } finally { symmetric.Clear(); } }
/// <summary> /// Initializes the decryptor to use the specified encryption algorithm, /// key, and initialization vector. /// </summary> /// <param name="algorithm">The symmetric algorithm name.</param> /// <param name="key">The encryption key.</param> /// <param name="IV">The initialization vector.</param> public BlockDecryptor(string algorithm, byte[] key, byte[] IV) { this.algorithm = algorithm; this.key = key; this.IV = IV; this.provider = EncryptionConfig.CreateSymmetric(algorithm); this.provider.Key = key; this.provider.IV = IV; this.decryptor = null; }