/// <summary>
        /// Converts the value of the current <see cref="SecureSymmetricKey" /> to its equivalent binary representation.
        /// </summary>
        /// <returns>
        /// A binary representation of the current <see cref="SecureSymmetricKey" />.
        /// </returns>
        public SecureBuffer ToBuffer()
        {
            var resultBuffer = new SecureBuffer(SerializedLength);

            try
            {
                using (var controlToken = StateControl.Enter())
                {
                    using (var plaintextBuffer = new PinnedBuffer(SerializedPlaintextLength, true))
                    {
                        KeySource.Access(pinnedKeySourceBuffer =>
                        {
                            Array.Copy(pinnedKeySourceBuffer, 0, plaintextBuffer, KeySourceBufferIndex, KeySourceLengthInBytes);
                        });

                        plaintextBuffer[AlgorithmBufferIndex]      = (Byte)Algorithm;
                        plaintextBuffer[DerivationModeBufferIndex] = (Byte)DerivationMode;

                        using (var cipher = BufferEncryptionAlgorithm.ToCipher(RandomnessProvider))
                        {
                            using (var initializationVector = new PinnedBuffer(cipher.BlockSizeInBytes, true))
                            {
                                RandomnessProvider.GetBytes(initializationVector);

                                resultBuffer.Access(pinnedResultBuffer =>
                                {
                                    using (var ciphertext = cipher.Encrypt(plaintextBuffer, BufferEncryptionKey, initializationVector))
                                    {
                                        Array.Copy(ciphertext, 0, pinnedResultBuffer, 0, SerializedLength);
                                    }
                                });
                            }
                        }
                    }
                }

                return(resultBuffer);
            }
            catch
            {
                resultBuffer.Dispose();
                throw new SecurityException("Key serialization failed.");
            }
        }
        private Rfc2898DeriveBytes InitializePbkdf2Algorithm()
        {
            Rfc2898DeriveBytes result = null;

            KeySource.Access(buffer =>
            {
                var iterationSumBuffer = buffer.Take(Pbkdf2IterationSumLengthInBytes);
                var saltBuffer         = buffer.Skip(Pbkdf2IterationSumLengthInBytes).Take(Pbkdf2SaltLengthInBytes);
                var passwordBuffer     = buffer.Skip(Pbkdf2IterationSumLengthInBytes + Pbkdf2SaltLengthInBytes).Take(Pbkdf2PasswordLengthInBytes);
                var iterationCount     = Pbkdf2MinimumIterationCount;

                foreach (var iterationSumValue in iterationSumBuffer)
                {
                    iterationCount += iterationSumValue;
                }

                result = new Rfc2898DeriveBytes(passwordBuffer.ToArray(), saltBuffer.ToArray(), iterationCount);
            });

            return(result);
        }
        internal PinnedBuffer DeriveKey()
        {
            var result = (PinnedBuffer)null;

            try
            {
                using (var controlToken = StateControl.Enter())
                {
                    if (DerivationMode == SecureSymmetricKeyDerivationMode.Pbkdf2)
                    {
                        try
                        {
                            // Perform PBKDF2 key-derivation.
                            result = new PinnedBuffer(Pbkdf2Provider.GetBytes(DerivedKeyLength), true);
                        }
                        finally
                        {
                            Pbkdf2Provider.Reset();
                        }

                        return(result);
                    }

                    result = new PinnedBuffer(DerivedKeyLength, true);

                    using (var sourceWords = new PinnedStructureArray <UInt32>(KeySourceWordCount, true))
                    {
                        KeySource.Access((PinnedBuffer buffer) =>
                        {
                            // Convert the source buffer to an array of 32-bit words.
                            Buffer.BlockCopy(buffer, 0, sourceWords, 0, KeySourceLengthInBytes);
                        });

                        using (var transformedWords = new PinnedStructureArray <UInt32>(BlockWordCount, true))
                        {
                            // Copy out the first block. If nothing further is done, this satisfies truncation mode.
                            Array.Copy(sourceWords, transformedWords, BlockWordCount);

                            switch (DerivationMode)
                            {
                            case SecureSymmetricKeyDerivationMode.Truncation:

                                break;

                            case SecureSymmetricKeyDerivationMode.XorLayering:

                                for (var i = 1; i < BlockCount; i++)
                                {
                                    for (var j = 0; j < BlockWordCount; j++)
                                    {
                                        // Perform the XOR layering operation.
                                        transformedWords[j] = (transformedWords[j] ^ sourceWords[(i * BlockWordCount) + j]);
                                    }
                                }

                                break;

                            case SecureSymmetricKeyDerivationMode.XorLayeringWithSubstitution:

                                for (var i = 1; i < BlockCount; i++)
                                {
                                    for (var j = 0; j < BlockWordCount; j++)
                                    {
                                        // Perform the XOR layering operation with substitution.
                                        transformedWords[j] = (SubstituteWord(transformedWords[j]) ^ sourceWords[(i * BlockWordCount) + j]);
                                    }
                                }

                                break;

                            default:

                                throw new InvalidOperationException($"The specified key derivation mode, {DerivationMode}, is not supported.");
                            }

                            // Copy out the key bits.
                            Buffer.BlockCopy(transformedWords, 0, result, 0, DerivedKeyLength);
                        }
                    }

                    return(result);
                }
            }
            catch
            {
                result?.Dispose();
                throw new SecurityException("Key derivation failed.");
            }
        }