PHP Developers Network

A community of PHP developers offering assistance, advice, discussion, and friendship.
 
Loading
It is currently Sat Jun 15, 2019 10:43 pm

All times are UTC - 5 hours




Post new topic Reply to topic  [ 4 posts ] 
Author Message
PostPosted: Mon Feb 24, 2014 1:14 pm 
Offline
Forum Regular
User avatar

Joined: Tue Sep 28, 2010 11:41 am
Posts: 984
Location: Columbus, Ohio
So I was revisiting old code written several years ago for hashing passwords, converting the site over to use password_hash instead.

Basically it used a sitewide salt and a row specific pepper, then did a SHA256 on it, and of course, the result is the hex hash. When I appended the random pepper to it, well if someone were to look at the list of passwords, it was quite clear.. I like to make it not as easy to "see". I know it practically not such a big deal, as usually, if they found a way to get the database, they most likely got a way to put something like a hack shell on the site to see the raw php code too...

So anyhow, I went to convert it over from hex "digits" over to every typeable character (without using the ALT+### method), chr(33)-chr(126). So what I did back then was just split the hash into 4 "digit" chunks, use hexdec() to get that back to an actual number, then covert that back over to a 3 digit base94 number, and string them all together. Below is there code off the top of my head, but the main gist of it. You end up with a SHA256 hashed password + pepper stored in a char(60) field, instead of a char(76).

Anyhow, it had me wondering, I'm sure there has to be a more efficient way to convert between the two bases, and know there are some people here who are way more advanced than me, and figured I'd ask to satisfy the geekness in me. I was thinking of applying something similar to the result of password_hash(), what can I say, it drive me nuts seeing a "unique" field with repeating patterns... (I need to get over it LOL). Anyhow, when comparing going from what be Base 65 ( $ . / a-z A-Z 0-9) over to a Base94, it didn't work enough to save bytes in storage, so without knowing how to convert without "chunking" it, just went with raw password_hash() results.

Thanks.

Syntax: [ Download ] [ Hide ]
function pass_hash($strPassword,$strPepper=NULL) {     
        if (is_null($strPepper) || $strPepper=='') {
                $strPepper = '';
                for($t=0;$t<12;$t++) { $strPepper .= chr(mt_rand(33,126)); }
        } else {
                while (strlen($strPepper)<12) { $strPepper .= $strPepper; }
                $strPepper = substr($strPepper,0,12);
        }
        $strMash =  SITE_SALT.$strPassword.$strPepper;
        $strHash64 = hash('sha256',$strMash);
        $strHash94 = '';
        foreach(str_split($strHash64,4) as $c) {
                $n = hexdec($c);
                $a = floor($n / 8836);
                $n -= 8836 * $a;
                $b = floor($n / 94);
                $c = $n - 94 * $b;
                $strHash94 .= chr(33+$a) . chr(33+$b) . chr(33+$c);
        }
        return $strPepper . $strHash94;
}

function pass_check($strPassword,$strHash) {
        $strPepper = substr($strHash,0,12);
        $strReHash = pass_hash($strPassword,$strPepper);
        return ($strHash==$strRehash);
}

 


Top
 Profile  
 
PostPosted: Mon Feb 24, 2014 1:59 pm 
Offline
Spammer :|
User avatar

Joined: Wed Oct 15, 2008 2:35 am
Posts: 6617
Location: WA, USA
There's no real benefit to trying to obscure the password hash - all you've done is add more processing time in order to compress the hash into a smaller string. A key tenant of cryptography is that knowledge of the algorithm used should not compromise anything, and once (not if) someone discovers your obfuscation method all of its benefit is immediately lost.
Salts are not about making it harder to crack a password but about making it harder to crack many passwords at once.

I don't get what you're saying about what was so clear when you appended the pepper: as long as you turn it into a hexadecimal string to match the hash output (eg, with bin2hex) then it all looks the same.

Additionally, no thread like this should go without a mention of how one should be using password_hash() or bcrypt instead of trying to roll their own.


Top
 Profile  
 
PostPosted: Mon Feb 24, 2014 3:05 pm 
Offline
Forum Regular
User avatar

Joined: Tue Sep 28, 2010 11:41 am
Posts: 984
Location: Columbus, Ohio
Quote:
There's no real benefit to trying to obscure the password hash


Yup, as I mentioned it is pretty pointless, was mainly my own wanting to not be able to viusally see a difference, plus require less storage space.

Quote:
Salts are not about making it harder to crack a password but about making it harder to crack many passwords at once.


True, never argued otherwise.

Quote:
I don't get what you're saying about what was so clear when you appended the pepper: as long as you turn it into a hexadecimal string to match the hash output (eg, with bin2hex) then it all looks the same.


I knew about the method you suggest, was went the opposite way to convert the other way to save on storage space (what can I say, I'm old school, started programming on a Commodore Vic-20, so have always been paranoid about the "smallest footprint possible", not the late 90's Microsoft theme of "if you build it, they will add more ram!" ;)

Quote:
Additionally, no thread like this should go without a mention of how one should be using password_hash() or bcrypt instead of trying to roll their own.


Yep, as mentioned in the first line, that is the route I was going, swapping out on sites for password_hash() as it is better. (For fun, when testing to see what all characters can be used in the result, I had it do 10,000 hashes, my laptop averaged 500 per minute, while using hash('sha256',$pass), it did 10,000 instantly)

The main point of the post wasn't to argue hashing methods, as I know I got overly crazy stupid with some things I do for my own compulsiveness, but more for the correct logic method to use to convert between different bases. There is a function in PHP to handle this as long as you are only up to base 36 (a-z0-9). I know you can do some fancy stuff with shifting bits in values and such, I just always have to work and play around for fancier stuff like that, and was stuck on what to actually look for.


Top
 Profile  
 
PostPosted: Mon Feb 24, 2014 4:29 pm 
Offline
Spammer :|
User avatar

Joined: Wed Oct 15, 2008 2:35 am
Posts: 6617
Location: WA, USA
twinedev wrote:
Quote:
I don't get what you're saying about what was so clear when you appended the pepper: as long as you turn it into a hexadecimal string to match the hash output (eg, with bin2hex) then it all looks the same.


I knew about the method you suggest, was went the opposite way to convert the other way to save on storage space (what can I say, I'm old school, started programming on a Commodore Vic-20, so have always been paranoid about the "smallest footprint possible", not the late 90's Microsoft theme of "if you build it, they will add more ram!" ;)

I also like to try to save space when possible, but also consider how much your time costs. Which is cheaper: spending more of your time trying to save a few bytes per user of disk space, or getting it done now and moving on to the next issue that needs your attention?

Quote:
The main point of the post wasn't to argue hashing methods, as I know I got overly crazy stupid with some things I do for my own compulsiveness, but more for the correct logic method to use to convert between different bases. There is a function in PHP to handle this as long as you are only up to base 36 (a-z0-9). I know you can do some fancy stuff with shifting bits in values and such, I just always have to work and play around for fancier stuff like that, and was stuck on what to actually look for.

I did try to get to that (though maybe not as well as I expected) - I just wanted to make sure that anybody else who finds this thread is caught up with what the two of us already know.



First, a change I would make would be to get the pepper using the full 8-bit spread of randomness. openssl_random_pseudo_bytes is great for that. It can be made "typeable" at the very end, after being appended to the hash. Unless you wanted the pepper itself typeable?
Syntax: [ Download ] [ Hide ]
$strPepper = openssl_random_pseudo_bytes(12);


After that... I'm not sure. 94 is an awkward number to work with - a proper base conversion would involve a lot of carry operations as there's no simple ratio between it and, well, any power of two. However arbitrary base conversion code isn't hard to do.
An alternative would be to stay your current path with the convention that 4 bytes of base 16 are converted to 3 bytes of base 94, even though it's not a straight equality (the first byte only has a range of 33-40, and 0xFFFF converts to 40,72,51). That would be a weakness though.
Yet another alternative, for the sake of saving space on a normal 64+12 hexadecimal string would be leaving the hash (and pepper) in raw binary and base-64 encoding them. That's 32+12 bytes of raw input, *4/3 for the base conversion, leaves you with 59 bytes of output. Compare that to the 57 of your base-94. Though I'm pretty sure it would have the tell-tale equals sign(s) at the end - which you could trim off though (just remember to add them back if you need to decode it).

Given the complexity of the second option, I think what you have now is the most straight-forward and maintainable way of writing it. I feel like bit arithmetic could work too but I'm not sure how.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 4 posts ] 

All times are UTC - 5 hours


Who is online

Users browsing this forum: No registered users and 4 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Jump to:  
Powered by phpBB® Forum Software © phpBB Group