func (s Salt) Match(ref []byte, minSecretLen int, maxSecretLen int) (bool, error) {
	res, _ := s.Generate(minSecretLen, maxSecretLen)
	ok := bytes.Equal(res, ref)
	return ok, nil
}
Match : compare 2 given salt information
package salt
import (
	"bytes"
	"crypto/rand"
	"crypto/sha1"
	"fmt"
	"hash"
	"io"
	logger "github.com/ibm-security-innovation/libsecurity-go/logger"
)
const (
	defaultOutputLen        = 128
	defaultSaltLen          = 8
	defaultNumOfItterations = 1
	minOutputLen        = 6
	minSaltLen          = 0
	maxSaltLen          = 128
	minNumOfItterations = 1
)
var defaultHashFunc = sha1.New
type Salt struct {
	Secret     []byte
	Salt       []byte
	OutputLen  int               
	Iterations int               
	Digest     func() hash.Hash  
}
func (s Salt) String() string {
	ret := fmt.Sprintf("Salt info: secret: %v, salt: %v, iterations: %v, output len: %v, digest: %v",
		string(s.Secret), string(s.Salt), s.Iterations, s.OutputLen, s.Digest)
	return ret
}
func isOutputLenValid(val int) error {
	if val < minOutputLen {
		return fmt.Errorf("Salt struct is not valid, The output length %v is less than the minimum %v", val, minOutputLen)
	}
	return nil
}
func isDigestValid(digest func() hash.Hash) error {
	if digest == nil {
		return fmt.Errorf("Salt struct is not valid, It must have a hash function, but the current hash is nil")
	}
	return nil
}
func isSecretValid(secret []byte, minSecretLen int, maxSecretLen int) error {
	if len(secret) < minSecretLen || len(secret) > maxSecretLen {
		return fmt.Errorf("Secret string has illegal length %v, The length must be between %v and %v", len(secret), minSecretLen, maxSecretLen)
	}
	return nil
}
func isSaltValid(salt []byte) error {
	if len(salt) < minSaltLen || len(salt) > maxSaltLen {
		return fmt.Errorf("Salt string has illegal length %v, The length must be between %v and %v", len(salt), minSaltLen, maxSaltLen)
	}
	return nil
}
func isNumOfIterationsValid(val int) error {
	if val < minNumOfItterations {
		return fmt.Errorf("Salt struct is not valid, The number of iterations %v is less than the minimum %v", val, minNumOfItterations)
	}
	return nil
}
func (s Salt) isValid(minSecretLen int, maxSecretLen int) error {
	err := isSecretValid(s.Secret, minSecretLen, maxSecretLen)
	if err != nil {
		return err
	}
	err = isSaltValid(s.Salt)
	if err != nil {
		return err
	}
	err = isOutputLenValid(s.OutputLen)
	if err != nil {
		return err
	}
	err = isNumOfIterationsValid(s.Iterations)
	if err != nil {
		return err
	}
	err = isDigestValid(s.Digest)
	if err != nil {
		return err
	}
	return nil
}
func NewSalt(secret []byte, minSecretLen int, maxSecretLen int, salt []byte) (*Salt, error) {
	err := isSecretValid(secret, minSecretLen, maxSecretLen)
	if err != nil {
		return nil, err
	}
	err = isSaltValid(salt)
	if err != nil {
		return nil, err
	}
	return &Salt{
		secret,
		salt,
		defaultOutputLen,
		defaultNumOfItterations,
		defaultHashFunc,
	}, nil
}
func GenerateSaltedPassword(pwd []byte, minSecretLen int, maxSecretLen int, saltData []byte, passwordLen int) ([]byte, error) {
	mySalt, err := NewSalt([]byte(pwd), minSecretLen, maxSecretLen, saltData)
	if err != nil {
		return nil, err
	}
	if passwordLen != -1 {
		mySalt.OutputLen = passwordLen
	}
	return mySalt.Generate(minSecretLen, maxSecretLen)
}
func GeneratePasswordWithRndSalt(pass string, minSecretLen int, maxSecretLen int) ([]byte, []byte, error) {
	salt, err := GetRandomSalt(defaultSaltLen)
	if err != nil {
		return nil, nil, err
	}
	s, err := NewSalt([]byte(pass), minSecretLen, maxSecretLen, salt)
	if err != nil {
		return nil, nil, err
	}
	saltedPass, err := s.Generate(minSecretLen, maxSecretLen)
	return saltedPass, salt, err
}
func (s Salt) Generate(minSecretLen int, maxSecretLen int) ([]byte, error) {
	err := s.isValid(minSecretLen, maxSecretLen)
	if err != nil {
		return []byte(""), err
	}
	h := s.Digest()
	data := s.Secret
	for i := 0; i < s.Iterations; i++ {
		data = append(data, s.Salt...)
		h.Write(data)
		data = h.Sum(nil)
	}
	logger.Trace.Println("data:", data)
	len := len(data)
	if len > s.OutputLen {
		len = s.OutputLen
	}
	ret := data[0:len]
	return ret, nil
}