package passwd import ( "crypto/hmac" "crypto/sha1" "fmt" "strconv" ) type SHA1Crypt struct { Passwd } func NewSHA1Passwd() PasswdInterface { m := new(SHA1Crypt) m.Magic = SHA1_CRYPT_MAGIC m.Params = "262144" m.i = m return m } // PBKDF1 with SHA1 crypt algorithm. func (a *SHA1Crypt) Hash(password []byte, salt []byte, iterations uint64) (hash []byte) { // We store the magic bytes as a string as we use sprintf to // encode the outputs and easily translate the iterations // from an uint64 to a string. magic := a.Magic // The first bit we encode into the hmac is the salt, // magic string, and iterations of hmac rounds. output := fmt.Sprintf("%s%s%d", salt, magic, iterations) // Setup hmac with the password as the key. hm := hmac.New(sha1.New, password) // Write the salt and parameters to the hmac. hm.Write([]byte(output)) // Get the first sum for the iterrations. buf := hm.Sum(nil) // Iterate the hmac to the specified number of iterations. for i := uint64(1); i < iterations; i++ { // Setup the hmac for this iteration. hm.Reset() // Feed back in the buffer from the last iteration. hm.Write(buf) // Get the buffer from this iteration. buf = hm.Sum(nil) } // Create hash with result. b64 := Base64Encode(buf) hash = []byte(fmt.Sprintf("%s%d$%s$", magic, iterations, salt)) hash = append(hash, b64...) return } // Override the hash with salt function to encode PBKDF1 with SHA1 hash. func (a *SHA1Crypt) HashPasswordWithSalt(password []byte, salt []byte) (hash []byte, err error) { iterations, err := strconv.ParseUint(a.Params, 10, 64) if err != nil { return nil, err } hash = a.Hash(password, salt, iterations) return }