package gaspass import ( "encoding/binary" "errors" "golang.org/x/crypto/argon2" ) const ( CharsLower string = "abcdefghijklmnopqrstuvwxyz" CharsUpper string = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" CharsNumbers string = "0123456789" // !#$%&'()*+,-./:;<=>?@[\]^_{|}~`" CharsSpecials string = "\x21\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x3a\x3b\x3c\x3d\x3e\x3f\x40\x5b\x5c\x5d\x5e\x5f\x7b\x7c\x7d\x7e\x60\x22" ) const ( argonMemory uint32 = 128 * 1024 // KiB argonIters uint32 = 8 argonThreads uint8 = 3 ) type Params struct { PrivKey []byte Salt []byte Counter []byte // Actually it is a part of argon salt so let it be the same type PassLength uint32 UseLower bool UseUpper bool UseNumbers bool UseSpecials bool } func (p *Params) GeneratePassword() (*string, error) { // TODO: Check PassLength <= MAX_UINT32/8 var charSet string if ! (p.UseLower || p.UseUpper || p.UseNumbers || p.UseSpecials) { return nil, errors.New("Use at least one character group.") } if p.UseLower { charSet += CharsLower } if p.UseUpper { charSet += CharsUpper } if p.UseNumbers { charSet += CharsNumbers } if p.UseSpecials { charSet += CharsSpecials } dkey := argon2.IDKey(p.PrivKey, append(p.Counter, p.Salt...), argonIters, argonMemory, argonThreads, p.PassLength*8) password := "" for cn := 0; cn < len(dkey); cn += 8 { password += string(charSet[binary.BigEndian.Uint64(dkey[cn:cn+8])%uint64(len(charSet))]) } return &password, nil }