feat: BREAKING: change from string to []byte
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
package argon2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/rand"
|
||||
"crypto/subtle"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/crypto/argon2"
|
||||
|
||||
@@ -73,35 +73,35 @@ func NewArgon2id(
|
||||
}
|
||||
}
|
||||
|
||||
func (p *argon) Passwd(pass string, check string) (string, error) {
|
||||
func (p *argon) Passwd(pass, check []byte) ([]byte, error) {
|
||||
var args *pwArgs
|
||||
var err error
|
||||
|
||||
if check == "" {
|
||||
if check == nil {
|
||||
args = p.defaultArgs()
|
||||
_, err := rand.Read(args.salt)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
args.hash = p.keyFn([]byte(pass), args.salt, args.time, args.memory, args.threads, args.keyLen)
|
||||
args.hash = p.keyFn(pass, args.salt, args.time, args.memory, args.threads, args.keyLen)
|
||||
} else {
|
||||
args, err = p.parseArgs(check)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
hash := p.keyFn([]byte(pass), args.salt, args.time, args.memory, args.threads, args.keyLen)
|
||||
hash := p.keyFn(pass, args.salt, args.time, args.memory, args.threads, args.keyLen)
|
||||
|
||||
if subtle.ConstantTimeCompare(hash, args.hash) == 0 {
|
||||
return "", passwd.ErrNoMatch
|
||||
return nil, passwd.ErrNoMatch
|
||||
}
|
||||
}
|
||||
|
||||
return args.String(), nil
|
||||
return args.Bytes(), nil
|
||||
}
|
||||
func (p *argon) ApplyPasswd(passwd *passwd.Passwd) {
|
||||
passwd.Register(p.name, p)
|
||||
}
|
||||
func (s *argon) IsPreferred(hash string) bool {
|
||||
func (s *argon) IsPreferred(hash []byte) bool {
|
||||
args, err := s.parseArgs(hash)
|
||||
if err != nil {
|
||||
return false
|
||||
@@ -142,29 +142,33 @@ func (p *argon) defaultArgs() *pwArgs {
|
||||
salt: make([]byte, p.saltLen),
|
||||
}
|
||||
}
|
||||
func (p *argon) parseArgs(hash string) (*pwArgs, error) {
|
||||
pfx := "$" + p.name + "$"
|
||||
func (p *argon) parseArgs(hash []byte) (*pwArgs, error) {
|
||||
pfx := []byte("$" + p.name + "$")
|
||||
|
||||
if !strings.HasPrefix(hash, pfx) {
|
||||
if !bytes.HasPrefix(hash, pfx) {
|
||||
return nil, fmt.Errorf("%w: missing prefix", passwd.ErrBadHash)
|
||||
}
|
||||
hash = strings.TrimPrefix(hash, pfx)
|
||||
args, hash, ok := strings.Cut(hash, "$")
|
||||
hash = bytes.TrimPrefix(hash, pfx)
|
||||
args, hash, ok := bytes.Cut(hash, []byte("$"))
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%w: missing args", passwd.ErrBadHash)
|
||||
}
|
||||
salt, hash, ok := strings.Cut(hash, "$")
|
||||
salt, hash, ok := bytes.Cut(hash, []byte("$"))
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%w: missing salt", passwd.ErrBadHash)
|
||||
}
|
||||
|
||||
var err error
|
||||
pass := p.defaultArgs()
|
||||
pass.salt, err = base64.RawStdEncoding.DecodeString(salt)
|
||||
|
||||
pass.salt = make([]byte, base64.RawStdEncoding.DecodedLen(len(salt)))
|
||||
_, err = base64.RawStdEncoding.Decode(pass.salt, salt)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: corrupt salt part", passwd.ErrBadHash)
|
||||
}
|
||||
pass.hash, err = base64.RawStdEncoding.DecodeString(hash)
|
||||
|
||||
pass.hash = make([]byte, base64.RawStdEncoding.DecodedLen(len(hash)))
|
||||
_, err = base64.RawStdEncoding.Decode(pass.hash, hash)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: corrupt hash part", passwd.ErrBadHash)
|
||||
}
|
||||
@@ -172,23 +176,23 @@ func (p *argon) parseArgs(hash string) (*pwArgs, error) {
|
||||
pass.name = p.name
|
||||
pass.keyLen = uint32(len(pass.hash))
|
||||
|
||||
for _, part := range strings.Split(args, ",") {
|
||||
if k, v, ok := strings.Cut(part, "="); ok {
|
||||
switch k {
|
||||
for _, part := range bytes.Split(args, []byte(",")) {
|
||||
if k, v, ok := bytes.Cut(part, []byte("=")); ok {
|
||||
switch string(k) {
|
||||
case "v":
|
||||
if i, err := strconv.ParseUint(v, 10, 8); err == nil {
|
||||
if i, err := strconv.ParseUint(string(v), 10, 8); err == nil {
|
||||
pass.version = uint8(i)
|
||||
}
|
||||
case "m":
|
||||
if i, err := strconv.ParseUint(v, 10, 32); err == nil {
|
||||
if i, err := strconv.ParseUint(string(v), 10, 32); err == nil {
|
||||
pass.memory = uint32(i)
|
||||
}
|
||||
case "t":
|
||||
if i, err := strconv.ParseUint(v, 10, 32); err == nil {
|
||||
if i, err := strconv.ParseUint(string(v), 10, 32); err == nil {
|
||||
pass.time = uint32(i)
|
||||
}
|
||||
case "p":
|
||||
if i, err := strconv.ParseUint(v, 10, 8); err == nil {
|
||||
if i, err := strconv.ParseUint(string(v), 10, 8); err == nil {
|
||||
pass.threads = uint8(i)
|
||||
}
|
||||
}
|
||||
@@ -209,9 +213,19 @@ type pwArgs struct {
|
||||
hash []byte
|
||||
}
|
||||
|
||||
func (p *pwArgs) String() string {
|
||||
salt := base64.RawStdEncoding.EncodeToString(p.salt)
|
||||
hash := base64.RawStdEncoding.EncodeToString(p.hash)
|
||||
func (p *pwArgs) Bytes() []byte {
|
||||
var b bytes.Buffer
|
||||
|
||||
return fmt.Sprintf("$%s$v=%d,m=%d,t=%d,p=%d$%s$%s", p.name, p.version, p.memory, p.time, p.threads, salt, hash)
|
||||
fmt.Fprintf(&b, "$%s$v=%d,m=%d,t=%d,p=%d$", p.name, p.version, p.memory, p.time, p.threads)
|
||||
|
||||
salt := make([]byte, base64.RawURLEncoding.EncodedLen(len(p.salt)))
|
||||
base64.RawStdEncoding.Encode(salt, p.salt)
|
||||
b.Write(salt)
|
||||
|
||||
hash := make([]byte, base64.RawURLEncoding.EncodedLen(len(p.hash)))
|
||||
base64.RawStdEncoding.Encode(hash, p.hash)
|
||||
b.WriteRune('$')
|
||||
b.Write(hash)
|
||||
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
|
||||
func TestPasswdHash(t *testing.T) {
|
||||
type testCase struct {
|
||||
pass, hash string
|
||||
pass, hash []byte
|
||||
}
|
||||
|
||||
tests := []testCase{}
|
||||
@@ -22,9 +22,9 @@ func TestPasswdHash(t *testing.T) {
|
||||
is := is.New(t)
|
||||
// Generate additional test cases for each algo.
|
||||
for _, algo := range algos {
|
||||
hash, err := algo.Passwd("passwd", "")
|
||||
hash, err := algo.Passwd([]byte("passwd"), nil)
|
||||
is.NoErr(err)
|
||||
tests = append(tests, testCase{"passwd", hash})
|
||||
tests = append(tests, testCase{[]byte("passwd"), hash})
|
||||
}
|
||||
|
||||
pass := passwd.New(algos...)
|
||||
@@ -45,12 +45,12 @@ func TestPasswdIsPreferred(t *testing.T) {
|
||||
|
||||
pass := passwd.New(argon2.Argon2i, &unix.MD5{})
|
||||
|
||||
ok := pass.IsPreferred("$argon2i$v=19,m=32768,t=3,p=4$LdaB2Z4EI4lwpxTc78QUFw$VhlPSK0tdF226QCLC24IIrmQcMBmg47Ik9h/Yq6htFI")
|
||||
ok := pass.IsPreferred([]byte("$argon2i$v=19,m=32768,t=3,p=4$LdaB2Z4EI4lwpxTc78QUFw$VhlPSK0tdF226QCLC24IIrmQcMBmg47Ik9h/Yq6htFI"))
|
||||
is.True(ok)
|
||||
|
||||
ok = pass.IsPreferred("$argon2i$v=19,m=1024,t=2,p=4$LdaB2Z4EI4lwpxTc78QUFw$VhlPSK0tdF226QCLC24IIrmQcMBmg47Ik9h/Yq6htFI")
|
||||
ok = pass.IsPreferred([]byte("$argon2i$v=19,m=1024,t=2,p=4$LdaB2Z4EI4lwpxTc78QUFw$VhlPSK0tdF226QCLC24IIrmQcMBmg47Ik9h/Yq6htFI"))
|
||||
is.True(!ok)
|
||||
|
||||
ok = pass.IsPreferred("$1$76a2173be6393254e72ffa4d6df1030a")
|
||||
ok = pass.IsPreferred([]byte("$1$76a2173be6393254e72ffa4d6df1030a"))
|
||||
is.True(!ok)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user