Skip to content

Instantly share code, notes, and snippets.

@0xef53
Created February 25, 2019 04:28
Show Gist options
  • Save 0xef53/f56ac4e12869c41c7c02433ee80ddf77 to your computer and use it in GitHub Desktop.
Save 0xef53/f56ac4e12869c41c7c02433ee80ddf77 to your computer and use it in GitHub Desktop.
MD5 hashing function (like mkpasswd --hash=md5)
func md5Crypt(password string, salt string, prefix string) string {
// start with a hash of password and salt
initBin := md5.Sum([]byte(password + salt + password))
// begin an initial string with hash and salt
initText := bytes.NewBufferString(password + prefix + salt)
// add crap to the string willy-nilly
for i := len(password); i > 0; i -= 16 {
lim := i
if lim > 16 {
lim = 16
}
initText.Write(initBin[0:lim])
}
// add more crap to the string willy-nilly
for i := len(password); i > 0; i >>= 1 {
if (i & 1) == 1 {
initText.WriteByte(byte(0))
} else {
initText.WriteByte(password[0])
}
}
// Begin our hashing in earnest using our initial string
bin := md5.Sum(initText.Bytes())
n := bytes.NewBuffer([]byte{})
for i := 0; i < 1000; i++ {
// prepare to make a new muddle
n.Reset()
// alternate password+crap+bin with bin+crap+password
if (i & 1) == 1 {
n.WriteString(password)
} else {
n.Write(bin[:])
}
// usually add the salt, but not always
if i%3 != 0 {
n.WriteString(salt)
}
// usually add the password but not always
if i%7 != 0 {
n.WriteString(password)
}
// the back half of that alternation
if (i & 1) == 1 {
n.Write(bin[:])
} else {
n.WriteString(password)
}
// replace bin with the md5 of this muddle
bin = md5.Sum(n.Bytes())
}
// At this point we stop transliterating the PHP code and flip back to
// reading the Apache source. The PHP uses their base64 library, but that
// uses the wrong character set so needs to be repaired afterwards and reversed
// and it is just really weird to read.
result := bytes.NewBuffer([]byte{})
// This is our own little similar-to-base64-but-not-quite filler
fill := func(a byte, b byte, c byte) {
v := (uint(a) << 16) + (uint(b) << 8) + uint(c) // take our 24 input bits
for i := 0; i < 4; i++ { // and pump out a character for each 6 bits
result.WriteByte("./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"[v&0x3f])
v >>= 6
}
}
// The order of these indices is strange, be careful
fill(bin[0], bin[6], bin[12])
fill(bin[1], bin[7], bin[13])
fill(bin[2], bin[8], bin[14])
fill(bin[3], bin[9], bin[15])
fill(bin[4], bin[10], bin[5]) // 5? Yes.
fill(0, 0, bin[11])
resultString := string(result.Bytes()[0:22]) // we wrote two extras since we only need 22.
return resultString
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment