From aabd216bb2c3ead5b7e944a0cd7680b663522931 Mon Sep 17 00:00:00 2001 From: xiaoqidun Date: Mon, 6 Jan 2020 14:16:08 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0idkey=E6=BA=90=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 5 +++ go.sum | 8 ++++ idkey.go | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 128 insertions(+) create mode 100644 go.mod create mode 100644 go.sum create mode 100644 idkey.go diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..84aeee9 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module idkey + +go 1.13 + +require golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..452e5b0 --- /dev/null +++ b/go.sum @@ -0,0 +1,8 @@ +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876 h1:sKJQZMuxjOAR/Uo2LBfU90onWEf1dF4C+0hPJCc9Mpc= +golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/idkey.go b/idkey.go new file mode 100644 index 0000000..6cd800e --- /dev/null +++ b/idkey.go @@ -0,0 +1,115 @@ +package main + +import ( + "bytes" + "crypto/rand" + "encoding/base64" + "errors" + "fmt" + "golang.org/x/crypto/argon2" + "strings" +) + +type Data struct { + Hash []byte // 密码密文 + Salt []byte // 加密盐值 + Time uint32 // 时间参数 + Memory uint32 // 内存参数 + Threads uint8 // 线程参数 + KeyLen uint32 // 密文长度 +} + +func Encode(password string) string { + salt := generateSalt(16) + data := &Data{ + Hash: nil, + Salt: salt, + Time: 1, + Memory: 64 * 1024, + Threads: 4, + KeyLen: 32, + } + hash := argon2.IDKey( + []byte(password), + data.Salt, + data.Time, + data.Memory, + data.Threads, + data.KeyLen, + ) + return fmt.Sprintf( + "$argon2id$v=%d$m=%d,t=%d,p=%d$%s$%s", + argon2.Version, + data.Memory, + data.Time, + data.Threads, + base64.RawStdEncoding.EncodeToString(salt), + base64.RawStdEncoding.EncodeToString(hash), + ) +} + +func Decode(passwordHash string) (data *Data, err error) { + data = &Data{} + params := strings.Split(passwordHash, "$") + if len(params) != 6 { + err = errors.New("input error") + return + } + var version int + _, err = fmt.Sscanf( + params[2], + "v=%d", + &version, + ) + if err != nil { + return + } + if version != argon2.Version { + err = errors.New("not support") + return + } + _, err = fmt.Sscanf( + params[3], + "m=%d,t=%d,p=%d", + &data.Memory, + &data.Time, + &data.Threads, + ) + if err != nil { + return + } + salt, err := base64.RawStdEncoding.DecodeString(params[4]) + if err != nil { + return + } + data.Salt = salt + hash, err := base64.RawStdEncoding.DecodeString(params[5]) + if err != nil { + return + } + data.Hash = hash + data.KeyLen = uint32(len(hash)) + return +} + +func Verify(password, passwordHash string) bool { + data, err := Decode(passwordHash) + if err != nil { + return false + } + hash := argon2.IDKey( + []byte(password), + data.Salt, + data.Time, + data.Memory, + data.Threads, + data.KeyLen, + ) + return bytes.Equal(hash, data.Hash) +} + +func generateSalt(l int) (b []byte) { + b = make([]byte, l) + _, _ = rand.Read(b) + return +}