first commit, i i have no idea what i have done

This commit is contained in:
tdv
2025-08-31 22:42:08 +03:00
commit c5632f6a37
177 changed files with 9173 additions and 0 deletions

View File

@@ -0,0 +1,102 @@
package crypto
import (
"crypto/rand"
"crypto/subtle"
"encoding/base64"
"errors"
"fmt"
"strconv"
"strings"
"golang.org/x/crypto/argon2"
)
type Argon2Params struct {
Memory uint32 // KiB
Time uint32
Threads uint8
SaltLen uint32
KeyLen uint32
}
var DefaultArgon2 = Argon2Params{
Memory: 7168, // 7 MiB
Time: 5,
Threads: 1,
SaltLen: 16,
KeyLen: 32,
}
// Hash returns PHC string: $argon2id$v=19$m=...,t=...,p=...$<salt>$<hash>
func Hash(password string, p Argon2Params) (string, error) {
salt := make([]byte, p.SaltLen)
if _, err := rand.Read(salt); err != nil {
return "", err
}
sum := argon2.IDKey([]byte(password), salt, p.Time, p.Memory, p.Threads, p.KeyLen)
return fmt.Sprintf("$argon2id$v=19$m=%d,t=%d,p=%d$%s$%s",
p.Memory, p.Time, p.Threads,
base64.RawStdEncoding.EncodeToString(salt),
base64.RawStdEncoding.EncodeToString(sum),
), nil
}
func Verify(password, phc string) (bool, error) {
parts := strings.Split(phc, "$")
// Expect: ["", "argon2id", "v=19", "m=...,t=...,p=...", "<saltB64>", "<hashB64>"]
if len(parts) != 6 || parts[1] != "argon2id" || parts[2] != "v=19" {
return false, errors.New("invalid PHC header")
}
// parse params
var mem, iters uint64
var threads uint64
for _, kv := range strings.Split(parts[3], ",") {
if strings.HasPrefix(kv, "m=") {
v := strings.TrimPrefix(kv, "m=")
x, err := strconv.ParseUint(v, 10, 32)
if err != nil {
return false, fmt.Errorf("mem: %w", err)
}
mem = x
} else if strings.HasPrefix(kv, "t=") {
v := strings.TrimPrefix(kv, "t=")
x, err := strconv.ParseUint(v, 10, 32)
if err != nil {
return false, fmt.Errorf("time: %w", err)
}
iters = x
} else if strings.HasPrefix(kv, "p=") {
v := strings.TrimPrefix(kv, "p=")
x, err := strconv.ParseUint(v, 10, 8)
if err != nil {
return false, fmt.Errorf("threads: %w", err)
}
threads = x
}
}
if mem == 0 || iters == 0 || threads == 0 {
return false, errors.New("invalid PHC params")
}
salt, err := b64DecodeFlex(parts[4])
if err != nil {
return false, fmt.Errorf("salt decode: %w", err)
}
want, err := b64DecodeFlex(parts[5])
if err != nil {
return false, fmt.Errorf("hash decode: %w", err)
}
got := argon2.IDKey([]byte(password), salt, uint32(iters), uint32(mem), uint8(threads), uint32(len(want)))
return subtle.ConstantTimeCompare(got, want) == 1, nil
}
func b64DecodeFlex(s string) ([]byte, error) {
if b, err := base64.RawStdEncoding.DecodeString(s); err == nil {
return b, nil
}
return base64.StdEncoding.DecodeString(s) // padded fallback
}