Moonshark/core/runner/password.go

114 lines
2.5 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: 64 * 1024,
Iterations: 3,
Parallelism: 4,
SaltLength: 16,
KeyLength: 32,
}
if state.IsTable(2) {
state.GetField(2, "memory")
if state.IsNumber(-1) {
params.Memory = uint32(state.ToNumber(-1))
if params.Memory < 8*1024 {
params.Memory = 8 * 1024 // Minimum 8MB
}
}
state.Pop(1)
state.GetField(2, "iterations")
if state.IsNumber(-1) {
params.Iterations = uint32(state.ToNumber(-1))
if params.Iterations < 1 {
params.Iterations = 1 // Minimum 1 iteration
}
}
state.Pop(1)
state.GetField(2, "parallelism")
if state.IsNumber(-1) {
params.Parallelism = uint8(state.ToNumber(-1))
if params.Parallelism < 1 {
params.Parallelism = 1 // Minimum 1 thread
}
}
state.Pop(1)
state.GetField(2, "salt_length")
if state.IsNumber(-1) {
params.SaltLength = uint32(state.ToNumber(-1))
if params.SaltLength < 8 {
params.SaltLength = 8 // Minimum 8 bytes
}
}
state.Pop(1)
state.GetField(2, "key_length")
if state.IsNumber(-1) {
params.KeyLength = uint32(state.ToNumber(-1))
if params.KeyLength < 16 {
params.KeyLength = 16 // Minimum 16 bytes
}
}
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
}