DAuth v0.6.1 - Salted Hashed Password Library

Nick Sabalausky via Digitalmars-d-announce digitalmars-d-announce at puremagic.com
Sat Aug 30 14:11:13 PDT 2014


On 8/30/2014 10:19 AM, Casey wrote:
> Would it be possible to support bcrypt style password hashing? The one
> key feature of it is that it encrypts/hashes the password many times to
> slow down brute force attacks.  Hash algorithms are too fast to prevent
> this.

DAuth is designed for everything to be overridable. So, while specific 
support for that is not currently built-in (I definitely want to add it 
though), you should still be able to use it.

The best way to do it:

All you need is a Phobos-compatible std.digest.digest[1]-style interface 
for bcrypt. You can wrap an existing bcrypt algorithm like this:

[1] http://dlang.org/phobos/std_digest_digest.html

------------------------------
import your_ordinary_bcrypt_module;
import std.digest.digest : WrapperDigest;

// Phobos's "template"-style
struct BCrypt
{
     // Implement Phobos digest interface:
     void start();
     void put(scope const(ubyte)[] data...);
     ubyte[SIZE_OF_YOUR_FINAL_HASH] finish();
}

// Phobos's OO-style
alias BCryptDigest = WrapperDigest!BCrypt;
------------------------------

The easiest way (although maybe not most flexible) to handle BCrypt's 
"number of rounds" parameter would be to make it a compile-time argument 
for your struct, and then make a few convenience aliases:

------------------------------
struct BCrypt(int numRounds) {...}
alias BCrypt256 = BCrypt!256;
alias BCrypt1024 = BCrypt!1024; // Or whatever
------------------------------

Now you have a BCrypt that's fully compatible with Phobos's digest 
system. If you don't care about DAuth's hash string format, then that's 
all you need: Just pass the in digest to any function which takes it:

------------------------------
// Generate password hash
Hash!Bcrypt256 hash = makeHash!Bcrypt256(pass);
ubyte[] mySalt = hash.salt;
ubyte[SIZE_OF_YOUR_FINAL_HASH] myHash = hash.hash;
saveItAllToYourDB(mySalt, myHash);

// Test password against a hash
Hash!Bcrypt256 someHash;
someHash.salt = mySalt;
someHash.hash = myHash;
bool accessGranted = isSameHash!Bcrypt256(pass, someHash);
------------------------------

To fully integrate it with DAuth and be able to use DAuth's hash 
strings, you can pass Hash.toString() and parseHash() with custom 
callbacks for 'digestCodeOfObj' and 'digestFromDAuthCode'. Examples of 
this are provided in the API reference:

http://semitwist.com/dauth/dauth/core/Hash.toString.html
http://semitwist.com/dauth/dauth/core/parseHash.html

If you don't want to create a Phobos-style digest wrapper for bcrypt, 
you don't have to. You can just bypass makeHash/isSameHash entirely:

------------------------------
import dauth;
import std.digest.digest;
import your_bcrypt_lib;

auto makeBCryptHash(Password pass, int rounds)
{
     // Digest is std.digest.digest.Digest, an OO interface
     Digest dummyDigest;

     Hash!Digest hash;
     hash.salt = randomSalt();
     hash.hash = do_the_bcrypt(h.salt ~ pass.data, rounds);

     return hash;
}

bool isSameBCryptHash(Password pass, int rounds, Hash!Digest hash)
{
     ubyte[] testHash = do_the_bcrypt(hash.salt ~ pass.data, rounds);
     return lengthConstantEquals(testHash, hash.hash);
}

// Don't use Hash.toString() or parseHash() since you opted
// not to create a Phobos-style digest. Instead, just
// save/load hash.salt and hash.hash manually.
------------------------------

I really should add a tutorial page to the official docs showing all 
this "how to add support for another hashing algorithm".



More information about the Digitalmars-d-announce mailing list