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: 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 }