APR1The Apache-defined APR1 hashing format addresses the problems of brute forcing an MD5 hash, and basically iterates over the hash value 1,000 times. This considerably slows an intruder as they try to crack the hashed value. The resulting hashed string contains \$apr1\$" to identify it and uses a 48-bit salt value. The other typical Unix hashes are: BCrypt, SHA-256 Crypt and SHA-512 Crypt. In this case we will use 1,000 rounds for these. How to check?If you have OpenSSL, you basically take your salt and the password, and check. If we get "\$apr1\$8sFt66rZ\$Y7XkHshZq90L3ql/CaLy50", then the salt is between the second dollar signs and is "8sFt66rZ". If the password is "hello" we check with: C:\openssl>openssl passwd -apr1 -salt 8sFt66rZ hello $apr1$8sFt66rZ$Y7XkHshZq90L3ql/CaLy50 We can also create a simple Python program with the passlib library, and add the same salt as the example above: import passlib.hash; import sys salt="8sFt66rZ" string="hello" if (len(sys.argv)>1): string=str(sys.argv[1]) if (len(sys.argv)>2): salt=str(sys.argv[2]) print ("Input:\t",string) print ("Salt:\t",salt) print ("\nAPR1:\t"+passlib.hash.apr_md5_crypt.hash(string, salt=salt)) print ("\nSHA-256 Crypt:\t"+passlib.hash.sha256_crypt.hash(string, salt=salt,rounds=1000)) print ("\nSHA-512 Crypt:\t"+passlib.hash.sha512_crypt.hash(string, salt=salt,rounds=1000)) print ("\nSHA-1 Crypt:\t"+passlib.hash.sha1_crypt.hash(string, salt=salt,rounds=1000)) print ("\nBCrypt:\t"+passlib.hash.bcrypt.hash(string, salt=salt.zfill(22))) print ("\nArgon 2:\t"+passlib.hash.argon2.hash(string)) print ("\nphpass:\t"+passlib.hash.phpass.hash(string)) print ("\npbkdf2_sha1:\t"+passlib.hash.pbkdf2_sha1.hash(string)) print ("\npbkdf2_sha256:\t"+passlib.hash.pbkdf2_sha256.hash(string)) print ("\npbkdf2_sha512:\t"+passlib.hash.pbkdf2_sha512.hash(string)) print ("\nscrypt:\t"+passlib.hash.scrypt.hash(string)) If we run with the same salt as the example above we get: Input: hello Salt: 8sFt66rZ APR1: $apr1$8sFt66rZ$Y7XkHshZq90L3ql/CaLy50 SHA-256 Crypt: $5$rounds=1000$8sFt66rZ$DPV0rAhS02VmmN3xQ6iD2czxBeUgGBQCxeheH3yc6Z1 SHA-512 Crypt: $6$rounds=1000$8sFt66rZ$mFhgPdUwGcjS68bv4Hmw1h/AQWJkdJHPRySmy1oIm4ZNOukWYPasJPkAUUl3jPy8PkmfgcCIxf/pnNRX7kMKH1 SHA-1 Crypt: $sha1$1000$8sFt66rZ$w2.rXlpSCzN6JhtJSHrgqgSYQ5Hx BCrypt: $2b$12$000000000000008sFt66rOIk69ADw8.yQCIPB249.vgap7jTf/Iji |
Code
Code uses Cryptsharp here
// Specify the $apr1$ Apache htpasswd variant of the MD5 crypt algorithm. string cryptedPassword = Crypter.MD5.Crypt(val1, new CrypterOptions() { {CrypterOption.Variant, MD5CrypterVariant.Apache } });