private PinnedBuffer EncryptInCbcMode(PinnedBuffer plaintext, PinnedBuffer privateKey, PinnedBuffer initializationVector)
        {
            initializationVector.RejectIf().IsNull(nameof(initializationVector)).OrIf(argument => argument.Count() != BlockSizeInBytes, nameof(privateKey), "The length of the specified initialization vector is invalid for the algorithm.");

            using (var encryptionProvider = InitializeProvider())
            {
                encryptionProvider.BlockSize = BlockSizeInBits;
                encryptionProvider.KeySize   = KeySizeInBits;
                encryptionProvider.Mode      = Mode;
                encryptionProvider.Padding   = PaddingMode;
                encryptionProvider.Key       = privateKey;
                encryptionProvider.IV        = initializationVector;

                using (var encryptor = encryptionProvider.CreateEncryptor(privateKey, initializationVector))
                {
                    using (var memoryStream = new MemoryStream())
                    {
                        using (var cryptographicStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write))
                        {
                            cryptographicStream.Write(plaintext, 0, plaintext.Length);
                            cryptographicStream.FlushFinalBlock();
                            return(new PinnedBuffer(initializationVector.Concat(memoryStream.ToArray()).ToArray(), false));
                        }
                    }
                }
            }
        }
        internal PinnedBuffer Decrypt(PinnedBuffer ciphertext, PinnedBuffer privateKey)
        {
            ciphertext.RejectIf().IsNull(nameof(ciphertext)).OrIf(argument => argument.Count() < BlockSizeInBytes, nameof(ciphertext), "The length of the specified ciphertext is invalid for the algorithm.");
            privateKey.RejectIf().IsNull(nameof(privateKey)).OrIf(argument => argument.Count() != KeySizeInBytes, nameof(privateKey), "The length of the specified key is invalid for the algorithm.");

            switch (Mode)
            {
            case CipherMode.CBC:

                return(DecryptInCbcMode(ciphertext, privateKey));

            case CipherMode.ECB:

                return(DecryptInEcbMode(ciphertext, privateKey));

            default:

                throw new InvalidOperationException($"The specified cipher mode, {Mode}, is not supported.");
            }
        }
 /// <summary>
 /// Generates a new <see cref="SecureSymmetricKey" />.
 /// </summary>
 /// <param name="algorithm">
 /// The symmetric-key algorithm that the generated key is derived to interoperate with. The default value is
 /// <see cref="SymmetricAlgorithmSpecification.Aes256Cbc" />.
 /// </param>
 /// <param name="derivationMode">
 /// The mode used to derive the generated key. The default value is
 /// <see cref="SecureSymmetricKeyDerivationMode.XorLayeringWithSubstitution" />.
 /// </param>
 /// <param name="keySource">
 /// A buffer comprising 384 bytes (3,072 bits) from which the private key is derived.
 /// </param>
 /// <returns>
 /// A new <see cref="SecureSymmetricKey" />.
 /// </returns>
 /// <exception cref="ArgumentException">
 /// <paramref name="keySource" /> is not 384 bytes in length.
 /// </exception>
 /// <exception cref="ArgumentOutOfRangeException">
 /// <paramref name="algorithm" /> is equal to <see cref="SymmetricAlgorithmSpecification.Unspecified" /> -or-
 /// <paramref name="derivationMode" /> is equal to <see cref="SecureSymmetricKeyDerivationMode.Unspecified" />.
 /// </exception>
 public static SecureSymmetricKey New(SymmetricAlgorithmSpecification algorithm, SecureSymmetricKeyDerivationMode derivationMode, PinnedBuffer keySource)
 {
     keySource.RejectIf(argument => argument.Length != KeySourceLengthInBytes, nameof(keySource), $"The key source is not {KeySourceLengthInBytes} bytes in length.");
     return(new SecureSymmetricKey(algorithm, derivationMode, keySource));
 }