Simplify random initialization
The entropy is now provided by the user. They are tasked with finding a high-quality source of entropy to initialize the generator with.
This commit is contained in:
parent
32ba9d8252
commit
6fbbab378a
|
@ -1,14 +1,15 @@
|
|||
local expect = require "cc.expect".expect
|
||||
local blake3 = require "ccryptolib.blake3"
|
||||
local chacha20 = require "ccryptolib.chacha20"
|
||||
local packing = require "ccryptolib.internal.packing"
|
||||
local util = require "ccryptolib.internal.util"
|
||||
|
||||
local u1x4, fmt1x4 = packing.compileUnpack("<I4")
|
||||
local lassert = util.lassert
|
||||
|
||||
-- Initialize from local context.
|
||||
-- Extract local context.
|
||||
local ctx = {
|
||||
"ccryptolib 2022-03-05T08:50:36Z random.lua initialization context",
|
||||
"ccryptolib 2023-04-11T19:43Z random.lua initialization context",
|
||||
os.epoch("utc"),
|
||||
os.epoch("ingame"),
|
||||
math.random(0, 2 ^ 24 - 1),
|
||||
math.random(0, 2 ^ 24 - 1),
|
||||
tostring({}),
|
||||
|
@ -16,72 +17,36 @@ local ctx = {
|
|||
}
|
||||
|
||||
local state = blake3.digest(table.concat(ctx, "|"))
|
||||
local accumulator = {}
|
||||
local accumulatorLen = 0
|
||||
|
||||
--- Adds data to the accumulator without context.
|
||||
--
|
||||
-- @tparam string data The input bytes.
|
||||
--
|
||||
local function reseed(data)
|
||||
local acc = accumulator
|
||||
local len = accumulatorLen
|
||||
|
||||
-- Append to the accumulator.
|
||||
acc[#acc + 1] = data
|
||||
len = len + #data
|
||||
|
||||
if len < 64 then
|
||||
accumulatorLen = len
|
||||
return
|
||||
end
|
||||
|
||||
-- Concatenate.
|
||||
local cat = table.concat(acc)
|
||||
|
||||
-- Align by 64-byte block.
|
||||
local rlen = len % 64
|
||||
local blen = len - rlen
|
||||
|
||||
-- Digest.
|
||||
state = blake3.digestKeyed(state, cat:sub(1, blen))
|
||||
accumulator = {cat:sub(blen + 1)}
|
||||
accumulatorLen = rlen
|
||||
end
|
||||
|
||||
do -- Load entropy from disk.
|
||||
local file = fs.open("/.random", "rb")
|
||||
if file then
|
||||
reseed(file.read(32) or "")
|
||||
file.close()
|
||||
end
|
||||
end
|
||||
local initialized = false
|
||||
|
||||
local mod = {}
|
||||
|
||||
--- Adds entropy into the generator state.
|
||||
--- Mixes entropy into the generator, and marks it as initialized.
|
||||
--
|
||||
-- @tparam string data The entropy data.
|
||||
-- @tparam string seed The seed data.
|
||||
--
|
||||
function mod.reseed(data)
|
||||
expect(1, data, "string")
|
||||
reseed(data)
|
||||
function mod.init(seed)
|
||||
expect(1, seed, "string")
|
||||
state = blake3.digestKeyed(state, seed)
|
||||
initialized = true
|
||||
end
|
||||
|
||||
--- Adds entropy from sampling system noise.
|
||||
--- Mixes extra entropy into the generator state.
|
||||
--
|
||||
-- @tparam number n The number of iterations to spend extracting entropy.
|
||||
-- @tparam string seed The additional entropy to mix.
|
||||
--
|
||||
function mod.stir(n)
|
||||
expect(1, n, "number")
|
||||
error("TODO") -- TODO
|
||||
function mod.mix(data)
|
||||
state = blake3.digestKeyed(state, data)
|
||||
end
|
||||
|
||||
--- Generates random bytes.
|
||||
--
|
||||
-- @tparam number len The desired output length.
|
||||
-- @throws If the generator hasn't been initialized.
|
||||
--
|
||||
function mod.random(len)
|
||||
expect(1, len, "number")
|
||||
lassert(initialized, "attempt to use an uninitialized random generator", 2)
|
||||
local msg = ("\0"):rep(len + 32)
|
||||
local nonce = ("\0"):rep(12)
|
||||
local out = chacha20.crypt(state, nonce, msg, 8, 0)
|
||||
|
@ -89,26 +54,4 @@ function mod.random(len)
|
|||
return out:sub(33)
|
||||
end
|
||||
|
||||
local random = mod.random
|
||||
|
||||
--- Saves the state to the filesystem.
|
||||
--
|
||||
-- This potentially adds security when starting the generator from boot. The
|
||||
-- saved path is fixed and located at `/.random`.
|
||||
--
|
||||
function mod.save()
|
||||
local file = fs.open("/.random", "wb")
|
||||
file.write(random(32))
|
||||
file.close()
|
||||
end
|
||||
|
||||
-- Add extra entropy.
|
||||
-- mod.stir(error("TODO")) -- TODO
|
||||
|
||||
-- Save.
|
||||
mod.save()
|
||||
|
||||
-- Regenerate the math.random seed.
|
||||
math.randomseed(u1x4(fmt1x4, random(4), 1))
|
||||
|
||||
return mod
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
local util = require "spec.util"
|
||||
local x25519 = require "ccryptolib.x25519"
|
||||
|
||||
require "ccryptolib.random".init("mock initialization")
|
||||
|
||||
describe("x25519.exchange", function()
|
||||
it("passes the section 5.2 test vector #1", function()
|
||||
local x = util.hexcat {
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
local util = require "spec.util"
|
||||
local x25519c = require "ccryptolib.x25519c"
|
||||
|
||||
require "ccryptolib.random".init("mock initialization")
|
||||
|
||||
local function exchange(sk, pk)
|
||||
local sk = x25519c.maskX(sk)
|
||||
sk = x25519c.remask(sk)
|
||||
|
|
Loading…
Reference in a new issue