aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorlloyd <[email protected]>2010-02-02 10:48:48 +0000
committerlloyd <[email protected]>2010-02-02 10:48:48 +0000
commitcf3e984dbffc0fb2a695306a9b4d53257bb74ea8 (patch)
treefbe0e6326c0bf33e3540f9b7b1905aba1e5cf755
parent121ca16daa158315682373213e150d9c18c28cdb (diff)
Prefix passhash with "$9$" in a manner similar with other
password hashing schemes. Increase salt size to 80 bits. Research shows that virtually no other PBKDF2 implementations support anything but SHA-1; for ease of implementation elsehwere switch back from SHA-512 to SHA-1. Should be mostly harmless; it limits total entropy of the password to a maximum of 160 bits, but this is unlikely anyway. Use two bytes to specify the work factor for future-proofing. Add a test.
-rw-r--r--checks/validate.cpp32
-rw-r--r--doc/examples/passhash.cpp4
-rw-r--r--src/constructs/passhash/info.txt3
-rw-r--r--src/constructs/passhash/passhash.cpp42
-rw-r--r--src/constructs/passhash/passhash.h2
5 files changed, 64 insertions, 19 deletions
diff --git a/checks/validate.cpp b/checks/validate.cpp
index 9500589ca..bbb710b91 100644
--- a/checks/validate.cpp
+++ b/checks/validate.cpp
@@ -18,6 +18,11 @@
#include <botan/exceptn.h>
#include <botan/selftest.h>
#include <botan/libstate.h>
+
+#if defined(BOTAN_HAS_PASSHASH)
+ #include <botan/passhash.h>
+#endif
+
using namespace Botan;
#include "validate.h"
@@ -61,6 +66,26 @@ std::vector<std::string> parse(const std::string&);
void strip(std::string&);
Botan::SecureVector<byte> decode_hex(const std::string&);
+bool test_passhash(RandomNumberGenerator& rng)
+ {
+#if defined(BOTAN_HAS_PASSHASH)
+
+ const std::string input = "secret";
+ const std::string fixed_hash = "$9$AArBRAG0kcKp3XPDUgd32ONhutn9HMQKix7H";
+
+ if(!password_hash_ok(input, fixed_hash))
+ return false;
+
+ std::string gen_hash = password_hash(input, rng, 5);
+
+ if(!password_hash_ok(input, gen_hash))
+ return false;
+
+#endif
+
+ return true;
+ }
+
u32bit do_validation_tests(const std::string& filename,
RandomNumberGenerator& rng,
bool should_pass)
@@ -179,6 +204,13 @@ u32bit do_validation_tests(const std::string& filename,
}
}
+
+ if(should_pass && !test_passhash(rng))
+ {
+ std::cout << "Passhash tests failed" << std::endl;
+ errors++;
+ }
+
if(should_pass)
std::cout << std::endl;
return errors;
diff --git a/doc/examples/passhash.cpp b/doc/examples/passhash.cpp
index 0949e944c..1e4c8c505 100644
--- a/doc/examples/passhash.cpp
+++ b/doc/examples/passhash.cpp
@@ -29,10 +29,8 @@ int main(int argc, char* argv[])
{
Botan::AutoSeeded_RNG rng;
- Botan::u32bit work_factor = 10;
-
std::cout << "H('" << argv[1] << "') = "
- << Botan::password_hash(argv[1], rng, work_factor) << '\n';
+ << Botan::password_hash(argv[1], rng) << '\n';
}
else
{
diff --git a/src/constructs/passhash/info.txt b/src/constructs/passhash/info.txt
index b2f54ef0a..fdc68deac 100644
--- a/src/constructs/passhash/info.txt
+++ b/src/constructs/passhash/info.txt
@@ -1,9 +1,8 @@
define PASSHASH
<requires>
+libstate
pbkdf2
-sha2
-hmac
rng
base64
</requires>
diff --git a/src/constructs/passhash/passhash.cpp b/src/constructs/passhash/passhash.cpp
index dade15ddb..d3571808d 100644
--- a/src/constructs/passhash/passhash.cpp
+++ b/src/constructs/passhash/passhash.cpp
@@ -6,9 +6,9 @@
*/
#include <botan/passhash.h>
+#include <botan/loadstor.h>
+#include <botan/libstate.h>
#include <botan/pbkdf2.h>
-#include <botan/hmac.h>
-#include <botan/sha2_64.h>
#include <botan/base64.h>
#include <botan/pipe.h>
@@ -16,17 +16,21 @@ namespace Botan {
namespace {
-const u32bit SALT_BYTES = 8; // 64 bits of salt
+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,
- byte work_factor)
+ u16bit work_factor)
{
- PKCS5_PBKDF2 kdf(new HMAC(new SHA_512));
+ PKCS5_PBKDF2 kdf(
+ global_state().algorithm_factory().make_mac(PBKDF_MAC)
+ );
SecureVector<byte> salt(SALT_BYTES);
rng.randomize(&salt[0], salt.size());
@@ -40,40 +44,52 @@ std::string password_hash(const std::string& pass,
Pipe pipe(new Base64_Encoder);
pipe.start_msg();
- pipe.write(work_factor);
+ 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 pipe.read_all_as_string();
+ 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);
+ pipe.write(hash.c_str() + MAGIC_PREFIX.size());
pipe.end_msg();
SecureVector<byte> bin = pipe.read_all();
- if(bin.size() != (1 + PBKDF_OUTPUT_LEN + SALT_BYTES))
+ const u32bit WORKFACTOR_BYTES = 2;
+
+ if(bin.size() != (WORKFACTOR_BYTES + PBKDF_OUTPUT_LEN + SALT_BYTES))
return false;
- u32bit kdf_iterations = WORK_FACTOR_SCALE * bin[0];
+ u32bit kdf_iterations = WORK_FACTOR_SCALE * load_be<u16bit>(bin, 0);
if(kdf_iterations == 0)
return false;
- PKCS5_PBKDF2 kdf(new HMAC(new SHA_512));
+ PKCS5_PBKDF2 kdf(
+ global_state().algorithm_factory().make_mac(PBKDF_MAC)
+ );
SecureVector<byte> cmp = kdf.derive_key(
PBKDF_OUTPUT_LEN, pass,
- &bin[1], SALT_BYTES,
+ &bin[WORKFACTOR_BYTES], SALT_BYTES,
kdf_iterations).bits_of();
return same_mem(cmp.begin(),
- bin.begin() + 1 + SALT_BYTES,
+ bin.begin() + WORKFACTOR_BYTES + SALT_BYTES,
PBKDF_OUTPUT_LEN);
}
diff --git a/src/constructs/passhash/passhash.h b/src/constructs/passhash/passhash.h
index e3b0419fe..9676ff85e 100644
--- a/src/constructs/passhash/passhash.h
+++ b/src/constructs/passhash/passhash.h
@@ -20,7 +20,7 @@ namespace Botan {
*/
std::string BOTAN_DLL password_hash(const std::string& password,
RandomNumberGenerator& rng,
- byte work_factor = 10);
+ u16bit work_factor = 10);
/**
* Check a previously created password hash