Hello,

I have been looking into using the SHA256/SHA512 crypt_hash functions, and 
during my testing, comparing the results with other implementations (Python's 
passlib, Openssl, MySQL and C), I found that for some passwords used, the 
resulting hash is different that the ones generated by other 
languages/implementations, and therefore would fail if a hash of these 
passwords done with Pike was then computed/verified with another system.

I don't know the reason of this, but it seems to fail with some passwords, 
regardless of the salt or number of rounds, and both SHA256 and SHA512 "fail", 
while for some other passwords it works well. A couple of values that fail are 
simply "pass" and "password".

Below I attach some examples, using the mentioned failing passwords, first in 
Pike, and then comparing the computation of the same hash, using the same 
password/salt/rounds in other implementations, and you can see that all the 
rest are the same among  them, but different from Pike. This fails also using 
Crypto.Password.hash(), and letting it compute a random salt. I also tested the 
reference base C implementation cited in your documentation 
(https://akkadia.org/drepper/SHA-crypt.txt), and it gives the same result as 
the others (and thus, different than Pike's).

In addition, I also found that in some cases, the random salt contains the 
character "+", which the Python library I tested doesn't 'allow' it seems, this 
is probably not a bug itself, but could be taken into account for future 
implementations when generating a salt, I attach here their explanation:

>From Python's passlib docs: "Restricted salt string character set:

"The underlying algorithm can unambiguously handle salt strings which contain 
any possible byte value besides \x00 and $. However, Passlib strictly limits 
salts to the hash64 character set, as nearly all implementations of 
sha256-crypt generate and expect salts containing those characters, but may 
have unexpected behaviors for other character values."

The hash64 character set is:
HASH64_CHARS = 
u("./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")


I would like to know if this is really a bug, and if it is, if you would be 
able to maybe fix it in some revision, if that's the case, I would be 
interested in using the updated/corrected code ASAP, implementing it in a 
module of my own perhaps.



Code examples:


Pike v8.0 release 1116 running Hilfe v3.5 (Incremental Pike Frontend):

> Crypto.SHA512.crypt_hash("pass","salt",10000);
(1) Result: 
"gJkLS5cThyks4JXgQ8x3UNvwYLNW22AHZdM70xoRvEma//RJfeBOC/Ik0EddD7DLI9Sau9pYCV29OLzxxVFph1"

> Crypto.Password.hash("pass","6",10000);
(2) Result: 
"$6$rounds=10000$UrtM9r9XUEqEp1H3$X.OaL5Jp8PNtjkgKPUdGv7hxFg.jjF0U0dqLnscH3F45socUKOP6jWK2hDtvZAj2f1/I1u7Sgc3n3U7MMJDIi1"

> Crypto.SHA512.crypt_hash("password","salt",10000);
(3) Result: 
"aaSSVStpZx9F9OYvj2130N4GR9uJcP/A10FvDYjBQWbs2RAYN.9iCJb9GvREy9Huz7H6Bp6u5SlHEEcrxaDPi0"

> Crypto.Password.hash("password","6",10000);
(4) Result: 
"$6$rounds=10000$CfcWNrK0SB8eROnk$a/agNPy2AKOVf4qNTHRXw16nUSjHeINZCTxgw5PjLlRBFnxJ6DDI/rebM3I8LD8pubgOji7ps70JddbFUWo190"

> Crypto.SHA256.crypt_hash("pass","salt",10000);
(5) Result: "s2.jgIPueybkP3hvZqjt3ql5emK9LDBUGvrNc8Cfq3B"

> Crypto.Password.hash("pass","5",10000);
(6) Result: 
"$5$rounds=10000$Pjj07C7RqLD+ydig$Heqa8mVcO6ttpcXxxtmYoRF6kuPDbieJgy8YPkNNpl."

> Crypto.Password.hash("pass","5",10000);
(7) Result: 
"$5$rounds=10000$PKoyOiOCTDQTwjBS$jgKXglMIaloY8JPEz/Zp14q1S6qrG2DShYeEUuO4YC4"

-----------------
Python:

>>> from passlib.hash import sha512_crypt

>>> sha512_crypt.hash("pass", salt="salt",rounds=10000)
'$6$rounds=10000$salt$OSEwMhCIwtjyui53YYIYdyKYKKMcnmS2EbioMYM3/7ya4jWlyYim8VJvMW4cVEgVkO.a.YBgUKiMtpAGUQSXf.'

>>> sha512_crypt.hash("pass", salt="UrtM9r9XUEqEp1H3",rounds=10000)
'$6$rounds=10000$UrtM9r9XUEqEp1H3$IazyuGXF.YEWCnYtarD5BGYduUW2zzydYZXN3xa5QfHx5wvE.lQyU2rPnqMSiSLMvXR0En2Suo/2805nGp1FU.'

>>> sha512_crypt.hash("password", salt="salt",rounds=10000)
'$6$rounds=10000$salt$dE5fLfpn2uXfkz.eouwYK/BjrHRu.piovQPjwlE06fDJHwMlg2l.IqEBUIfWBzf7YPXOAddB3FM7rnXHHKVNt.'

>>> sha512_crypt.hash("password", salt="CfcWNrK0SB8eROnk",rounds=10000)
'$6$rounds=10000$CfcWNrK0SB8eROnk$wuB7fFzyIokmn5WLk2theKXOpBbIkuyRqtUNTtwPWdEI7eKi.dnvcPtrM337BUXvgUXwrBPYWjKFl.r0i39Yz0'

>>> pike_hash = 
>>> "$6$rounds=10000$UrtM9r9XUEqEp1H3$X.OaL5Jp8PNtjkgKPUdGv7hxFg.jjF0U0dqLnscH3F45socUKOP6jWK2hDtvZAj2f1/I1u7Sgc3n3U7MMJDIi1"
>>> sha512_crypt.verify("pass",pike_hash)
False

>>> pike_hash2="$6$rounds=10000$CfcWNrK0SB8eROnk$a/agNPy2AKOVf4qNTHRXw16nUSjHeINZCTxgw5PjLlRBFnxJ6DDI/rebM3I8LD8pubgOji7ps70JddbFUWo190"
>>> sha512_crypt.verify("password",pike_hash2)
False

>>> sha256_crypt.hash("pass", salt="salt",rounds=10000)
'$5$rounds=10000$salt$Lffn09CeAx2gukDdao1thbgNhgpn41BG4JJNh0Nk6C/'

>>> pike_hash3 = 
>>> '$5$rounds=10000$Pjj07C7RqLD+ydig$Heqa8mVcO6ttpcXxxtmYoRF6kuPDbieJgy8YPkNNpl.'

>>> sha256_crypt.verify("pass",pike_hash3)
Traceback (most recent call last):
(...)
raise ValueError("invalid characters in %s salt" % cls.name)
ValueError: invalid characters in sha256_crypt salt

>>> sha256_crypt.hash("pass", salt="Pjj07C7RqLD+ydig",rounds=10000)
Traceback (most recent call last):
(...)
raise ValueError("invalid characters in %s salt" % cls.name)
ValueError: invalid characters in sha256_crypt salt

>>> pike_hash4 = 
>>> "$5$rounds=10000$PKoyOiOCTDQTwjBS$jgKXglMIaloY8JPEz/Zp14q1S6qrG2DShYeEUuO4YC4"
>>> sha256_crypt.verify("pass",pike_hash4)
False


------------------

Openssl:
$ openssl passwd -6 -salt 'rounds=10000$salt' 'pass'
$6$rounds=10000$salt$OSEwMhCIwtjyui53YYIYdyKYKKMcnmS2EbioMYM3/7ya4jWlyYim8VJvMW4cVEgVkO.a.YBgUKiMtpAGUQSXf.

$ openssl passwd -6 -salt 'rounds=10000$salt' 'password'
$6$rounds=10000$salt$dE5fLfpn2uXfkz.eouwYK/BjrHRu.piovQPjwlE06fDJHwMlg2l.IqEBUIfWBzf7YPXOAddB3FM7rnXHHKVNt.

$ openssl passwd -5 -salt 'rounds=10000$salt' 'pass'
$5$rounds=10000$salt$Lffn09CeAx2gukDdao1thbgNhgpn41BG4JJNh0Nk6C/

$ openssl passwd -5 -salt 'rounds=10000$Pjj07C7RqLD+ydig' 'pass'
$5$rounds=10000$Pjj07C7RqLD+ydig$56R7PRLYPMhN07ZhnoGFCKkNK5.N0ZDY0hViH4yG19/


-----------------
MySQL:

SELECT ENCRYPT('pass', '$6$rounds=10000$salt');
$6$rounds=10000$salt$OSEwMhCIwtjyui53YYIYdyKYKKMcnmS2EbioMYM3/7ya4jWlyYim8VJvMW4cVEgVkO.a.YBgUKiMtpAGUQSXf.

SELECT ENCRYPT('password', '$6$rounds=10000$salt');
$6$rounds=10000$salt$dE5fLfpn2uXfkz.eouwYK/BjrHRu.piovQPjwlE06fDJHwMlg2l.IqEBUIfWBzf7YPXOAddB3FM7rnXHHKVNt.


SELECT ENCRYPT('pass', '$5$rounds=10000$salt');
$5$rounds=10000$salt$Lffn09CeAx2gukDdao1thbgNhgpn41BG4JJNh0Nk6C/

SELECT ENCRYPT('pass', '$5$rounds=10000$Pjj07C7RqLD+ydig');
$5$rounds=10000$Pjj07C7RqLD+ydig$56R7PRLYPMhN07ZhnoGFCKkNK5.N0ZDY0hViH4yG19/

-----------------



I await your response, thank you for your time.
Yours truthfully,

Ricard Garra Oronich
Desarollador de Núcleo | Core Developer
[email protected]
(+34) 680 423 701
[http://www.lleida.net/mailing/fires/signatura.png]
Parc Científic i Tecnològic Agroalimentari de Lleida
Edifici H1 2a planta B | 25003 Lleida (Spain)
Tel. (+34) 973 282 300
Fax (+34) 973 282 195
www.lleida.net<http://www.lleida.net>
Política de privacidad<http://www.lleida.net/es/privacy.html>
  • SHA256/SHA512 cryp... Ricard Garra Oronich

Reply via email to