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 }