Up ../

(Ancient History Now) SuSE Password hashes start with "$2a$"

Noticing that SuSE 10.x had a different password hash from RHEL4 (md5)

I was curious.

Its apparently based on the blowfish cipher and originally used in OpenBSD.

The hash starts with $2a$ followed by log2 of the number of rounds and then 22 bytes of salt and 31 bytes of hash.

eg

	
$2a$10$yHYYjnT5gvqrFQ5JHCiEMuhAXOj35458FGzykEaQ48.OL9sHMOyyi
^--^--^-------salt----------^^----------hashed password----^

How do you calculate these hashes?

Normally you wouldn't need to - pam takes care of the details.

But still... how do you?

The manual pages on the SuSE box weren't very forthcoming.

After a bit of spelunking I determined the the crypt_rn() and crypt_gensalt_rn() are used.
(See http://www.openwall.com/crypt/)

Basically

crypt_gensalt_rn (CIPHER, NROUNDS, ENTROPY)  --> SALT
crypt_rn (CLEARTEXT_PASSWORD, SALT) --> HASH

where SALT includes the prefix '$2a$' and NROUNDS (which is actually log2 of the number of rounds.)

eg

$2a$10$yHYYjnT5gvqrFQ5JHCiEMu

CYPHER just select the cipher

eg

"$1$" -> md5, "" -> des, "$2a$" -> bf

What it looks like


const   char    CX_BLOWFISH[]   = "$2a$";
enum    {	// These are sprinkled throughout the source code as 7,22 & 31
        BF_ENTROPY_BITS         = 128,
        BF_ENTROPY_BYTES        = (BF_ENTROPY_BITS>>3),
        BF_PREFIX_LEN           = 7,
        BF_SALT_LEN             = 22,
        BF_SETTING_LEN          = (BF_PREFIX_LEN+BF_SALT_LEN),
        BF_HASH_LEN             = 31,
        BF_TOTAL_LEN            = (BF_SETTING_LEN+BF_HASH_LEN),
        BF_ROUNDS               = 10,   // log2 Nrounds
        
};

char    entropy [BF_ENTROPY_BYTES];
char    settings [BF_SETTING_LEN+1];		// +1 for terminating '\0'
char    hashed_password [BF_TOTAL_LEN+1];
char    clear_text [BUFSIZ];

getentropy (entropy, sizeof(entropy));	// Usually just read BF_ENTROPY_BYTES from /dev/random

crypt_gensalt_rn (CX_BLOWFISH, BF_ROUNDS,    // "$2a", 10
		entropy, BF_ENTROPY_BYTES,	     // [], 16
		settings, BF_SETTING_LEN+1); // -> "$2a$10$HYYjnT5gvqrFQ5JHCiEMu 

memset (hashed_password, 0, sizeof(hashed_password));	// needs to be cleared

crypt_rn (clear_text,	 // "XXXX"
	settings,	 // "2a$10$HYYjnT5gvqrFQ5JHCiEMu"
	hashed_password, // -> $2a$10$yHYYjnT5gvqrFQ5JHCiEMuhAXOj35458FGzykEaQ48.OL9sHMOyyi
	BF_TOTAL_LEN+1);

A short program to generate these password hashes: tar archive or source under genbfpw files/

You will need the crypt_blowfish-1.0.2 library from Openwall if you don't have crypt_gensalt_rn(3) & crypt_rn(3) on your system.

LICENSE
Creative Commons CC0 http://creativecommons.org/publicdomain/zero/1.0/legalcode

AUTHOR
James Sainsbury