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/aes/Cmac192.lvt
namespace Livt.Crypto.Aes
// AES-192 CMAC (Cipher-based MAC) — NIST SP 800-38B.
//
// Usage (per message):
// 1. SetKey(key)
// 2. Reset()
// 3. For each non-final complete block: UpdateBlock(block)
// 4a. FinalizeBlock(block) — final complete block (uses K1)
// 4b. FinalizePaddedBlock(block) — final padded block (uses K2)
// Caller pads: data[0..n-1] || 0x80 || 0x00..0x00
// 5. GetTag()
//
// For a zero-length message: Reset() then FinalizePaddedBlock(0x80 00..00).
component Cmac192
{
public const KEY_SIZE: int = 24
public const BLOCK_SIZE: int = 16
public const TAG_SIZE: int = 16
enc: EncryptBlock192
k1: byte[16]
k2: byte[16]
X: byte[16]
tag: byte[16]
new()
{
this.enc = new EncryptBlock192()
}
// -----------------------------------------------------------------------
// Public API
// -----------------------------------------------------------------------
public fn SetKey(key: byte[24])
{
this.enc.SetKey(key)
// L = AES_K(0^128).
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 L: byte[16] = this.enc.GetBlock()
// Read L bytes as ints for DeriveSubkey (§10 two-step cast).
var l0b: byte = L[0]
var l0: int = l0b as int
var l1b: byte = L[1]
var l1: int = l1b as int
var l2b: byte = L[2]
var l2: int = l2b as int
var l3b: byte = L[3]
var l3: int = l3b as int
var l4b: byte = L[4]
var l4: int = l4b as int
var l5b: byte = L[5]
var l5: int = l5b as int
var l6b: byte = L[6]
var l6: int = l6b as int
var l7b: byte = L[7]
var l7: int = l7b as int
var l8b: byte = L[8]
var l8: int = l8b as int
var l9b: byte = L[9]
var l9: int = l9b as int
var l10b: byte = L[10]
var l10: int = l10b as int
var l11b: byte = L[11]
var l11: int = l11b as int
var l12b: byte = L[12]
var l12: int = l12b as int
var l13b: byte = L[13]
var l13: int = l13b as int
var l14b: byte = L[14]
var l14: int = l14b as int
var l15b: byte = L[15]
var l15: int = l15b as int
// K1 = DeriveSubkey(L).
var k1Result: byte[16] = this.DeriveSubkey(l0, l1, l2, l3, l4, l5, l6, l7,
l8, l9, l10, l11, l12, l13, l14, l15)
// Read K1 bytes as ints for DeriveSubkey(K1) (§10 two-step cast).
var k1_0b: byte = k1Result[0]
var k1_0: int = k1_0b as int
var k1_1b: byte = k1Result[1]
var k1_1: int = k1_1b as int
var k1_2b: byte = k1Result[2]
var k1_2: int = k1_2b as int
var k1_3b: byte = k1Result[3]
var k1_3: int = k1_3b as int
var k1_4b: byte = k1Result[4]
var k1_4: int = k1_4b as int
var k1_5b: byte = k1Result[5]
var k1_5: int = k1_5b as int
var k1_6b: byte = k1Result[6]
var k1_6: int = k1_6b as int
var k1_7b: byte = k1Result[7]
var k1_7: int = k1_7b as int
var k1_8b: byte = k1Result[8]
var k1_8: int = k1_8b as int
var k1_9b: byte = k1Result[9]
var k1_9: int = k1_9b as int
var k1_10b: byte = k1Result[10]
var k1_10: int = k1_10b as int
var k1_11b: byte = k1Result[11]
var k1_11: int = k1_11b as int
var k1_12b: byte = k1Result[12]
var k1_12: int = k1_12b as int
var k1_13b: byte = k1Result[13]
var k1_13: int = k1_13b as int
var k1_14b: byte = k1Result[14]
var k1_14: int = k1_14b as int
var k1_15b: byte = k1Result[15]
var k1_15: int = k1_15b as int
// K2 = DeriveSubkey(K1).
var k2Result: byte[16] = this.DeriveSubkey(k1_0, k1_1, k1_2, k1_3, k1_4, k1_5, k1_6, k1_7,
k1_8, k1_9, k1_10, k1_11, k1_12, k1_13, k1_14, k1_15)
// Store K1.
for (var i = 0; i < 16; i++)
{
this.k1[i] = k1Result[i]
}
// Store K2.
for (var j = 0; j < 16; j++)
{
this.k2[j] = k2Result[j]
}
}
// Reset the running state X to 0^128 before processing a new message.
public fn Reset()
{
for (var i = 0; i < 16; i++)
{
this.X[i] = 0x00
}
}
// Feed a non-final complete 16-byte block: X = AES_K(X XOR block).
public fn UpdateBlock(block: byte[16])
{
var x0: byte = this.X[0]
var x1: byte = this.X[1]
var x2: byte = this.X[2]
var x3: byte = this.X[3]
var x4: byte = this.X[4]
var x5: byte = this.X[5]
var x6: byte = this.X[6]
var x7: byte = this.X[7]
var x8: byte = this.X[8]
var x9: byte = this.X[9]
var x10: byte = this.X[10]
var x11: byte = this.X[11]
var x12: byte = this.X[12]
var x13: byte = this.X[13]
var x14: byte = this.X[14]
var x15: byte = this.X[15]
// Read block into locals.
var b0: byte = block[0]
var b1: byte = block[1]
var b2: byte = block[2]
var b3: byte = block[3]
var b4: byte = block[4]
var b5: byte = block[5]
var b6: byte = block[6]
var b7: byte = block[7]
var b8: byte = block[8]
var b9: byte = block[9]
var b10: byte = block[10]
var b11: byte = block[11]
var b12: byte = block[12]
var b13: byte = block[13]
var b14: byte = block[14]
var b15: byte = block[15]
// XOR X with block.
var xb0: byte = x0 ^ b0
var xb1: byte = x1 ^ b1
var xb2: byte = x2 ^ b2
var xb3: byte = x3 ^ b3
var xb4: byte = x4 ^ b4
var xb5: byte = x5 ^ b5
var xb6: byte = x6 ^ b6
var xb7: byte = x7 ^ b7
var xb8: byte = x8 ^ b8
var xb9: byte = x9 ^ b9
var xb10: byte = x10 ^ b10
var xb11: byte = x11 ^ b11
var xb12: byte = x12 ^ b12
var xb13: byte = x13 ^ b13
var xb14: byte = x14 ^ b14
var xb15: byte = x15 ^ b15
var xorBlock: byte[16]
xorBlock[0] = xb0
xorBlock[1] = xb1
xorBlock[2] = xb2
xorBlock[3] = xb3
xorBlock[4] = xb4
xorBlock[5] = xb5
xorBlock[6] = xb6
xorBlock[7] = xb7
xorBlock[8] = xb8
xorBlock[9] = xb9
xorBlock[10] = xb10
xorBlock[11] = xb11
xorBlock[12] = xb12
xorBlock[13] = xb13
xorBlock[14] = xb14
xorBlock[15] = xb15
// Encrypt and store result back to X.
this.enc.LoadBlock(xorBlock)
this.enc.EncryptBlock()
var result: byte[16] = this.enc.GetBlock()
for (var i = 0; i < 16; i++)
{
this.X[i] = result[i]
}
}
// Finalize a complete 16-byte final block: tag = AES_K(X XOR block XOR K1).
public fn FinalizeBlock(block: byte[16])
{
var x0: byte = this.X[0]
var x1: byte = this.X[1]
var x2: byte = this.X[2]
var x3: byte = this.X[3]
var x4: byte = this.X[4]
var x5: byte = this.X[5]
var x6: byte = this.X[6]
var x7: byte = this.X[7]
var x8: byte = this.X[8]
var x9: byte = this.X[9]
var x10: byte = this.X[10]
var x11: byte = this.X[11]
var x12: byte = this.X[12]
var x13: byte = this.X[13]
var x14: byte = this.X[14]
var x15: byte = this.X[15]
var k1_0: byte = this.k1[0]
var k1_1: byte = this.k1[1]
var k1_2: byte = this.k1[2]
var k1_3: byte = this.k1[3]
var k1_4: byte = this.k1[4]
var k1_5: byte = this.k1[5]
var k1_6: byte = this.k1[6]
var k1_7: byte = this.k1[7]
var k1_8: byte = this.k1[8]
var k1_9: byte = this.k1[9]
var k1_10: byte = this.k1[10]
var k1_11: byte = this.k1[11]
var k1_12: byte = this.k1[12]
var k1_13: byte = this.k1[13]
var k1_14: byte = this.k1[14]
var k1_15: byte = this.k1[15]
// Read block into locals.
var b0: byte = block[0]
var b1: byte = block[1]
var b2: byte = block[2]
var b3: byte = block[3]
var b4: byte = block[4]
var b5: byte = block[5]
var b6: byte = block[6]
var b7: byte = block[7]
var b8: byte = block[8]
var b9: byte = block[9]
var b10: byte = block[10]
var b11: byte = block[11]
var b12: byte = block[12]
var b13: byte = block[13]
var b14: byte = block[14]
var b15: byte = block[15]
// Compute X XOR block.
var xb0: byte = x0 ^ b0
var xb1: byte = x1 ^ b1
var xb2: byte = x2 ^ b2
var xb3: byte = x3 ^ b3
var xb4: byte = x4 ^ b4
var xb5: byte = x5 ^ b5
var xb6: byte = x6 ^ b6
var xb7: byte = x7 ^ b7
var xb8: byte = x8 ^ b8
var xb9: byte = x9 ^ b9
var xb10: byte = x10 ^ b10
var xb11: byte = x11 ^ b11
var xb12: byte = x12 ^ b12
var xb13: byte = x13 ^ b13
var xb14: byte = x14 ^ b14
var xb15: byte = x15 ^ b15
// Compute (X XOR block) XOR K1.
var y0: byte = xb0 ^ k1_0
var y1: byte = xb1 ^ k1_1
var y2: byte = xb2 ^ k1_2
var y3: byte = xb3 ^ k1_3
var y4: byte = xb4 ^ k1_4
var y5: byte = xb5 ^ k1_5
var y6: byte = xb6 ^ k1_6
var y7: byte = xb7 ^ k1_7
var y8: byte = xb8 ^ k1_8
var y9: byte = xb9 ^ k1_9
var y10: byte = xb10 ^ k1_10
var y11: byte = xb11 ^ k1_11
var y12: byte = xb12 ^ k1_12
var y13: byte = xb13 ^ k1_13
var y14: byte = xb14 ^ k1_14
var y15: byte = xb15 ^ k1_15
var inputBlock: byte[16]
inputBlock[0] = y0
inputBlock[1] = y1
inputBlock[2] = y2
inputBlock[3] = y3
inputBlock[4] = y4
inputBlock[5] = y5
inputBlock[6] = y6
inputBlock[7] = y7
inputBlock[8] = y8
inputBlock[9] = y9
inputBlock[10] = y10
inputBlock[11] = y11
inputBlock[12] = y12
inputBlock[13] = y13
inputBlock[14] = y14
inputBlock[15] = y15
// Encrypt to produce tag.
this.enc.LoadBlock(inputBlock)
this.enc.EncryptBlock()
var result: byte[16] = this.enc.GetBlock()
for (var i = 0; i < 16; i++)
{
this.tag[i] = result[i]
}
}
// Finalize a padded final block: tag = AES_K(X XOR block XOR K2).
// Caller must have already applied the 0x80 || 0x00... padding.
public fn FinalizePaddedBlock(block: byte[16])
{
var x0: byte = this.X[0]
var x1: byte = this.X[1]
var x2: byte = this.X[2]
var x3: byte = this.X[3]
var x4: byte = this.X[4]
var x5: byte = this.X[5]
var x6: byte = this.X[6]
var x7: byte = this.X[7]
var x8: byte = this.X[8]
var x9: byte = this.X[9]
var x10: byte = this.X[10]
var x11: byte = this.X[11]
var x12: byte = this.X[12]
var x13: byte = this.X[13]
var x14: byte = this.X[14]
var x15: byte = this.X[15]
var k2_0: byte = this.k2[0]
var k2_1: byte = this.k2[1]
var k2_2: byte = this.k2[2]
var k2_3: byte = this.k2[3]
var k2_4: byte = this.k2[4]
var k2_5: byte = this.k2[5]
var k2_6: byte = this.k2[6]
var k2_7: byte = this.k2[7]
var k2_8: byte = this.k2[8]
var k2_9: byte = this.k2[9]
var k2_10: byte = this.k2[10]
var k2_11: byte = this.k2[11]
var k2_12: byte = this.k2[12]
var k2_13: byte = this.k2[13]
var k2_14: byte = this.k2[14]
var k2_15: byte = this.k2[15]
// Read block into locals.
var b0: byte = block[0]
var b1: byte = block[1]
var b2: byte = block[2]
var b3: byte = block[3]
var b4: byte = block[4]
var b5: byte = block[5]
var b6: byte = block[6]
var b7: byte = block[7]
var b8: byte = block[8]
var b9: byte = block[9]
var b10: byte = block[10]
var b11: byte = block[11]
var b12: byte = block[12]
var b13: byte = block[13]
var b14: byte = block[14]
var b15: byte = block[15]
// Compute X XOR block.
var xb0: byte = x0 ^ b0
var xb1: byte = x1 ^ b1
var xb2: byte = x2 ^ b2
var xb3: byte = x3 ^ b3
var xb4: byte = x4 ^ b4
var xb5: byte = x5 ^ b5
var xb6: byte = x6 ^ b6
var xb7: byte = x7 ^ b7
var xb8: byte = x8 ^ b8
var xb9: byte = x9 ^ b9
var xb10: byte = x10 ^ b10
var xb11: byte = x11 ^ b11
var xb12: byte = x12 ^ b12
var xb13: byte = x13 ^ b13
var xb14: byte = x14 ^ b14
var xb15: byte = x15 ^ b15
// Compute (X XOR block) XOR K2.
var y0: byte = xb0 ^ k2_0
var y1: byte = xb1 ^ k2_1
var y2: byte = xb2 ^ k2_2
var y3: byte = xb3 ^ k2_3
var y4: byte = xb4 ^ k2_4
var y5: byte = xb5 ^ k2_5
var y6: byte = xb6 ^ k2_6
var y7: byte = xb7 ^ k2_7
var y8: byte = xb8 ^ k2_8
var y9: byte = xb9 ^ k2_9
var y10: byte = xb10 ^ k2_10
var y11: byte = xb11 ^ k2_11
var y12: byte = xb12 ^ k2_12
var y13: byte = xb13 ^ k2_13
var y14: byte = xb14 ^ k2_14
var y15: byte = xb15 ^ k2_15
var inputBlock: byte[16]
inputBlock[0] = y0
inputBlock[1] = y1
inputBlock[2] = y2
inputBlock[3] = y3
inputBlock[4] = y4
inputBlock[5] = y5
inputBlock[6] = y6
inputBlock[7] = y7
inputBlock[8] = y8
inputBlock[9] = y9
inputBlock[10] = y10
inputBlock[11] = y11
inputBlock[12] = y12
inputBlock[13] = y13
inputBlock[14] = y14
inputBlock[15] = y15
// Encrypt to produce tag.
this.enc.LoadBlock(inputBlock)
this.enc.EncryptBlock()
var result: byte[16] = this.enc.GetBlock()
for (var i = 0; i < 16; i++)
{
this.tag[i] = result[i]
}
}
public fn GetTag() byte[16]
{
return this.tag
}
public fn ClearKey()
{
for (var i = 0; i < 16; i++)
{
this.k1[i] = 0x00
}
for (var j = 0; j < 16; j++)
{
this.k2[j] = 0x00
}
for (var k = 0; k < 16; k++)
{
this.X[k] = 0x00
}
for (var m = 0; m < 16; m++)
{
this.tag[m] = 0x00
}
this.enc.ClearKey()
}
// -----------------------------------------------------------------------
// Private helpers
// -----------------------------------------------------------------------
// Left-shift a 128-bit value (supplied as 16 int bytes) by one bit.
// If the original MSB (bit 127) was 1, XOR byte 15 with Rb = 0x87.
fn DeriveSubkey[](v0: int, v1: int, v2: int, v3: int, v4: int, v5: int, v6: int, v7: int,
v8: int, v9: int, v10: int, v11: int, v12: int, v13: int, v14: int, v15: int) byte[16]
{
var msb: int = v0 / 128 % 2
// Shift each byte left by 1, carrying in MSB of the next byte.
var n0: int = v0 * 2 % 256 + v1 / 128 % 2
var n1: int = v1 * 2 % 256 + v2 / 128 % 2
var n2: int = v2 * 2 % 256 + v3 / 128 % 2
var n3: int = v3 * 2 % 256 + v4 / 128 % 2
var n4: int = v4 * 2 % 256 + v5 / 128 % 2
var n5: int = v5 * 2 % 256 + v6 / 128 % 2
var n6: int = v6 * 2 % 256 + v7 / 128 % 2
var n7: int = v7 * 2 % 256 + v8 / 128 % 2
var n8: int = v8 * 2 % 256 + v9 / 128 % 2
var n9: int = v9 * 2 % 256 + v10 / 128 % 2
var n10: int = v10 * 2 % 256 + v11 / 128 % 2
var n11: int = v11 * 2 % 256 + v12 / 128 % 2
var n12: int = v12 * 2 % 256 + v13 / 128 % 2
var n13: int = v13 * 2 % 256 + v14 / 128 % 2
var n14: int = v14 * 2 % 256 + v15 / 128 % 2
var n15: int = v15 * 2 % 256
// Convert int results to bytes.
var n0b: byte = n0 as byte
var n1b: byte = n1 as byte
var n2b: byte = n2 as byte
var n3b: byte = n3 as byte
var n4b: byte = n4 as byte
var n5b: byte = n5 as byte
var n6b: byte = n6 as byte
var n7b: byte = n7 as byte
var n8b: byte = n8 as byte
var n9b: byte = n9 as byte
var n10b: byte = n10 as byte
var n11b: byte = n11 as byte
var n12b: byte = n12 as byte
var n13b: byte = n13 as byte
var n14b: byte = n14 as byte
var n15b: byte = n15 as byte
// Conditionally XOR byte 15 with Rb = 0x87 = 135 using multiply trick
// (avoids if-reassignment): rbInt is 0 when msb=0, 135 when msb=1.
var rbInt: int = msb * 135
var rbByte: byte = rbInt as byte
var xn15: byte = n15b ^ rbByte
var result: byte[16]
result[0] = n0b
result[1] = n1b
result[2] = n2b
result[3] = n3b
result[4] = n4b
result[5] = n5b
result[6] = n6b
result[7] = n7b
result[8] = n8b
result[9] = n9b
result[10] = n10b
result[11] = n11b
result[12] = n12b
result[13] = n13b
result[14] = n14b
result[15] = xn15
return result
}
}