Thread overview
DAuth v0.6.1 - Salted Hashed Password Library
Aug 30, 2014
Nick Sabalausky
Aug 30, 2014
Nick Sabalausky
Aug 30, 2014
Casey
Aug 30, 2014
Nick Sabalausky
August 30, 2014
An update to DAuth is out:

https://github.com/Abscissa/DAuth

Main Changes:
- Add support for DMD 2.066 (Now supports v2.064.2 through v2.066.0)
- Supports crypt(3)-style hash strings for MS5, SHA-256 and SHA-512.
- Improved README
- Improved API Reference - now uses ddox.

Full ChangeLog:
https://github.com/Abscissa/DAuth/blob/master/CHANGELOG.md

Coming on the horizon: DAuth will be rebranded as "InstaUser Basic". It will be one pillar of a broader multiple-lib project called InstaUser, which will also include optional higher-level tools "InstaUser Store" and "InstaUser Web".
August 30, 2014
On 8/30/2014 6:29 AM, Nick Sabalausky wrote:
> An update to DAuth is out:
>
> https://github.com/Abscissa/DAuth
>
> Main Changes:
> - Add support for DMD 2.066 (Now supports v2.064.2 through v2.066.0)
> - Supports crypt(3)-style hash strings for MS5, SHA-256 and SHA-512.

Would you believe *MD5*, not MS5. Need sleep apparently... ;)

August 30, 2014
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.
August 30, 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".