// Copyright 2024 Patial Tech (Ankit Patial). // // This file is part of code.patial.tech/go/appcore, which is MIT licensed. // See http://opensource.org/licenses/MIT package crypto import ( "bytes" "encoding/base64" "golang.org/x/crypto/argon2" ) const ( a2KeyMem = 19456 // 1024*19 a2KeyLen = 32 ) func argon2Hash(pwd, salt []byte) []byte { // https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html // m=19456 (19 MiB), t=2, p=1 return argon2.IDKey(pwd, salt, 2, a2KeyMem, 1, a2KeyLen) } // PasswordHash using Argon2id // // https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#argon2id func PasswordHash(pwd string) (hash, salt string, err error) { var sl []byte sl, err = RandomBytes(a2KeyLen) if err != nil { return } // Generate hash h := argon2Hash([]byte(pwd), sl) hash = base64.StdEncoding.EncodeToString(h) salt = base64.StdEncoding.EncodeToString(sl) return } func ComparePasswordHash(pwd, hash, salt string) (bool, error) { var h, s []byte var err error if h, err = base64.StdEncoding.DecodeString(hash); err != nil { return false, err } if s, err = base64.StdEncoding.DecodeString(salt); err != nil { return false, err } // Generate hash for comparison. ph := argon2Hash([]byte(pwd), s) // Compare the generated hash with the stored hash. // If they don't match return error. return bytes.Equal(h, ph), nil }