Livt packages
Livt.Crypto
Version 1.0.5
Fixed-size cryptographic components for Livt, including AES, ChaCha20, SHA, MACs, and key derivation.
Published files (69)
src/random/Aes256CtrDrbg.lvt
namespace Livt.Crypto.Random
using Livt.Crypto.Aes
// CTR_DRBG instantiated with AES-256, no derivation function, no prediction resistance.
// Implements NIST SP 800-90A §10.2.
// seedlen = keylen + blocklen = 32 + 16 = 48 bytes.
//
// Usage:
// 1. Instantiate(entropy[48]) — seed the DRBG (key=0, V=0, then CTR_DRBG_Update(entropy)).
// 2. GenerateBlock() — produce one 16-byte output block; call repeatedly for more output.
// 3. FinalizeGenerate() — call after all blocks for one Generate request are done;
// runs CTR_DRBG_Update(0^48) to refresh state.
// Reseed(entropy[48]) — refresh internal state from new entropy at any time.
component Aes256CtrDrbg
{
public const SEED_SIZE: int = 48
public const KEY_SIZE: int = 32
public const BLOCK_SIZE: int = 16
enc: EncryptBlock256
// V counter: 128-bit big-endian integer. Stored as byte-wide int values
// so carry propagation can use simple integer arithmetic.
v: int[16]
// Output buffer for the most recent GenerateBlock() call.
outBlk: byte[16]
new()
{
this.enc = new EncryptBlock256()
}
// -----------------------------------------------------------------------
// Public API
// -----------------------------------------------------------------------
// Instantiate: set key=0^32, V=0^16, then run CTR_DRBG_Update(entropy).
// entropy must be exactly 48 bytes (SEED_SIZE).
public fn Instantiate(entropy: byte[48])
{
var zk: byte[32] = [
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
this.enc.SetKey(zk)
for (var vi = 0; vi < 16; vi++)
{
this.v[vi] = 0
}
this.Update(entropy)
}
// GenerateBlock: increment V, encrypt V under the current key, store result in outBlk.
// Call FinalizeGenerate() after all blocks for one Generate request are done.
public fn GenerateBlock()
{
this.IncrV()
var cb: byte[16]
for (var ci = 0; ci < 16; ci++)
{
cb[ci] = this.v[ci] as byte
}
this.enc.LoadBlock(cb)
this.enc.EncryptBlock()
var result: byte[16] = this.enc.GetBlock()
for (var i = 0; i < 16; i++)
{
this.outBlk[i] = result[i]
}
}
// FinalizeGenerate: run CTR_DRBG_Update(0^48) after all output blocks are generated.
// Must be called once per logical Generate request.
public fn FinalizeGenerate()
{
var zeros: byte[48] = [
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
this.Update(zeros)
}
// Reseed: run CTR_DRBG_Update(entropy) to refresh the internal state.
// entropy must be exactly 48 bytes (SEED_SIZE).
public fn Reseed(entropy: byte[48])
{
this.Update(entropy)
}
public fn GetBlock() byte[16]
{
return this.outBlk
}
public fn GetByte(idx: int) byte
{
return this.outBlk[idx]
}
public fn ClearKey()
{
this.enc.ClearKey()
}
// -----------------------------------------------------------------------
// Private helpers
// -----------------------------------------------------------------------
// CTR_DRBG_Update per NIST SP 800-90A §10.2.1.2 (no DF variant).
// Generates 3 AES blocks by encrypting V+1, V+2, V+3 with the current key,
// XORs the 48 bytes with data, then sets:
// new key = XOR result bytes 0..31
// new V = XOR result bytes 32..47
fn Update(data: byte[48])
{
// Block T0: encrypt V+1
this.IncrV()
var cb0: byte[16]
for (var c0i = 0; c0i < 16; c0i++)
{
cb0[c0i] = this.v[c0i] as byte
}
this.enc.LoadBlock(cb0)
this.enc.EncryptBlock()
var t0: byte[16] = this.enc.GetBlock()
// Block T1: encrypt V+2
this.IncrV()
var cb1: byte[16]
for (var c1i = 0; c1i < 16; c1i++)
{
cb1[c1i] = this.v[c1i] as byte
}
this.enc.LoadBlock(cb1)
this.enc.EncryptBlock()
var t1: byte[16] = this.enc.GetBlock()
// Block T2: encrypt V+3
this.IncrV()
var cb2: byte[16]
for (var c2i = 0; c2i < 16; c2i++)
{
cb2[c2i] = this.v[c2i] as byte
}
this.enc.LoadBlock(cb2)
this.enc.EncryptBlock()
var t2: byte[16] = this.enc.GetBlock()
// Read all 48 data bytes into locals.
var d0: byte = data[0]; var d1: byte = data[1]; var d2: byte = data[2]; var d3: byte = data[3]
var d4: byte = data[4]; var d5: byte = data[5]; var d6: byte = data[6]; var d7: byte = data[7]
var d8: byte = data[8]; var d9: byte = data[9]; var d10: byte = data[10]; var d11: byte = data[11]
var d12: byte = data[12]; var d13: byte = data[13]; var d14: byte = data[14]; var d15: byte = data[15]
var d16: byte = data[16]; var d17: byte = data[17]; var d18: byte = data[18]; var d19: byte = data[19]
var d20: byte = data[20]; var d21: byte = data[21]; var d22: byte = data[22]; var d23: byte = data[23]
var d24: byte = data[24]; var d25: byte = data[25]; var d26: byte = data[26]; var d27: byte = data[27]
var d28: byte = data[28]; var d29: byte = data[29]; var d30: byte = data[30]; var d31: byte = data[31]
var d32: byte = data[32]; var d33: byte = data[33]; var d34: byte = data[34]; var d35: byte = data[35]
var d36: byte = data[36]; var d37: byte = data[37]; var d38: byte = data[38]; var d39: byte = data[39]
var d40: byte = data[40]; var d41: byte = data[41]; var d42: byte = data[42]; var d43: byte = data[43]
var d44: byte = data[44]; var d45: byte = data[45]; var d46: byte = data[46]; var d47: byte = data[47]
// Read t0 bytes into locals.
var t0b0: byte = t0[0]; var t0b1: byte = t0[1]; var t0b2: byte = t0[2]; var t0b3: byte = t0[3]
var t0b4: byte = t0[4]; var t0b5: byte = t0[5]; var t0b6: byte = t0[6]; var t0b7: byte = t0[7]
var t0b8: byte = t0[8]; var t0b9: byte = t0[9]; var t0b10: byte = t0[10]; var t0b11: byte = t0[11]
var t0b12: byte = t0[12]; var t0b13: byte = t0[13]; var t0b14: byte = t0[14]; var t0b15: byte = t0[15]
// Read t1 bytes into locals.
var t1b0: byte = t1[0]; var t1b1: byte = t1[1]; var t1b2: byte = t1[2]; var t1b3: byte = t1[3]
var t1b4: byte = t1[4]; var t1b5: byte = t1[5]; var t1b6: byte = t1[6]; var t1b7: byte = t1[7]
var t1b8: byte = t1[8]; var t1b9: byte = t1[9]; var t1b10: byte = t1[10]; var t1b11: byte = t1[11]
var t1b12: byte = t1[12]; var t1b13: byte = t1[13]; var t1b14: byte = t1[14]; var t1b15: byte = t1[15]
// Read t2 bytes into locals.
var t2b0: byte = t2[0]; var t2b1: byte = t2[1]; var t2b2: byte = t2[2]; var t2b3: byte = t2[3]
var t2b4: byte = t2[4]; var t2b5: byte = t2[5]; var t2b6: byte = t2[6]; var t2b7: byte = t2[7]
var t2b8: byte = t2[8]; var t2b9: byte = t2[9]; var t2b10: byte = t2[10]; var t2b11: byte = t2[11]
var t2b12: byte = t2[12]; var t2b13: byte = t2[13]; var t2b14: byte = t2[14]; var t2b15: byte = t2[15]
// New key = (t0 || t1) XOR data[0..31]
var nk0: byte = d0 ^ t0b0
var nk1: byte = d1 ^ t0b1
var nk2: byte = d2 ^ t0b2
var nk3: byte = d3 ^ t0b3
var nk4: byte = d4 ^ t0b4
var nk5: byte = d5 ^ t0b5
var nk6: byte = d6 ^ t0b6
var nk7: byte = d7 ^ t0b7
var nk8: byte = d8 ^ t0b8
var nk9: byte = d9 ^ t0b9
var nk10: byte = d10 ^ t0b10
var nk11: byte = d11 ^ t0b11
var nk12: byte = d12 ^ t0b12
var nk13: byte = d13 ^ t0b13
var nk14: byte = d14 ^ t0b14
var nk15: byte = d15 ^ t0b15
var nk16: byte = d16 ^ t1b0
var nk17: byte = d17 ^ t1b1
var nk18: byte = d18 ^ t1b2
var nk19: byte = d19 ^ t1b3
var nk20: byte = d20 ^ t1b4
var nk21: byte = d21 ^ t1b5
var nk22: byte = d22 ^ t1b6
var nk23: byte = d23 ^ t1b7
var nk24: byte = d24 ^ t1b8
var nk25: byte = d25 ^ t1b9
var nk26: byte = d26 ^ t1b10
var nk27: byte = d27 ^ t1b11
var nk28: byte = d28 ^ t1b12
var nk29: byte = d29 ^ t1b13
var nk30: byte = d30 ^ t1b14
var nk31: byte = d31 ^ t1b15
// New V = t2 XOR data[32..47]
var nv0: byte = d32 ^ t2b0
var nv1: byte = d33 ^ t2b1
var nv2: byte = d34 ^ t2b2
var nv3: byte = d35 ^ t2b3
var nv4: byte = d36 ^ t2b4
var nv5: byte = d37 ^ t2b5
var nv6: byte = d38 ^ t2b6
var nv7: byte = d39 ^ t2b7
var nv8: byte = d40 ^ t2b8
var nv9: byte = d41 ^ t2b9
var nv10: byte = d42 ^ t2b10
var nv11: byte = d43 ^ t2b11
var nv12: byte = d44 ^ t2b12
var nv13: byte = d45 ^ t2b13
var nv14: byte = d46 ^ t2b14
var nv15: byte = d47 ^ t2b15
// Update AES key schedule with the new key.
var newKey: byte[32]
newKey[0] = nk0; newKey[1] = nk1; newKey[2] = nk2; newKey[3] = nk3
newKey[4] = nk4; newKey[5] = nk5; newKey[6] = nk6; newKey[7] = nk7
newKey[8] = nk8; newKey[9] = nk9; newKey[10] = nk10; newKey[11] = nk11
newKey[12] = nk12; newKey[13] = nk13; newKey[14] = nk14; newKey[15] = nk15
newKey[16] = nk16; newKey[17] = nk17; newKey[18] = nk18; newKey[19] = nk19
newKey[20] = nk20; newKey[21] = nk21; newKey[22] = nk22; newKey[23] = nk23
newKey[24] = nk24; newKey[25] = nk25; newKey[26] = nk26; newKey[27] = nk27
newKey[28] = nk28; newKey[29] = nk29; newKey[30] = nk30; newKey[31] = nk31
this.enc.SetKey(newKey)
this.v[0] = nv0 as int
this.v[1] = nv1 as int
this.v[2] = nv2 as int
this.v[3] = nv3 as int
this.v[4] = nv4 as int
this.v[5] = nv5 as int
this.v[6] = nv6 as int
this.v[7] = nv7 as int
this.v[8] = nv8 as int
this.v[9] = nv9 as int
this.v[10] = nv10 as int
this.v[11] = nv11 as int
this.v[12] = nv12 as int
this.v[13] = nv13 as int
this.v[14] = nv14 as int
this.v[15] = nv15 as int
}
// Increment the 128-bit big-endian V counter.
// Carry propagates from byte 15 (LSB in big-endian) toward byte 0 (MSB).
fn IncrV()
{
var c0: int = this.v[0]
var c1: int = this.v[1]
var c2: int = this.v[2]
var c3: int = this.v[3]
var c4: int = this.v[4]
var c5: int = this.v[5]
var c6: int = this.v[6]
var c7: int = this.v[7]
var c8: int = this.v[8]
var c9: int = this.v[9]
var c10: int = this.v[10]
var c11: int = this.v[11]
var c12: int = this.v[12]
var c13: int = this.v[13]
var c14: int = this.v[14]
var c15: int = this.v[15]
c15 = c15 + 1
if (c15 == 256)
{
c15 = 0
c14 = c14 + 1
if (c14 == 256)
{
c14 = 0
c13 = c13 + 1
if (c13 == 256)
{
c13 = 0
c12 = c12 + 1
if (c12 == 256)
{
c12 = 0
c11 = c11 + 1
if (c11 == 256)
{
c11 = 0
c10 = c10 + 1
if (c10 == 256)
{
c10 = 0
c9 = c9 + 1
if (c9 == 256)
{
c9 = 0
c8 = c8 + 1
if (c8 == 256)
{
c8 = 0
c7 = c7 + 1
if (c7 == 256)
{
c7 = 0
c6 = c6 + 1
if (c6 == 256)
{
c6 = 0
c5 = c5 + 1
if (c5 == 256)
{
c5 = 0
c4 = c4 + 1
if (c4 == 256)
{
c4 = 0
c3 = c3 + 1
if (c3 == 256)
{
c3 = 0
c2 = c2 + 1
if (c2 == 256)
{
c2 = 0
c1 = c1 + 1
if (c1 == 256)
{
c1 = 0
c0 = c0 + 1
if (c0 == 256)
{
c0 = 0
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
}
this.v[0] = c0
this.v[1] = c1
this.v[2] = c2
this.v[3] = c3
this.v[4] = c4
this.v[5] = c5
this.v[6] = c6
this.v[7] = c7
this.v[8] = c8
this.v[9] = c9
this.v[10] = c10
this.v[11] = c11
this.v[12] = c12
this.v[13] = c13
this.v[14] = c14
this.v[15] = c15
}
}