// Copyright 2024 Patial Tech. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package crypto import ( "bytes" "crypto/md5" "crypto/rand" "encoding/base64" "encoding/hex" "log/slog" "math/big" "gitserver.in/patialtech/rano/util/logger" "golang.org/x/crypto/argon2" ) func MD5(b []byte) string { hash := md5.Sum(b) return hex.EncodeToString(hash[:]) } func MD5Int(b []byte) uint64 { n := new(big.Int) n.SetString(MD5(b), 16) return n.Uint64() } // Password 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 = randomSecret(32) if err != nil { return } // Generate hash h := argon2.IDKey([]byte(pwd), sl, 3, 12288, 1, 32) hash = base64.StdEncoding.EncodeToString(h) salt = base64.StdEncoding.EncodeToString(sl) return } // ComparePassword func ComparePasswordHash(pwd, hash, salt string) bool { var h, s []byte var err error if h, err = base64.StdEncoding.DecodeString(hash); err != nil { logger.Error(err, slog.String("ref", "util/crypto.ComparePasswordHash decode hash")) } if s, err = base64.StdEncoding.DecodeString(salt); err != nil { logger.Error(err, slog.String("ref", "util/crypto.ComparePasswordHash decode salt")) } // Generate hash for comparison. ph := argon2.IDKey([]byte(pwd), s, 3, 12288, 1, 32) // Compare the generated hash with the stored hash. // If they don't match return error. return bytes.Equal(h, ph) } func randomSecret(length uint32) ([]byte, error) { secret := make([]byte, length) _, err := rand.Read(secret) if err != nil { return nil, err } return secret, nil }