package bhash import ( "bytes" "crypto/sha512" "encoding/binary" "golang.org/x/crypto/blowfish" ) var ( magic = []byte("OxychromaticBlowfishSwatDynamite") rounds = 64 words = blowfish.BlockSize hashSize = words * 4 ) func Hash(pass, salt []byte) []byte { c, err := blowfish.NewSaltedCipher(pass, salt) if err != nil { panic(err) } // key expansion for i := 0; i < rounds; i++ { blowfish.ExpandKey(salt, c) blowfish.ExpandKey(pass, c) } // encryption buf := new(bytes.Buffer) for n := 0; n < len(magic)/words; n++ { b := make([]byte, words) copy(b, magic[n*words:(n+1)*words]) for i := 0; i < rounds; i++ { c.Encrypt(b, b) } // swap bytes and copy out var u [2]uint32 binary.Read(bytes.NewReader(b), binary.BigEndian, &u) binary.Write(buf, binary.LittleEndian, u) } return buf.Bytes() } func Pbkdf(pass, salt []byte, iter, keyLen int) []byte { // collapse password h := sha512.New() h.Write(pass) sha2pass := h.Sum(nil) numBlocks := (keyLen + hashSize - 1) / hashSize out := make([]byte, hashSize) key := make([]byte, hashSize*numBlocks) for n := 1; n <= numBlocks; n++ { // first round, salt is salt h.Reset() h.Write(salt) binary.Write(h, binary.BigEndian, uint32(n)) tmp := Hash(sha2pass, h.Sum(nil)) copy(out, tmp) for i := 1; i < iter; i++ { h.Reset() h.Write(tmp) tmp = Hash(sha2pass, h.Sum(nil)) for x := range tmp { out[x] ^= tmp[x] } } // pbkdf2 deviation: output the key material non-linearly for x := range out { dst := x*numBlocks + (n - 1) key[dst] = out[x] } } return key[:keyLen] }