Skip to content

Commit

Permalink
core/crypto/aegis: Initial import
Browse files Browse the repository at this point in the history
  • Loading branch information
Yawning committed Sep 26, 2024
1 parent 4a14c2a commit 00e013b
Show file tree
Hide file tree
Showing 11 changed files with 1,451 additions and 74 deletions.
7 changes: 2 additions & 5 deletions core/crypto/_aes/ct64/ct64.odin
Original file line number Diff line number Diff line change
Expand Up @@ -210,11 +210,8 @@ orthogonalize :: proc "contextless" (q: ^[8]u64) {
}

@(require_results)
interleave_in :: proc "contextless" (w: []u32) -> (q0, q1: u64) #no_bounds_check {
if len(w) < 4 {
panic_contextless("aes/ct64: invalid input size")
}
x0, x1, x2, x3 := u64(w[0]), u64(w[1]), u64(w[2]), u64(w[3])
interleave_in :: proc "contextless" (w0, w1, w2, w3: u32) -> (q0, q1: u64) #no_bounds_check {
x0, x1, x2, x3 := u64(w0), u64(w1), u64(w2), u64(w3)
x0 |= (x0 << 16)
x1 |= (x1 << 16)
x2 |= (x2 << 16)
Expand Down
56 changes: 1 addition & 55 deletions core/crypto/_aes/ct64/ct64_keysched.odin
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ keysched :: proc(comp_skey: []u64, key: []byte) -> int {

q: [8]u64 = ---
for i, j := 0, 0; i < nkf; i, j = i + 4, j + 2 {
q[0], q[4] = interleave_in(skey[i:])
q[0], q[4] = interleave_in(skey[i], skey[i+1], skey[i+2], skey[i+3])
q[1] = q[0]
q[2] = q[0]
q[3] = q[0]
Expand Down Expand Up @@ -122,57 +122,3 @@ skey_expand :: proc "contextless" (skey, comp_skey: []u64, num_rounds: int) {
skey[v + 3] = (x3 << 4) - x3
}
}

orthogonalize_roundkey :: proc "contextless" (qq: []u64, key: []byte) {
if len(qq) < 8 || len(key) != 16 {
panic_contextless("aes/ct64: invalid round key size")
}

skey: [4]u32 = ---
skey[0] = endian.unchecked_get_u32le(key[0:])
skey[1] = endian.unchecked_get_u32le(key[4:])
skey[2] = endian.unchecked_get_u32le(key[8:])
skey[3] = endian.unchecked_get_u32le(key[12:])

q: [8]u64 = ---
q[0], q[4] = interleave_in(skey[:])
q[1] = q[0]
q[2] = q[0]
q[3] = q[0]
q[5] = q[4]
q[6] = q[4]
q[7] = q[4]
orthogonalize(&q)

comp_skey: [2]u64 = ---
comp_skey[0] =
(q[0] & 0x1111111111111111) |
(q[1] & 0x2222222222222222) |
(q[2] & 0x4444444444444444) |
(q[3] & 0x8888888888888888)
comp_skey[1] =
(q[4] & 0x1111111111111111) |
(q[5] & 0x2222222222222222) |
(q[6] & 0x4444444444444444) |
(q[7] & 0x8888888888888888)

for x, u in comp_skey {
x0 := x
x1, x2, x3 := x0, x0, x0
x0 &= 0x1111111111111111
x1 &= 0x2222222222222222
x2 &= 0x4444444444444444
x3 &= 0x8888888888888888
x1 >>= 1
x2 >>= 2
x3 >>= 3
qq[u * 4 + 0] = (x0 << 4) - x0
qq[u * 4 + 1] = (x1 << 4) - x1
qq[u * 4 + 2] = (x2 << 4) - x2
qq[u * 4 + 3] = (x3 << 4) - x3
}

mem.zero_explicit(&skey, size_of(skey))
mem.zero_explicit(&q, size_of(q))
mem.zero_explicit(&comp_skey, size_of(comp_skey))
}
22 changes: 10 additions & 12 deletions core/crypto/_aes/ct64/helpers.odin
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,11 @@ load_blockx1 :: proc "contextless" (q: ^[8]u64, src: []byte) {
panic_contextless("aes/ct64: invalid block size")
}

w: [4]u32 = ---
w[0] = endian.unchecked_get_u32le(src[0:])
w[1] = endian.unchecked_get_u32le(src[4:])
w[2] = endian.unchecked_get_u32le(src[8:])
w[3] = endian.unchecked_get_u32le(src[12:])
q[0], q[4] = interleave_in(w[:])
w0 := endian.unchecked_get_u32le(src[0:])
w1 := endian.unchecked_get_u32le(src[4:])
w2 := endian.unchecked_get_u32le(src[8:])
w3 := endian.unchecked_get_u32le(src[12:])
q[0], q[4] = interleave_in(w0, w1, w2, w3)
orthogonalize(q)
}

Expand All @@ -35,17 +34,16 @@ load_blocks :: proc "contextless" (q: ^[8]u64, src: [][]byte) {
panic_contextless("aes/ct64: invalid block(s) size")
}

w: [4]u32 = ---
for s, i in src {
if len(s) != _aes.BLOCK_SIZE {
panic_contextless("aes/ct64: invalid block size")
}

w[0] = endian.unchecked_get_u32le(s[0:])
w[1] = endian.unchecked_get_u32le(s[4:])
w[2] = endian.unchecked_get_u32le(s[8:])
w[3] = endian.unchecked_get_u32le(s[12:])
q[i], q[i + 4] = interleave_in(w[:])
w0 := endian.unchecked_get_u32le(s[0:])
w1 := endian.unchecked_get_u32le(s[4:])
w2 := endian.unchecked_get_u32le(s[8:])
w3 := endian.unchecked_get_u32le(s[12:])
q[i], q[i + 4] = interleave_in(w0, w1, w2, w3)
}
orthogonalize(q)
}
Expand Down
47 changes: 45 additions & 2 deletions core/crypto/aead/low_level.odin
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package aead

import "core:crypto/aegis"
import "core:crypto/aes"
import "core:crypto/chacha20"
import "core:crypto/chacha20poly1305"
Expand All @@ -15,7 +16,7 @@ Implementation :: union {

// MAX_TAG_SIZE is the maximum size tag that can be returned by any of the
// Algorithms supported via this package.
MAX_TAG_SIZE :: 16
MAX_TAG_SIZE :: 32

// Algorithm is the algorithm identifier associated with a given Context.
Algorithm :: enum {
Expand All @@ -25,16 +26,24 @@ Algorithm :: enum {
AES_GCM_256,
CHACHA20POLY1305,
XCHACHA20POLY1305,
AEGIS_128L,
AEGIS_128L_256, // AEGIS-128L (256-bit tag)
AEGIS_256,
AEGIS_256_256, // AEGIS-256 (256-bit tag)
}

// ALGORITM_NAMES is the Agorithm to algorithm name string.
// ALGORITM_NAMES is the Algorithm to algorithm name string.
ALGORITHM_NAMES := [Algorithm]string {
.Invalid = "Invalid",
.AES_GCM_128 = "AES-GCM-128",
.AES_GCM_192 = "AES-GCM-192",
.AES_GCM_256 = "AES-GCM-256",
.CHACHA20POLY1305 = "chacha20poly1305",
.XCHACHA20POLY1305 = "xchacha20poly1305",
.AEGIS_128L = "AEGIS-128L",
.AEGIS_128L_256 = "AEGIS-128L-256",
.AEGIS_256 = "AEGIS-256",
.AEGIS_256_256 = "AEGIS-256-256",
}

// TAG_SIZES is the Algorithm to tag size in bytes.
Expand All @@ -45,6 +54,10 @@ TAG_SIZES := [Algorithm]int {
.AES_GCM_256 = aes.GCM_TAG_SIZE,
.CHACHA20POLY1305 = chacha20poly1305.TAG_SIZE,
.XCHACHA20POLY1305 = chacha20poly1305.TAG_SIZE,
.AEGIS_128L = aegis.TAG_SIZE_128,
.AEGIS_128L_256 = aegis.TAG_SIZE_256,
.AEGIS_256 = aegis.TAG_SIZE_128,
.AEGIS_256_256 = aegis.TAG_SIZE_256,
}

// KEY_SIZES is the Algorithm to key size in bytes.
Expand All @@ -55,6 +68,10 @@ KEY_SIZES := [Algorithm]int {
.AES_GCM_256 = aes.KEY_SIZE_256,
.CHACHA20POLY1305 = chacha20poly1305.KEY_SIZE,
.XCHACHA20POLY1305 = chacha20poly1305.KEY_SIZE,
.AEGIS_128L = aegis.KEY_SIZE_128L,
.AEGIS_128L_256 = aegis.KEY_SIZE_128L,
.AEGIS_256 = aegis.KEY_SIZE_256,
.AEGIS_256_256 = aegis.KEY_SIZE_256,
}

// IV_SIZES is the Algorithm to initialization vector size in bytes.
Expand All @@ -67,6 +84,10 @@ IV_SIZES := [Algorithm]int {
.AES_GCM_256 = aes.GCM_IV_SIZE,
.CHACHA20POLY1305 = chacha20poly1305.IV_SIZE,
.XCHACHA20POLY1305 = chacha20poly1305.XIV_SIZE,
.AEGIS_128L = aegis.IV_SIZE_128L,
.AEGIS_128L_256 = aegis.IV_SIZE_128L,
.AEGIS_256 = aegis.IV_SIZE_256,
.AEGIS_256_256 = aegis.IV_SIZE_256,
}

// Context is a concrete instantiation of a specific AEAD algorithm.
Expand All @@ -75,6 +96,7 @@ Context :: struct {
_impl: union {
aes.Context_GCM,
chacha20poly1305.Context,
aegis.Context,
},
}

Expand All @@ -86,6 +108,10 @@ _IMPL_IDS := [Algorithm]typeid {
.AES_GCM_256 = typeid_of(aes.Context_GCM),
.CHACHA20POLY1305 = typeid_of(chacha20poly1305.Context),
.XCHACHA20POLY1305 = typeid_of(chacha20poly1305.Context),
.AEGIS_128L = typeid_of(aegis.Context),
.AEGIS_128L_256 = typeid_of(aegis.Context),
.AEGIS_256 = typeid_of(aegis.Context),
.AEGIS_256_256 = typeid_of(aegis.Context),
}

// init initializes a Context with a specific AEAD Algorithm.
Expand Down Expand Up @@ -113,6 +139,9 @@ init :: proc(ctx: ^Context, algorithm: Algorithm, key: []byte, impl: Implementat
case .XCHACHA20POLY1305:
impl_ := impl != nil ? impl.(chacha20.Implementation) : chacha20.DEFAULT_IMPLEMENTATION
chacha20poly1305.init_xchacha(&ctx._impl.(chacha20poly1305.Context), key, impl_)
case .AEGIS_128L, .AEGIS_128L_256, .AEGIS_256, .AEGIS_256_256:
impl_ := impl != nil ? impl.(aes.Implementation) : aes.DEFAULT_IMPLEMENTATION
aegis.init(&ctx._impl.(aegis.Context), key, impl_)
case .Invalid:
panic("crypto/aead: uninitialized algorithm")
case:
Expand All @@ -127,11 +156,17 @@ init :: proc(ctx: ^Context, algorithm: Algorithm, key: []byte, impl: Implementat
//
// dst and plaintext MUST alias exactly or not at all.
seal_ctx :: proc(ctx: ^Context, dst, tag, iv, aad, plaintext: []byte) {
if len(tag) != TAG_SIZES[ctx._algo] {
panic("crypto/aead: invalid tag size")
}

switch &impl in ctx._impl {
case aes.Context_GCM:
aes.seal_gcm(&impl, dst, tag, iv, aad, plaintext)
case chacha20poly1305.Context:
chacha20poly1305.seal(&impl, dst, tag, iv, aad, plaintext)
case aegis.Context:
aegis.seal(&impl, dst, tag, iv, aad, plaintext)
case:
panic("crypto/aead: uninitialized algorithm")
}
Expand All @@ -145,11 +180,17 @@ seal_ctx :: proc(ctx: ^Context, dst, tag, iv, aad, plaintext: []byte) {
// dst and plaintext MUST alias exactly or not at all.
@(require_results)
open_ctx :: proc(ctx: ^Context, dst, iv, aad, ciphertext, tag: []byte) -> bool {
if len(tag) != TAG_SIZES[ctx._algo] {
panic("crypto/aead: invalid tag size")
}

switch &impl in ctx._impl {
case aes.Context_GCM:
return aes.open_gcm(&impl, dst, iv, aad, ciphertext, tag)
case chacha20poly1305.Context:
return chacha20poly1305.open(&impl, dst, iv, aad, ciphertext, tag)
case aegis.Context:
return aegis.open(&impl, dst, iv, aad, ciphertext, tag)
case:
panic("crypto/aead: uninitialized algorithm")
}
Expand All @@ -163,6 +204,8 @@ reset :: proc(ctx: ^Context) {
aes.reset_gcm(&impl)
case chacha20poly1305.Context:
chacha20poly1305.reset(&impl)
case aegis.Context:
aegis.reset(&impl)
case:
// Calling reset repeatedly is fine.
}
Expand Down
Loading

0 comments on commit 00e013b

Please sign in to comment.