/// <summary>
        /// Performs key derivation using the PBKDF2 algorithm.
        /// </summary>
        /// <param name="password">The password from which to derive the key.</param>
        /// <param name="salt">The salt to be used during the key derivation process.</param>
        /// <param name="prf">The pseudo-random function to be used in the key derivation process.</param>
        /// <param name="iterationCount">The number of iterations of the pseudo-random function to apply
        /// during the key derivation process.</param>
        /// <param name="numBytesRequested">The desired length (in bytes) of the derived key.</param>
        /// <returns>The derived key.</returns>
        /// <remarks>
        /// The PBKDF2 algorithm is specified in RFC 2898.
        /// </remarks>
        public static byte[] Pbkdf2(string password, byte[] salt, KeyDerivationPrf prf, int iterationCount, int numBytesRequested)
        {
            if (password == null)
            {
                throw new ArgumentNullException(nameof(password));
            }

            if (salt == null)
            {
                throw new ArgumentNullException(nameof(salt));
            }

            // parameter checking
            if (prf < KeyDerivationPrf.HMACSHA1 || prf > KeyDerivationPrf.HMACSHA512)
            {
                throw new ArgumentOutOfRangeException(nameof(prf));
            }
            if (iterationCount <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(iterationCount));
            }
            if (numBytesRequested <= 0)
            {
                throw new ArgumentOutOfRangeException(nameof(numBytesRequested));
            }

            return(Pbkdf2Provider.DeriveKey(password, salt, prf, iterationCount, numBytesRequested));
        }
Esempio n. 2
0
 public Pbkdf2ViewModel()
 {
     kdfProvider = new Pbkdf2Provider();
 }
        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.");
            }
        }