-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit fec39e5
Showing
5 changed files
with
341 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# Compiled Object files, Static and Dynamic libs (Shared Objects) | ||
*.o | ||
*.a | ||
*.so | ||
|
||
# Folders | ||
_obj | ||
_test | ||
|
||
# Architecture specific extensions/prefixes | ||
*.[568vq] | ||
[568vq].out | ||
*.cgo1.go | ||
*.cgo2.c | ||
_cgo_defun.c | ||
_cgo_gotypes.go | ||
_cgo_export.* | ||
_testmain.go | ||
*.exe | ||
|
||
# Cloud 9 | ||
.c9revisions/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package passwords | ||
|
||
import ( | ||
"crypto/sha1" | ||
"encoding/hex" | ||
) | ||
|
||
// Passwords for MySql | ||
func Mysql(pass string) string { | ||
// Create our own hasher, for thread safety | ||
hasher := sha1.New() | ||
// This is actually really simple, it's just a sha1 of a sha1 displayed as hex | ||
// (with a leading * to indicate the 'new' password hash of MySql) | ||
hasher.Write([]byte(pass)) | ||
interm := hasher.Sum(nil) | ||
hasher.Reset() | ||
hasher.Write(interm) | ||
return "*" + hex.EncodeToString(hasher.Sum(nil)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
Passwords | ||
========= | ||
|
||
As far as I know, no one has bothered to port the crypt() function to other platforms, or even really looked at it in a long while. | ||
|
||
I found myself in need of being able to make unix password hashes in my Go programs, so I went hunting to re-create this functionality. I wasn't able to find the source of crypt() itself (at least not abstracted to the point that I'd have to dig through several libraries of source). But I did find a pure bash recreation of it, at least for sha512. While abhorently slow, this bash script did acurately produce the same output as crypt() (read: same output as mkpasswd). So I used this as a template for recreating it in Go. | ||
|
||
Long story short, I did it, and learned that crypt() is absurdly (and unessecarily) complicated (security through obscurity is not security, expecially when the source for your process is very public). | ||
|
||
I decided to make this into a library that'll provide the ability to programatically create various proprietary password hashes. So far this is just sha512 from crypt() and MySql's PASSWORD(). If you have/know of others please let me know! (or just make a pull request ;D) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,141 @@ | ||
package passwords | ||
|
||
import ( | ||
"crypto/sha512" | ||
"errors" | ||
"math/big" | ||
) | ||
|
||
const ( | ||
b64String = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" | ||
sigBytes = 86 | ||
) | ||
|
||
var ( | ||
// we have to re-arrange the hash towards the end, this is the new order (space efficient BECAUSE I CAN) | ||
newOrder = [64]uint8{ | ||
63, 62, 20, 41, 40, 61, 19, 18, 39, 60, 59, 17, 38, 37, 58, 16, 15, 36, 57, 56, 14, 35, | ||
34, 55, 13, 12, 33, 54, 53, 11, 32, 31, 52, 10, 9, 30, 51, 50, 8, 29, 28, 49, 7, | ||
6, 27, 48, 47, 5, 26, 25, 46, 4, 3, 24, 45, 44, 2, 23, 22, 43, 1, 0, 21, 42} | ||
big63 = big.NewInt(63) | ||
) | ||
|
||
// Creates a unix password string using sha512 | ||
func ShaCrypt(pass, salt string) (string, error) { | ||
// Get the length (we need this later) | ||
passLen := len(pass) | ||
saltLen := len(salt) | ||
|
||
// Salt must be the right length | ||
if saltLen < 8 || saltLen > 16 { | ||
return "", errors.New("arg 2 must be between 8 and 16 bytes long") | ||
} | ||
|
||
// Create the hasher (unique per instance to be thread safe :D) | ||
hasher := sha512.New() | ||
hashLen := hasher.Size() | ||
|
||
// Change to bytes, more naitive | ||
passByte := []byte(pass) | ||
saltByte := []byte(salt) | ||
|
||
// Create the 'alternate' | ||
hasher.Write(passByte) | ||
hasher.Write(saltByte) | ||
hasher.Write(passByte) | ||
alternate := hasher.Sum(nil) | ||
hasher.Reset() | ||
|
||
// Write the initial password and salt | ||
hasher.Write(passByte) | ||
hasher.Write(saltByte) | ||
|
||
// Write one byte of 'alternate' for every byte of the password | ||
for i := passLen; i != 0; { | ||
var n int | ||
if i > hashLen { | ||
n, _ = hasher.Write(alternate) | ||
} else { | ||
n, _ = hasher.Write(alternate[:i]) | ||
} | ||
i -= n | ||
} | ||
|
||
// Alternate between the password and the alternate for the length of the password | ||
for i := passLen; i != 0; i >>= 1 { | ||
if i&1 == 1 { | ||
hasher.Write(alternate) | ||
} else { | ||
hasher.Write(passByte) | ||
} | ||
} | ||
|
||
// Now we have our intermediate :D (re-using variables tho {this is for you gc :3}) | ||
alternate = hasher.Sum(nil) | ||
hasher.Reset() | ||
|
||
// Get value of the first byte | ||
firstByte := int(alternate[0]) | ||
|
||
// Get first passLen bytes of hash of password repeated passLen times | ||
for i := 0; i < passLen; i++ { | ||
hasher.Write(passByte) | ||
} | ||
pHash := hasher.Sum(nil)[:passLen] | ||
hasher.Reset() | ||
|
||
// Get the first saltLen bytes of hash of salt repeated (first byte of pass) + 16 times | ||
for i := 0; i < firstByte+16; i++ { | ||
hasher.Write(saltByte) | ||
} | ||
sHash := hasher.Sum(nil)[:saltLen] | ||
// We reset at the start on the next one (to avoid an extra call to reset), so we can skip this one | ||
//hasher.Reset() | ||
|
||
// Loop 5k times, on some do some things, others do others | ||
for i := 0; i < 5000; i++ { | ||
hasher.Reset() | ||
if i&1 == 1 { | ||
hasher.Write(pHash) | ||
} else { | ||
hasher.Write(alternate) | ||
} | ||
if i%3 != 0 { | ||
hasher.Write(sHash) | ||
} | ||
if i%7 != 0 { | ||
hasher.Write(pHash) | ||
} | ||
if i&1 == 1 { | ||
hasher.Write(alternate) | ||
} else { | ||
hasher.Write(pHash) | ||
} | ||
alternate = hasher.Sum(nil) | ||
} | ||
// Not using this again, so no need to reset | ||
//hasher.Reset() | ||
|
||
// Now re-arrange the intermediate | ||
intermediate := make([]byte, hashLen) | ||
for i, new := range newOrder { | ||
intermediate[i] = alternate[new] | ||
} | ||
|
||
// I THINK it's a normal b64 encoding (with the altered order of bytes used, see b64String) | ||
// but with the order the 6-bits are read reversed. That is if my understanding of b64 encoding | ||
// is correct. Bellow does what is needed, and very efficiently. I'll look into reversing the | ||
// order and using the base64 package later. | ||
asInt := big.NewInt(0) | ||
asInt.SetBytes(intermediate) | ||
rem := big.NewInt(0) | ||
realPass := make([]byte, sigBytes) | ||
for i := 0; i < sigBytes; i++ { | ||
rem.And(asInt, big63) | ||
realPass[i] = b64String[rem.Int64()] | ||
asInt.Rsh(asInt, 6) | ||
} | ||
|
||
// Done! | ||
return "$6$" + salt + "$" + string(realPass), nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
#!/bin/bash | ||
# sha512-crypt for GNU and Bash | ||
# By Vidar 'koala_man' Holen | ||
|
||
## This is the script that I used as reference to reverse engineer crypt(), at least for sha512 | ||
|
||
b64="./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" | ||
|
||
stringToNumber() { | ||
expression=0 | ||
for((i=0; i<${#1}; i++)) | ||
do | ||
expression=$(printf '(%s)*256+%d' "$expression" "'${1:$i:1}") | ||
done | ||
bc <<< "$expression" | ||
} | ||
|
||
# Turn some string into a \xd4\x1d hex string | ||
stringToHex() { | ||
for((i=0; i<${#1}; i++)) | ||
do | ||
printf '\\x%x' "'${1:i:1}" | ||
done | ||
} | ||
|
||
# Turn stdin into a \xd4\x1d style sha512 hash | ||
sha512hex() { | ||
sum=$(sha512sum) | ||
read sum rest <<< "$sum" # remove trailing dash | ||
hex=$(sed 's/../\\x&/g' <<< "$sum") | ||
echo "$hex" | ||
} | ||
|
||
# Turn an integer into a crypt base64 string with n characters | ||
### Take an number ($1) (representing a binary value), and return the first n ($2) b64 bytes of it | ||
intToBase64() { | ||
number=$1 | ||
n=$2 | ||
for((j=0; j<n; j++)) | ||
do | ||
digit=$(bc <<< "$number % 64") | ||
number=$(bc <<< "$number / 64") | ||
echo -n "${b64:digit:1}" | ||
done | ||
} | ||
|
||
# From hex string $1, get the bytes indexed by $2, $3 .. | ||
### This does the re-arraging of the hash | ||
getBytes() { | ||
num=$1 | ||
shift | ||
### This is a bashism, for i loops over $1 with shift | ||
for i | ||
do | ||
echo -n "${num:$((i*4)):4}" | ||
done | ||
} | ||
|
||
|
||
### converts a hex string to a number, the tr capitalizes it, sed removes the \x before the hex | ||
hexToInt() { | ||
{ | ||
echo 'ibase=16;' | ||
tr a-f A-F <<< "$1" | sed -e 's/\\x//g' | ||
} | bc | ||
} | ||
|
||
base64EncodeBytes() { | ||
n=$1 | ||
shift | ||
bytes=$(getBytes "$@") | ||
int=$(hexToInt "$bytes") | ||
intToBase64 "$int" "$n" | ||
} | ||
|
||
doHash() { | ||
password="$1" | ||
passwordLength=$(printf "$password" | wc -c) | ||
salt="$2" | ||
saltLength=$(printf "$salt" | wc -c) | ||
magic="$3" | ||
[[ -z $magic ]] && magic='$6$' | ||
|
||
salt=${salt#$magic} | ||
salt=${salt:0:64} # 16 first bytes | ||
|
||
intermediate=$( | ||
{ | ||
# Start intermediate result | ||
printf "$password$salt" | ||
# compute a separate sha512 sum | ||
alternate=$(printf "$password$salt$password" | sha512hex) | ||
# Add one byte from alternate for each character in the password. Wtf? | ||
while true; do printf "$alternate"; done | head -c "$passwordLength" | ||
# For every 1 bit in the key length, add the alternate sum | ||
# Otherwise add the entire key (unlike MD5-crypt) | ||
for ((i=$passwordLength; i != 0; i>>=1)) | ||
do | ||
if (( i & 1 )) | ||
then | ||
printf "$alternate" | ||
else | ||
printf "$password" | ||
fi | ||
done | ||
} | sha512hex | ||
) | ||
firstByte=$(hexToInt $(getBytes "$intermediate" 0)) | ||
|
||
p_bytes=$(for((i=0; i<$passwordLength; i++)); do printf "$password"; done | sha512hex | head -c $((passwordLength*4)) ) | ||
s_bytes=$(for((i=0; i<16+${firstByte}; i++)); do printf "$salt"; done | sha512hex | head -c $((saltLength*4)) ) | ||
|
||
|
||
for((i=0; i<5000; i++)) | ||
do | ||
intermediate=$({ | ||
(( i & 1 )) && printf "$p_bytes" || printf "$intermediate" | ||
(( i % 3 )) && printf "$s_bytes" | ||
(( i % 7 )) && printf "$p_bytes" | ||
(( i & 1 )) && printf "$intermediate" || printf "$p_bytes" | ||
} | sha512hex) | ||
done | ||
|
||
# Rearrange the bytes and crypt-base64 encode them | ||
hex=$(base64EncodeBytes 86 "$intermediate" \ | ||
63 62 20 41 40 61 19 18 39 60 59 17 38 37 58 16 15 36 57 56 14 35 \ | ||
34 55 13 12 33 54 53 11 32 31 52 10 9 30 51 50 8 29 28 49 7 \ | ||
6 27 48 47 5 26 25 46 4 3 24 45 44 2 23 22 43 1 0 21 42) | ||
|
||
printf "%s$salt\$%s\n" "$magic" "$hex" | ||
|
||
} | ||
|
||
|
||
if [[ $# < 1 ]] | ||
then | ||
echo "Usage: $0 password [salt]" >&2 | ||
exit 1 | ||
fi | ||
|
||
password=$(stringToHex "$1") | ||
salt=$(stringToHex "$2") | ||
[[ -z $salt ]] && salt=$(tr -cd 'a-zA-Z0-9' < /dev/urandom | head -c 16) | ||
|
||
doHash "$password" "$salt" '$6$' |