text: /*
  * PBKDF
  * (C) 1999-2007,2012,2015 Jack Lloyd
  *
  * Botan is released under the Simplified BSD License (see license.txt)
  */
  
  #ifndef BOTAN_PBKDF_H__
  #define BOTAN_PBKDF_H__
  
  #include <botan/symkey.h>
  #include <botan/exceptn.h>
  #include <chrono>
  
  namespace Botan {
  
  /**
  * Base class for PBKDF (password based key derivation function)
  * implementations. Converts a password into a key using a salt
  * and iterated hashing to make brute force attacks harder.
  */
  class BOTAN_DLL PBKDF
     {
     public:
        /**
        * Create an instance based on a name
        * If provider is empty then best available is chosen.
        * @param algo_spec algorithm name
        * @param provider provider implementation to choose
        * @return a null pointer if the algo/provider combination cannot be found
        */
        static std::unique_ptr<PBKDF> create(const std::string& algo_spec,
                                             const std::string& provider = "");
  
        /**
        * @return list of available providers for this algorithm, empty if not available
        */
        static std::vector<std::string> providers(const std::string& algo_spec);
  
        /**
        * @return new instance of this same algorithm
        */
        virtual PBKDF* clone() const = 0;
  
        /**
        * @return name of this PBKDF
        */
        virtual std::string name() const = 0;
  
        virtual ~PBKDF() = default;
  
        /**
        * Derive a key from a passphrase for a number of iterations
        * specified by either iterations or if iterations == 0 then
        * running until msec time has elapsed.
        *
        * @param out buffer to store the derived key, must be of out_len bytes
        * @param out_len the desired length of the key to produce
        * @param passphrase the password to derive the key from
        * @param salt a randomly chosen salt
        * @param salt_len length of salt in bytes
        * @param iterations the number of iterations to use (use 10K or more)
        * @param msec if iterations is zero, then instead the PBKDF is
        *        run until msec milliseconds has passed.
        * @return the number of iterations performed
        */
        virtual size_t pbkdf(uint8_t out[], size_t out_len,
                             const std::string& passphrase,
                             const uint8_t salt[], size_t salt_len,
                             size_t iterations,
                             std::chrono::milliseconds msec) const = 0;
  
        /**
        * Derive a key from a passphrase for a number of iterations.
        *
        * @param out buffer to store the derived key, must be of out_len bytes
        * @param out_len the desired length of the key to produce
        * @param passphrase the password to derive the key from
        * @param salt a randomly chosen salt
        * @param salt_len length of salt in bytes
        * @param iterations the number of iterations to use (use 10K or more)
        */
        void pbkdf_iterations(uint8_t out[], size_t out_len,
                              const std::string& passphrase,
                              const uint8_t salt[], size_t salt_len,
                              size_t iterations) const;
  
        /**
        * Derive a key from a passphrase, running until msec time has elapsed.
        *
        * @param out buffer to store the derived key, must be of out_len bytes
        * @param out_len the desired length of the key to produce
        * @param passphrase the password to derive the key from
        * @param salt a randomly chosen salt
        * @param salt_len length of salt in bytes
        * @param msec if iterations is zero, then instead the PBKDF is
        *        run until msec milliseconds has passed.
        * @param iterations set to the number iterations executed
        */
        void pbkdf_timed(uint8_t out[], size_t out_len,
                           const std::string& passphrase,
                           const uint8_t salt[], size_t salt_len,
                           std::chrono::milliseconds msec,
                           size_t& iterations) const;
  
        /**
        * Derive a key from a passphrase for a number of iterations.
        *
        * @param out_len the desired length of the key to produce
        * @param passphrase the password to derive the key from
        * @param salt a randomly chosen salt
        * @param salt_len length of salt in bytes
        * @param iterations the number of iterations to use (use 10K or more)
        * @return the derived key
        */
        secure_vector<uint8_t> pbkdf_iterations(size_t out_len,
                                             const std::string& passphrase,
                                             const uint8_t salt[], size_t salt_len,
                                             size_t iterations) const;
  
        /**
        * Derive a key from a passphrase, running until msec time has elapsed.
        *
        * @param out_len the desired length of the key to produce
        * @param passphrase the password to derive the key from
        * @param salt a randomly chosen salt
        * @param salt_len length of salt in bytes
        * @param msec if iterations is zero, then instead the PBKDF is
        *        run until msec milliseconds has passed.
        * @param iterations set to the number iterations executed
        * @return the derived key
        */
        secure_vector<uint8_t> pbkdf_timed(size_t out_len,
                                        const std::string& passphrase,
                                        const uint8_t salt[], size_t salt_len,
                                        std::chrono::milliseconds msec,
                                        size_t& iterations) const;
  
        // Following kept for compat with 1.10:
  
        /**
        * Derive a key from a passphrase
        * @param out_len the desired length of the key to produce
        * @param passphrase the password to derive the key from
        * @param salt a randomly chosen salt
        * @param salt_len length of salt in bytes
        * @param iterations the number of iterations to use (use 10K or more)
        */
        OctetString derive_key(size_t out_len,
                               const std::string& passphrase,
                               const uint8_t salt[], size_t salt_len,
                               size_t iterations) const
           {
           return pbkdf_iterations(out_len, passphrase, salt, salt_len, iterations);
           }
  
        /**
        * Derive a key from a passphrase
        * @param out_len the desired length of the key to produce
        * @param passphrase the password to derive the key from
        * @param salt a randomly chosen salt
        * @param iterations the number of iterations to use (use 10K or more)
        */
        template<typename Alloc>
        OctetString derive_key(size_t out_len,
                               const std::string& passphrase,
                               const std::vector<uint8_t, Alloc>& salt,
                               size_t iterations) const
           {
           return pbkdf_iterations(out_len, passphrase, salt.data(), salt.size(), iterations);
           }
  
        /**
        * Derive a key from a passphrase
        * @param out_len the desired length of the key to produce
        * @param passphrase the password to derive the key from
        * @param salt a randomly chosen salt
        * @param salt_len length of salt in bytes
        * @param msec is how long to run the PBKDF
        * @param iterations is set to the number of iterations used
        */
        OctetString derive_key(size_t out_len,
                               const std::string& passphrase,
                               const uint8_t salt[], size_t salt_len,
                               std::chrono::milliseconds msec,
                               size_t& iterations) const
           {
           return pbkdf_timed(out_len, passphrase, salt, salt_len, msec, iterations);
           }
  
        /**
        * Derive a key from a passphrase using a certain amount of time
        * @param out_len the desired length of the key to produce
        * @param passphrase the password to derive the key from
        * @param salt a randomly chosen salt
        * @param msec is how long to run the PBKDF
        * @param iterations is set to the number of iterations used
        */
        template<typename Alloc>
        OctetString derive_key(size_t out_len,
                               const std::string& passphrase,
                               const std::vector<uint8_t, Alloc>& salt,
                               std::chrono::milliseconds msec,
                               size_t& iterations) const
           {
           return pbkdf_timed(out_len, passphrase, salt.data(), salt.size(), msec, iterations);
           }
     };
  
  /**
  * Password based key derivation function factory method
  * @param algo_spec the name of the desired PBKDF algorithm
  * @param provider the provider to use
  * @return pointer to newly allocated object of that type
  */
  inline PBKDF* get_pbkdf(const std::string& algo_spec,
                             const std::string& provider = "")
     {
     std::unique_ptr<PBKDF> p(PBKDF::create(algo_spec, provider));
     if(p)
        return p.release();
     throw Algorithm_Not_Found(algo_spec);
     }
  
  }
  
  #endif
  