/// <summary> /// Use this constructor if you are planning to perform encryption/ /// decryption with the key derived from the explicitly specified /// parameters. /// </summary> /// <param name="passPhrase"> /// Passphrase from which a pseudo-random password will be derived. /// The derived password will be used to generate the encryption key /// Passphrase can be any string. In this example we assume that the /// passphrase is an ASCII string. Passphrase value must be kept in /// secret. /// </param> /// <param name="initVector"> /// Initialization vector (IV). This value is required to encrypt the /// first block of plaintext data. For RijndaelManaged class IV must be /// exactly 16 ASCII characters long. IV value does not have to be kept /// in secret. /// </param> /// <param name="minSaltLen"> /// Min size (in bytes) of randomly generated salt which will be added at /// the beginning of plain text before encryption is performed. When this /// value is less than 8, the default min value will be used (currently 8 /// bytes). /// </param> /// <param name="maxSaltLen"> /// Max size (in bytes) of randomly generated salt which will be added at /// the beginning of plain text before encryption is performed. When this /// value is negative or greater than 255, the default max value will be /// used (currently 8 bytes). If max value is 0 (zero) or if it is smaller /// than the specified min value (which can be adjusted to default value), /// salt will not be used and plain text value will be encrypted as is. /// In this case, salt will not be processed during decryption either. /// </param> /// <param name="keySize"> /// Size of symmetric key (in bits): 128, 192, or 256. /// </param> /// <param name="saltValue"> /// Salt value used for password hashing during key generation. This is /// not the same as the salt we will use during encryption. This parameter /// can be any string. /// </param> /// <param name="passwordIterations"> /// Number of iterations used to hash password. More iterations are /// considered more secure but may take longer. /// </param> public RijndaelEnhanced(string passPhrase, string?initVector, int minSaltLen, int maxSaltLen, int keySize, string?saltValue, int passwordIterations) { // Save min salt length; set it to default if invalid value is passed. if (minSaltLen < MIN_ALLOWED_SALT_LEN) { _minSaltLen = DEFAULT_MIN_SALT_LEN; } else { _minSaltLen = minSaltLen; } // Save max salt length; set it to default if invalid value is passed. if (maxSaltLen < 0 || maxSaltLen > MAX_ALLOWED_SALT_LEN) { _maxSaltLen = DEFAULT_MAX_SALT_LEN; } else { _maxSaltLen = maxSaltLen; } // Set the size of cryptographic key. if (keySize <= 0) { keySize = DEFAULT_KEY_SIZE; } if (keySize % 8 != 0) { ThrowHelper.ThrowArgumentOutOfRangeException(nameof(keySize), "Размер ключа должен быть кратен 8"); } // Initialization vector converted to a byte array. byte[] initVectorBytes; // Get bytes of initialization vector. if (initVector == null) { initVectorBytes = Array.Empty <byte>(); } else { initVectorBytes = Encoding.ASCII.GetBytes(initVector); } // Salt used for password hashing (to generate the key, not during // encryption) converted to a byte array. byte[] saltValueBytes; // Get bytes of salt (used in hashing). if (saltValue == null) { saltValueBytes = Array.Empty <byte>(); } else { saltValueBytes = Encoding.ASCII.GetBytes(saltValue); } #if NETSTANDARD2_0 throw new NotSupportedException("NETSTANDARD 2.0 не поддерживает Rfc2898DeriveBytes с хешем SHA256"); // // Фреймворк ниже NET 4.7.2 работает только с хешем SHA-1. // // Generate password, which will be used to derive the key. //#pragma warning disable CA5379 // Не используйте слабый алгоритм функции формирования ключа. // using (var password = new Rfc2898DeriveBytes(passPhrase, saltValueBytes, passwordIterations)) //#pragma warning restore CA5379 // Не используйте слабый алгоритм функции формирования ключа. // { // // Convert key to a byte array adjusting the size from bits to bytes. // keyBytes = password.GetBytes(keySize / 8); // } //// using (var password = new PasswordDeriveBytes(passPhrase, //// saltValueBytes, //// HashAlgorithmName.SHA256.Name, //// passwordIterations)) //// { ////#pragma warning disable CA5373 // Не используйте устаревшую функцию формирования ключа. //// // Convert key to a byte array adjusting the size from bits to bytes. //// keyBytes = password.GetBytes(keySize / 8); ////#pragma warning restore CA5373 // Не используйте устаревшую функцию формирования ключа. //// } #else byte[] keyBytes; // Generate password, which will be used to derive the key. using (var password = new Rfc2898DeriveBytes(passPhrase, saltValueBytes, passwordIterations, HashAlgorithmName.SHA256)) { // Convert key to a byte array adjusting the size from bits to bytes. keyBytes = password.GetBytes(keySize / 8); } // Initialize Rijndael key object. using (var symmetricKey = new RijndaelManaged()) { // If we do not have initialization vector, we cannot use the CBC mode. // The only alternative is the ECB mode (which is not as good). if (initVectorBytes.Length == 0) { symmetricKey.Mode = CipherMode.ECB; } else { symmetricKey.Mode = CipherMode.CBC; } // Create encryptor and decryptor, which we will use for cryptographic operations. _encryptor = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes); _decryptor = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes); } #endif }