示例#1
0
        /// <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
        }