func (c *crypter) Generate(key, salt []byte) (string, error) { if len(salt) == 0 { salt = c.Salt.GenerateWRounds(SaltLenMax, RoundsDefault) } salt, rounds, isRoundsDef, _, err := c.Salt.Decode(salt) if err != nil { return "", err } keyLen := len(key) saltLen := len(salt) h := sha512.New() // compute sumB // step 4-8 h.Write(key) h.Write(salt) h.Write(key) sumB := h.Sum(nil) // Compute sumA // step 1-3, 9-12 h.Reset() h.Write(key) h.Write(salt) h.Write(internal.RepeatByteSequence(sumB, keyLen)) for i := keyLen; i > 0; i >>= 1 { if i%2 == 0 { h.Write(key) } else { h.Write(sumB) } } sumA := h.Sum(nil) internal.CleanSensitiveData(sumB) // Compute seqP // step 13-16 h.Reset() for i := 0; i < keyLen; i++ { h.Write(key) } seqP := internal.RepeatByteSequence(h.Sum(nil), keyLen) // Compute seqS // step 17-20 h.Reset() for i := 0; i < 16+int(sumA[0]); i++ { h.Write(salt) } seqS := internal.RepeatByteSequence(h.Sum(nil), saltLen) // step 21 for i := 0; i < rounds; i++ { h.Reset() if i&1 != 0 { h.Write(seqP) } else { h.Write(sumA) } if i%3 != 0 { h.Write(seqS) } if i%7 != 0 { h.Write(seqP) } if i&1 != 0 { h.Write(sumA) } else { h.Write(seqP) } copy(sumA, h.Sum(nil)) } internal.CleanSensitiveData(seqP) internal.CleanSensitiveData(seqS) // make output buf := bytes.Buffer{} buf.Grow(len(c.Salt.MagicPrefix) + len(_rounds) + 9 + 1 + len(salt) + 1 + 86) buf.Write(c.Salt.MagicPrefix) if isRoundsDef { buf.Write(_rounds) buf.WriteString(strconv.Itoa(rounds)) buf.WriteByte('$') } buf.Write(salt) buf.WriteByte('$') buf.Write(common.Base64_24Bit([]byte{ sumA[42], sumA[21], sumA[0], sumA[1], sumA[43], sumA[22], sumA[23], sumA[2], sumA[44], sumA[45], sumA[24], sumA[3], sumA[4], sumA[46], sumA[25], sumA[26], sumA[5], sumA[47], sumA[48], sumA[27], sumA[6], sumA[7], sumA[49], sumA[28], sumA[29], sumA[8], sumA[50], sumA[51], sumA[30], sumA[9], sumA[10], sumA[52], sumA[31], sumA[32], sumA[11], sumA[53], sumA[54], sumA[33], sumA[12], sumA[13], sumA[55], sumA[34], sumA[35], sumA[14], sumA[56], sumA[57], sumA[36], sumA[15], sumA[16], sumA[58], sumA[37], sumA[38], sumA[17], sumA[59], sumA[60], sumA[39], sumA[18], sumA[19], sumA[61], sumA[40], sumA[41], sumA[20], sumA[62], sumA[63], })) return buf.String(), nil }
func (c *crypter) Generate(key, salt []byte) (result string, err error) { if len(salt) == 0 { salt = c.Salt.Generate(SaltLenMax) } salt, _, _, _, err = c.Salt.Decode(salt) if err != nil { return } keyLen := len(key) h := md5.New() // Compute sumB h.Write(key) h.Write(salt) h.Write(key) sumB := h.Sum(nil) // Compute sumA h.Reset() h.Write(key) h.Write(c.Salt.MagicPrefix) h.Write(salt) h.Write(internal.RepeatByteSequence(sumB, keyLen)) // The original implementation now does something weird: // For every 1 bit in the key, the first 0 is added to the buffer // For every 0 bit, the first character of the key // This does not seem to be what was intended but we have to follow this to // be compatible. for i := keyLen; i > 0; i >>= 1 { if i%2 == 0 { h.Write(key[0:1]) } else { h.Write([]byte{0}) } } sumA := h.Sum(nil) internal.CleanSensitiveData(sumB) // In fear of password crackers here comes a quite long loop which just // processes the output of the previous round again. // We cannot ignore this here. for i := 0; i < RoundsDefault; i++ { h.Reset() // Add key or last result. if i%2 != 0 { h.Write(key) } else { h.Write(sumA) } // Add salt for numbers not divisible by 3. if i%3 != 0 { h.Write(salt) } // Add key for numbers not divisible by 7. if i%7 != 0 { h.Write(key) } // Add key or last result. if i&1 != 0 { h.Write(sumA) } else { h.Write(key) } copy(sumA, h.Sum(nil)) } buf := bytes.Buffer{} buf.Grow(len(c.Salt.MagicPrefix) + len(salt) + 1 + 22) buf.Write(c.Salt.MagicPrefix) buf.Write(salt) buf.WriteByte('$') buf.Write(common.Base64_24Bit([]byte{ sumA[12], sumA[6], sumA[0], sumA[13], sumA[7], sumA[1], sumA[14], sumA[8], sumA[2], sumA[15], sumA[9], sumA[3], sumA[5], sumA[10], sumA[4], sumA[11], })) return buf.String(), nil }