// Copyright 2012, Jeramey Crawford // Copyright 2013, Jonas mg // All rights reserved. // // Use of this source code is governed by a BSD-style license // that can be found in the LICENSE file. package common import ( "crypto/rand" "errors" "strconv" ) var ( ErrSaltPrefix = errors.New("invalid magic prefix") ErrSaltFormat = errors.New("invalid salt format") ErrSaltRounds = errors.New("invalid rounds") ) // Salt represents a salt. type Salt struct { MagicPrefix []byte SaltLenMin int SaltLenMax int RoundsMin int RoundsMax int RoundsDefault int } func (s *Salt) Generate(length int) []byte { if length > s.SaltLenMax { length = s.SaltLenMax } else if length < s.SaltLenMin { length = s.SaltLenMin } saltLen := (length * 6 / 8) if (length*6)%8 != 0 { saltLen++ } salt := make([]byte, saltLen) _, err := rand.Read(salt) if err != nil { return []byte{} } out := make([]byte, len(s.MagicPrefix)+length) copy(out, s.MagicPrefix) copy(out[len(s.MagicPrefix):], Base64_24Bit(salt)) return out } func (s *Salt) GenerateWRounds(length, rounds int) []byte { if length > s.SaltLenMax { length = s.SaltLenMax } else if length < s.SaltLenMin { length = s.SaltLenMin } if rounds < 0 { rounds = s.RoundsDefault } else if rounds < s.RoundsMin { rounds = s.RoundsMin } else if rounds > s.RoundsMax { rounds = s.RoundsMax } saltLen := (length * 6 / 8) if (length*6)%8 != 0 { saltLen++ } salt := make([]byte, saltLen) _, err := rand.Read(salt) if err != nil { return []byte{} } roundsText := "" if rounds != s.RoundsDefault { roundsText = "rounds=" + strconv.Itoa(rounds) + "$" } out := make([]byte, len(s.MagicPrefix)+len(roundsText)+length) copy(out, s.MagicPrefix) copy(out[len(s.MagicPrefix):], []byte(roundsText)) copy(out[len(s.MagicPrefix)+len(roundsText):], Base64_24Bit(salt)) return out }