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/aead/Aes192Gcm.lvt
namespace Livt.Crypto.Aead
using Livt.Crypto.Aes
using Livt.Crypto.Internal
// AES-192 GCM (Galois/Counter Mode) — single-block interface.
// NIST SP 800-38D. IV (nonce) must be exactly 96 bits (12 bytes).
// See Aes256Gcm for full usage notes.
component Aes192Gcm
{
public const KEY_SIZE: int = 24
public const BLOCK_SIZE: int = 16
public const NONCE_SIZE: int = 12
public const TAG_SIZE: int = 16
enc: EncryptBlock192
ghash: Ghash
H: byte[16]
J0: byte[16]
Yi: byte[16]
yi12: int
yi13: int
yi14: int
yi15: int
blk: byte[16]
outBlk: byte[16]
tag: byte[16]
new()
{
this.enc = new EncryptBlock192()
this.ghash = new Ghash()
}
public fn SetKey(key: byte[24])
{
this.enc.SetKey(key)
var zeroBlock: byte[16] = [
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
this.enc.LoadBlock(zeroBlock)
this.enc.EncryptBlock()
var h: byte[16] = this.enc.GetBlock()
state {
this.H[0] = h[0]
this.H[1] = h[1]
this.H[2] = h[2]
this.H[3] = h[3]
this.H[4] = h[4]
this.H[5] = h[5]
this.H[6] = h[6]
this.H[7] = h[7]
this.H[8] = h[8]
this.H[9] = h[9]
this.H[10] = h[10]
this.H[11] = h[11]
this.H[12] = h[12]
this.H[13] = h[13]
this.H[14] = h[14]
this.H[15] = h[15]
}
this.ghash.SetHashKey(h)
}
public fn SetNonce(nonce: byte[12])
{
state {
this.J0[0] = nonce[0]
this.J0[1] = nonce[1]
this.J0[2] = nonce[2]
this.J0[3] = nonce[3]
this.J0[4] = nonce[4]
this.J0[5] = nonce[5]
this.J0[6] = nonce[6]
this.J0[7] = nonce[7]
this.J0[8] = nonce[8]
this.J0[9] = nonce[9]
this.J0[10] = nonce[10]
this.J0[11] = nonce[11]
this.J0[12] = 0x00
this.J0[13] = 0x00
this.J0[14] = 0x00
this.J0[15] = 0x01
this.Yi[0] = nonce[0]
this.Yi[1] = nonce[1]
this.Yi[2] = nonce[2]
this.Yi[3] = nonce[3]
this.Yi[4] = nonce[4]
this.Yi[5] = nonce[5]
this.Yi[6] = nonce[6]
this.Yi[7] = nonce[7]
this.Yi[8] = nonce[8]
this.Yi[9] = nonce[9]
this.Yi[10] = nonce[10]
this.Yi[11] = nonce[11]
this.Yi[12] = 0x00
this.Yi[13] = 0x00
this.Yi[14] = 0x00
this.Yi[15] = 0x02
}
this.yi12 = 0
this.yi13 = 0
this.yi14 = 0
this.yi15 = 2
this.ghash.Reset()
}
public fn FeedAAD(block: byte[16])
{
this.ghash.UpdateBlock(block)
}
public fn LoadBlock(block: byte[16])
{
state {
this.blk[0] = block[0]
this.blk[1] = block[1]
this.blk[2] = block[2]
this.blk[3] = block[3]
this.blk[4] = block[4]
this.blk[5] = block[5]
this.blk[6] = block[6]
this.blk[7] = block[7]
this.blk[8] = block[8]
this.blk[9] = block[9]
this.blk[10] = block[10]
this.blk[11] = block[11]
this.blk[12] = block[12]
this.blk[13] = block[13]
this.blk[14] = block[14]
this.blk[15] = block[15]
}
}
public fn EncryptBlock()
{
var ks: byte[16] = this.EncryptCounter()
var b0: byte = this.blk[0]
var b1: byte = this.blk[1]
var b2: byte = this.blk[2]
var b3: byte = this.blk[3]
var b4: byte = this.blk[4]
var b5: byte = this.blk[5]
var b6: byte = this.blk[6]
var b7: byte = this.blk[7]
var b8: byte = this.blk[8]
var b9: byte = this.blk[9]
var b10: byte = this.blk[10]
var b11: byte = this.blk[11]
var b12: byte = this.blk[12]
var b13: byte = this.blk[13]
var b14: byte = this.blk[14]
var b15: byte = this.blk[15]
var ct: byte[16]
state {
ct[0] = b0 ^ ks[0]
ct[1] = b1 ^ ks[1]
ct[2] = b2 ^ ks[2]
ct[3] = b3 ^ ks[3]
ct[4] = b4 ^ ks[4]
ct[5] = b5 ^ ks[5]
ct[6] = b6 ^ ks[6]
ct[7] = b7 ^ ks[7]
ct[8] = b8 ^ ks[8]
ct[9] = b9 ^ ks[9]
ct[10] = b10 ^ ks[10]
ct[11] = b11 ^ ks[11]
ct[12] = b12 ^ ks[12]
ct[13] = b13 ^ ks[13]
ct[14] = b14 ^ ks[14]
ct[15] = b15 ^ ks[15]
}
this.ghash.UpdateBlock(ct)
state {
this.outBlk[0] = ct[0]
this.outBlk[1] = ct[1]
this.outBlk[2] = ct[2]
this.outBlk[3] = ct[3]
this.outBlk[4] = ct[4]
this.outBlk[5] = ct[5]
this.outBlk[6] = ct[6]
this.outBlk[7] = ct[7]
this.outBlk[8] = ct[8]
this.outBlk[9] = ct[9]
this.outBlk[10] = ct[10]
this.outBlk[11] = ct[11]
this.outBlk[12] = ct[12]
this.outBlk[13] = ct[13]
this.outBlk[14] = ct[14]
this.outBlk[15] = ct[15]
}
this.IncrementCounter()
}
public fn DecryptBlock()
{
var ks: byte[16] = this.EncryptCounter()
var b0: byte = this.blk[0]
var b1: byte = this.blk[1]
var b2: byte = this.blk[2]
var b3: byte = this.blk[3]
var b4: byte = this.blk[4]
var b5: byte = this.blk[5]
var b6: byte = this.blk[6]
var b7: byte = this.blk[7]
var b8: byte = this.blk[8]
var b9: byte = this.blk[9]
var b10: byte = this.blk[10]
var b11: byte = this.blk[11]
var b12: byte = this.blk[12]
var b13: byte = this.blk[13]
var b14: byte = this.blk[14]
var b15: byte = this.blk[15]
this.ghash.UpdateBlock(this.blk)
state {
this.outBlk[0] = b0 ^ ks[0]
this.outBlk[1] = b1 ^ ks[1]
this.outBlk[2] = b2 ^ ks[2]
this.outBlk[3] = b3 ^ ks[3]
this.outBlk[4] = b4 ^ ks[4]
this.outBlk[5] = b5 ^ ks[5]
this.outBlk[6] = b6 ^ ks[6]
this.outBlk[7] = b7 ^ ks[7]
this.outBlk[8] = b8 ^ ks[8]
this.outBlk[9] = b9 ^ ks[9]
this.outBlk[10] = b10 ^ ks[10]
this.outBlk[11] = b11 ^ ks[11]
this.outBlk[12] = b12 ^ ks[12]
this.outBlk[13] = b13 ^ ks[13]
this.outBlk[14] = b14 ^ ks[14]
this.outBlk[15] = b15 ^ ks[15]
}
this.IncrementCounter()
}
public fn FinalizeTag(aadLenBytes: int, dataLenBytes: int)
{
var aadBits: int = aadLenBytes * 8
var dataBits: int = dataLenBytes * 8
var lenBlock: byte[16]
lenBlock[0] = 0x00
lenBlock[1] = 0x00
lenBlock[2] = 0x00
lenBlock[3] = 0x00
var ab3: int = aadBits % 256
var ab3b: byte = ab3 as byte
var ab2: int = (aadBits / 256) % 256
var ab2b: byte = ab2 as byte
var ab1: int = (aadBits / 65536) % 256
var ab1b: byte = ab1 as byte
var ab0: int = (aadBits / 16777216) % 256
var ab0b: byte = ab0 as byte
lenBlock[4] = ab0b
lenBlock[5] = ab1b
lenBlock[6] = ab2b
lenBlock[7] = ab3b
lenBlock[8] = 0x00
lenBlock[9] = 0x00
lenBlock[10] = 0x00
lenBlock[11] = 0x00
var db3: int = dataBits % 256
var db3b: byte = db3 as byte
var db2: int = (dataBits / 256) % 256
var db2b: byte = db2 as byte
var db1: int = (dataBits / 65536) % 256
var db1b: byte = db1 as byte
var db0: int = (dataBits / 16777216) % 256
var db0b: byte = db0 as byte
lenBlock[12] = db0b
lenBlock[13] = db1b
lenBlock[14] = db2b
lenBlock[15] = db3b
this.ghash.UpdateBlock(lenBlock)
var S: byte[16] = this.ghash.GetY()
this.enc.LoadBlock(this.J0)
this.enc.EncryptBlock()
var ej0: byte[16] = this.enc.GetBlock()
state {
this.tag[0] = S[0] ^ ej0[0]
this.tag[1] = S[1] ^ ej0[1]
this.tag[2] = S[2] ^ ej0[2]
this.tag[3] = S[3] ^ ej0[3]
this.tag[4] = S[4] ^ ej0[4]
this.tag[5] = S[5] ^ ej0[5]
this.tag[6] = S[6] ^ ej0[6]
this.tag[7] = S[7] ^ ej0[7]
this.tag[8] = S[8] ^ ej0[8]
this.tag[9] = S[9] ^ ej0[9]
this.tag[10] = S[10] ^ ej0[10]
this.tag[11] = S[11] ^ ej0[11]
this.tag[12] = S[12] ^ ej0[12]
this.tag[13] = S[13] ^ ej0[13]
this.tag[14] = S[14] ^ ej0[14]
this.tag[15] = S[15] ^ ej0[15]
}
}
public fn GetBlock() byte[16]
{
return this.outBlk
}
public fn GetByte(idx: int) byte
{
return this.outBlk[idx]
}
public fn GetTag() byte[16]
{
return this.tag
}
// VerifyTag compares the finalized authentication tag without early exit.
// Returns 1 on match, 0 on mismatch.
public fn VerifyTag(expected: byte[16]) int
{
var diff: byte = 0x00
for (var i = 0; i < 16; i++)
{
var delta: byte = this.tag[i] ^ expected[i]
diff = diff ^ delta
}
var result: int = 0
if (diff == 0x00)
{
result = 1
}
return result
}
public fn ClearKey()
{
this.enc.ClearKey()
}
fn EncryptCounter() byte[16]
{
this.enc.LoadBlock(this.Yi)
this.enc.EncryptBlock()
return this.enc.GetBlock()
}
fn IncrementCounter()
{
var c12: int = this.yi12
var c13: int = this.yi13
var c14: int = this.yi14
var c15: int = this.yi15
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
}
}
}
}
this.yi12 = c12
this.yi13 = c13
this.yi14 = c14
this.yi15 = c15
this.Yi[12] = c12 as byte
this.Yi[13] = c13 as byte
this.Yi[14] = c14 as byte
this.Yi[15] = c15 as byte
}
}