diff --git a/sys/modules/opus/security.lua b/sys/modules/opus/security.lua index 4fb6f8d..b99500f 100644 --- a/sys/modules/opus/security.lua +++ b/sys/modules/opus/security.lua @@ -1,10 +1,38 @@ local Config = require('opus.config') +local SHA = require('opus.crypto.sha2') +local Util = require('opus.util') + +local PBKDF2_ITERATIONS = 100 local Security = { } +local function generateSalt() + local salt = { } + for _ = 1, 16 do + salt[#salt + 1] = math.random(0, 0xFF) + end + return setmetatable(salt, Util.byteArrayMT):toHex() +end + function Security.verifyPassword(password) - local current = Security.getPassword() - return current and password == current + local stored = Security.getPassword() + if not stored then + return false + end + + -- New format: { hash = hex, salt = hex, iter = N } + if type(stored) == 'table' and stored.hash and stored.salt then + local iter = stored.iter or PBKDF2_ITERATIONS + local derived = SHA.pbkdf2(password, Util.hexToByteArray(stored.salt), iter) + return derived:toHex() == stored.hash + end + + -- Legacy format: plain SHA-256 hex string + if type(stored) == 'string' then + return SHA.compute(password) == stored + end + + return false end function Security.hasPassword() @@ -28,8 +56,15 @@ function Security.getIdentifier() end function Security.updatePassword(password) + local salt = generateSalt() + local derived = SHA.pbkdf2(password, Util.hexToByteArray(salt), PBKDF2_ITERATIONS) + local config = Config.load('os') - config.password = password + config.password = { + hash = derived:toHex(), + salt = salt, + iter = PBKDF2_ITERATIONS, + } Config.update('os', config) end