Moonshark/runner/password.go
2025-05-10 13:02:09 -05:00

99 lines
2.1 KiB
Go

package runner
import (
"fmt"
luajit "git.sharkk.net/Sky/LuaJIT-to-Go"
"github.com/alexedwards/argon2id"
)
// RegisterPasswordFunctions registers password-related functions in the Lua state
func RegisterPasswordFunctions(state *luajit.State) error {
if err := state.RegisterGoFunction("__password_hash", passwordHash); err != nil {
return err
}
if err := state.RegisterGoFunction("__password_verify", passwordVerify); err != nil {
return err
}
return nil
}
// passwordHash implements the Argon2id password hashing using alexedwards/argon2id
func passwordHash(state *luajit.State) int {
if !state.IsString(1) {
state.PushString("password_hash error: expected string password")
return 1
}
password := state.ToString(1)
params := &argon2id.Params{
Memory: 128 * 1024,
Iterations: 4,
Parallelism: 4,
SaltLength: 16,
KeyLength: 32,
}
if state.IsTable(2) {
state.GetField(2, "memory")
if state.IsNumber(-1) {
params.Memory = max(uint32(state.ToNumber(-1)), 8*1024)
}
state.Pop(1)
state.GetField(2, "iterations")
if state.IsNumber(-1) {
params.Iterations = max(uint32(state.ToNumber(-1)), 1)
}
state.Pop(1)
state.GetField(2, "parallelism")
if state.IsNumber(-1) {
params.Parallelism = max(uint8(state.ToNumber(-1)), 1)
}
state.Pop(1)
state.GetField(2, "salt_length")
if state.IsNumber(-1) {
params.SaltLength = max(uint32(state.ToNumber(-1)), 8)
}
state.Pop(1)
state.GetField(2, "key_length")
if state.IsNumber(-1) {
params.KeyLength = max(uint32(state.ToNumber(-1)), 16)
}
state.Pop(1)
}
hash, err := argon2id.CreateHash(password, params)
if err != nil {
state.PushString(fmt.Sprintf("password_hash error: %v", err))
return 1
}
state.PushString(hash)
return 1
}
// passwordVerify verifies a password against a hash
func passwordVerify(state *luajit.State) int {
if !state.IsString(1) || !state.IsString(2) {
state.PushBoolean(false)
return 1
}
password := state.ToString(1)
hash := state.ToString(2)
match, err := argon2id.ComparePasswordAndHash(password, hash)
if err != nil {
state.PushBoolean(false)
return 1
}
state.PushBoolean(match)
return 1
}