I am hashing passwords in MariaDB using:
ENCRYPT('password', CONCAT('$6$', SUBSTRING(SHA(RAND()), -16))
Which produces something like:
$6$3b502db443d64283$BNSYWsf3T0e4xT23GJW/QPpKvzLidio5zk9v7kCE.wk4dtNo4avMzBxvqoWc0Y5ihj/zVwtGCwZRfTFur0BnI1
The format here is $6
meaning SHA512, then the $salt$
and then the computed password hash. So the computed hash alone is
BNSYWsf3T0e4xT23GJW/QPpKvzLidio5zk9v7kCE.wk4dtNo4avMzBxvqoWc0Y5ihj/zVwtGCwZRfTFur0BnI1
As I understand it this uses crypt(3) in the background. If I write a short bit of C such as:
#define _GNU_SOURCE
#include <crypt.h>
#include <stdio.h>
int main() {
char * blah = crypt("password", "$6$3b502db443d64283");
puts(blah);
}
Taking care to put in the same random salt as the RAND()
function generated for MySQL and prepending the $6
to use SHA512, then I do indeed get the same result:
$6$3b502db443d64283$BNSYWsf3T0e4xT23GJW/QPpKvzLidio5zk9v7kCE.wk4dtNo4avMzBxvqoWc0Y5ihj/zVwtGCwZRfTFur0BnI1
Again the computed hash itself is:
BNSYWsf3T0e4xT23GJW/QPpKvzLidio5zk9v7kCE.wk4dtNo4avMzBxvqoWc0Y5ihj/zVwtGCwZRfTFur0BnI1
Now if I use CryptoJS and wanted to compare that Hash in JS code rather than in the DB (or in - heaven forfend! - C), then I find that I have a problem. For example here is my CryptoJS code:
var CryptoJS = require('crypto-js');
var SHA512 = require('crypto-js/sha512');
console.log(SHA512("3b502db443d64283password")).toString();
I prepend the salt to the password as this function takes only a single argument. The result is:
105865ba5bf0649410927131204a1228260e59e95b1b53942001b98835dca4aedfe7039a00060fdba8531c44c83cd3b7bec4864865915938d2ed7ed477254f61
Ok. So I recognise that that is a Hex encoding of the Hashed password. So I'll change the encoding...but to what? I'll try Base64:
`console.log(SHA512("3b502db443d64283password")).toString(CryptoJS.enc.Base64);`
The output is:
EFhlulvwZJQQknExIEoSKCYOWelbG1OUIAG5iDXcpK7f5wOaAAYP26hTHETIPNO3vsSGSGWRWTjS7X7UdyVPYQ==
I'm starting to see a problem here. The encoding used by crypt(3) isn't base64. What is it? I look in the man page:
The characters in "salt" and "encrypted" are drawn from the set [a-zA-Z0-9./].
So I'm left with these questions:
What is the encoding used by crypt(3)? Is it a standard or just a chosen character set.
Is there any way to compare hashes generated with two different character sets like this? I mean is there an underlying representation they share of the hashed password? Can I access it?
How do I know how many rounds each function is making? Is there any way to know without examining the source code?
Is my assumption that I prepend the salt correct when using CryptoJS?