From 3c8bfb624e321e5a56938fc27f9312cfd3d23d97 Mon Sep 17 00:00:00 2001 From: lloyd Date: Fri, 5 Feb 2010 20:41:13 +0000 Subject: Further passhash changes before release and things have to be finalized. Move header to passhash9.h and rename the functions to be passhash9 specific ({generator,check}_passhash9) Add an algorithm identifer field. Currently only id 0 is defined, for HMAC(SHA-1), but this opens up for using HMAC(SHA-512) or HMAC(SHA-3) or CMAC(Blowfish) or whatever in the future if necessary. Increase the salt size to 96 bits and the PRF output size to 192 bits. Document in api.tex --- src/constructs/passhash/info.txt | 2 +- src/constructs/passhash/passhash.cpp | 96 ------------------------- src/constructs/passhash/passhash.h | 35 ---------- src/constructs/passhash/passhash9.cpp | 127 ++++++++++++++++++++++++++++++++++ src/constructs/passhash/passhash9.h | 35 ++++++++++ 5 files changed, 163 insertions(+), 132 deletions(-) delete mode 100644 src/constructs/passhash/passhash.cpp delete mode 100644 src/constructs/passhash/passhash.h create mode 100644 src/constructs/passhash/passhash9.cpp create mode 100644 src/constructs/passhash/passhash9.h (limited to 'src/constructs') diff --git a/src/constructs/passhash/info.txt b/src/constructs/passhash/info.txt index fdc68deac..f96809f29 100644 --- a/src/constructs/passhash/info.txt +++ b/src/constructs/passhash/info.txt @@ -1,4 +1,4 @@ -define PASSHASH +define PASSHASH9 libstate diff --git a/src/constructs/passhash/passhash.cpp b/src/constructs/passhash/passhash.cpp deleted file mode 100644 index d3571808d..000000000 --- a/src/constructs/passhash/passhash.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* -* Password Hashing -* (C) 2010 Jack Lloyd -* -* Distributed under the terms of the Botan license -*/ - -#include -#include -#include -#include -#include -#include - -namespace Botan { - -namespace { - -const std::string MAGIC_PREFIX = "$9$"; -const u32bit SALT_BYTES = 10; // 80 bits of salt -const u32bit PBKDF_OUTPUT_LEN = 15; // 112 bits output -const u32bit WORK_FACTOR_SCALE = 10000; -const std::string PBKDF_MAC = "HMAC(SHA-1)"; - -} - -std::string password_hash(const std::string& pass, - RandomNumberGenerator& rng, - u16bit work_factor) - { - PKCS5_PBKDF2 kdf( - global_state().algorithm_factory().make_mac(PBKDF_MAC) - ); - - SecureVector salt(SALT_BYTES); - rng.randomize(&salt[0], salt.size()); - - u32bit kdf_iterations = WORK_FACTOR_SCALE * work_factor; - - SecureVector pbkdf2_output = - kdf.derive_key(PBKDF_OUTPUT_LEN, pass, - &salt[0], salt.size(), - kdf_iterations).bits_of(); - - Pipe pipe(new Base64_Encoder); - pipe.start_msg(); - pipe.write(get_byte(0, work_factor)); - pipe.write(get_byte(1, work_factor)); - pipe.write(salt); - pipe.write(pbkdf2_output); - pipe.end_msg(); - - return MAGIC_PREFIX + pipe.read_all_as_string(); - } - -bool password_hash_ok(const std::string& pass, const std::string& hash) - { - if(hash.size() != (36 + MAGIC_PREFIX.size())) - return false; - - for(size_t i = 0; i != MAGIC_PREFIX.size(); ++i) - if(hash[i] != MAGIC_PREFIX[i]) - return false; - - Pipe pipe(new Base64_Decoder); - pipe.start_msg(); - pipe.write(hash.c_str() + MAGIC_PREFIX.size()); - pipe.end_msg(); - - SecureVector bin = pipe.read_all(); - - const u32bit WORKFACTOR_BYTES = 2; - - if(bin.size() != (WORKFACTOR_BYTES + PBKDF_OUTPUT_LEN + SALT_BYTES)) - return false; - - u32bit kdf_iterations = WORK_FACTOR_SCALE * load_be(bin, 0); - - if(kdf_iterations == 0) - return false; - - PKCS5_PBKDF2 kdf( - global_state().algorithm_factory().make_mac(PBKDF_MAC) - ); - - SecureVector cmp = kdf.derive_key( - PBKDF_OUTPUT_LEN, pass, - &bin[WORKFACTOR_BYTES], SALT_BYTES, - kdf_iterations).bits_of(); - - return same_mem(cmp.begin(), - bin.begin() + WORKFACTOR_BYTES + SALT_BYTES, - PBKDF_OUTPUT_LEN); - } - -} diff --git a/src/constructs/passhash/passhash.h b/src/constructs/passhash/passhash.h deleted file mode 100644 index 9676ff85e..000000000 --- a/src/constructs/passhash/passhash.h +++ /dev/null @@ -1,35 +0,0 @@ -/* -* Password Hashing -* (C) 2010 Jack Lloyd -* -* Distributed under the terms of the Botan license -*/ - -#ifndef BOTAN_PASSHASH_H__ -#define BOTAN_PASSHASH_H__ - -#include - -namespace Botan { - -/** -* Create a password hash using PBKDF2 -* @param password the password -* @param rng a random number generator -* @Param work_factor how much work to do to slow down guessing attacks -*/ -std::string BOTAN_DLL password_hash(const std::string& password, - RandomNumberGenerator& rng, - u16bit work_factor = 10); - -/** -* Check a previously created password hash -* @param password the password to check against -* @param hash the stored hash to check against -*/ -bool BOTAN_DLL password_hash_ok(const std::string& password, - const std::string& hash); - -} - -#endif diff --git a/src/constructs/passhash/passhash9.cpp b/src/constructs/passhash/passhash9.cpp new file mode 100644 index 000000000..9e5ff3257 --- /dev/null +++ b/src/constructs/passhash/passhash9.cpp @@ -0,0 +1,127 @@ +/* +* Passhash9 Password Hashing +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include +#include +#include +#include +#include +#include + +namespace Botan { + +namespace { + +const std::string MAGIC_PREFIX = "$9$"; + +const u32bit WORKFACTOR_BYTES = 2; +const u32bit ALGID_BYTES = 1; +const u32bit SALT_BYTES = 12; // 96 bits of salt +const u32bit PBKDF_OUTPUT_LEN = 24; // 192 bits output + +const u32bit WORK_FACTOR_SCALE = 10000; + +MessageAuthenticationCode* get_pbkdf_prf(byte alg_id) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + + if(alg_id == 0) + return af.make_mac("HMAC(SHA-1)"); + + return 0; + } + +std::pair choose_pbkdf_prf() + { + byte alg_id = 0; + return std::make_pair(alg_id, get_pbkdf_prf(alg_id)); + } + +} + +std::string generate_passhash9(const std::string& pass, + RandomNumberGenerator& rng, + u16bit work_factor) + { + std::pair prf = choose_pbkdf_prf(); + byte alg_id = prf.first; + + PKCS5_PBKDF2 kdf(prf.second); // takes ownership of pointer + + SecureVector salt(SALT_BYTES); + rng.randomize(&salt[0], salt.size()); + + u32bit kdf_iterations = WORK_FACTOR_SCALE * work_factor; + + SecureVector pbkdf2_output = + kdf.derive_key(PBKDF_OUTPUT_LEN, pass, + &salt[0], salt.size(), + kdf_iterations).bits_of(); + + Pipe pipe(new Base64_Encoder); + pipe.start_msg(); + pipe.write(alg_id); + pipe.write(get_byte(0, work_factor)); + pipe.write(get_byte(1, work_factor)); + pipe.write(salt); + pipe.write(pbkdf2_output); + pipe.end_msg(); + + return MAGIC_PREFIX + pipe.read_all_as_string(); + } + +bool check_passhash9(const std::string& pass, const std::string& hash) + { + const u32bit BINARY_LENGTH = + (ALGID_BYTES + WORKFACTOR_BYTES + PBKDF_OUTPUT_LEN + SALT_BYTES); + + const u32bit BASE64_LENGTH = + MAGIC_PREFIX.size() + (BINARY_LENGTH * 8) / 6; + + if(hash.size() != BASE64_LENGTH) + return false; + + for(size_t i = 0; i != MAGIC_PREFIX.size(); ++i) + if(hash[i] != MAGIC_PREFIX[i]) + return false; + + Pipe pipe(new Base64_Decoder); + pipe.start_msg(); + pipe.write(hash.c_str() + MAGIC_PREFIX.size()); + pipe.end_msg(); + + SecureVector bin = pipe.read_all(); + + if(bin.size() != BINARY_LENGTH) + return false; + + byte alg_id = bin[0]; + + u32bit kdf_iterations = + WORK_FACTOR_SCALE * load_be(bin + ALGID_BYTES, 0); + + if(kdf_iterations == 0) + return false; + + MessageAuthenticationCode* pbkdf_prf = get_pbkdf_prf(alg_id); + + if(pbkdf_prf == 0) + return false; // unknown algorithm, reject + + PKCS5_PBKDF2 kdf(pbkdf_prf); // takes ownership of pointer + + SecureVector cmp = kdf.derive_key( + PBKDF_OUTPUT_LEN, pass, + &bin[ALGID_BYTES + WORKFACTOR_BYTES], SALT_BYTES, + kdf_iterations).bits_of(); + + return same_mem(cmp.begin(), + bin.begin() + ALGID_BYTES + WORKFACTOR_BYTES + SALT_BYTES, + PBKDF_OUTPUT_LEN); + } + +} diff --git a/src/constructs/passhash/passhash9.h b/src/constructs/passhash/passhash9.h new file mode 100644 index 000000000..6020dce42 --- /dev/null +++ b/src/constructs/passhash/passhash9.h @@ -0,0 +1,35 @@ +/* +* Passhash9 Password Hashing +* (C) 2010 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_PASSHASH9_H__ +#define BOTAN_PASSHASH9_H__ + +#include + +namespace Botan { + +/** +* Create a password hash using PBKDF2 +* @param password the password +* @param rng a random number generator +* @Param work_factor how much work to do to slow down guessing attacks +*/ +std::string BOTAN_DLL generate_passhash9(const std::string& password, + RandomNumberGenerator& rng, + u16bit work_factor = 10); + +/** +* Check a previously created password hash +* @param password the password to check against +* @param hash the stored hash to check against +*/ +bool BOTAN_DLL check_passhash9(const std::string& password, + const std::string& hash); + +} + +#endif -- cgit v1.2.3