Make key, nonce the first arguments (in this order), require kwargs past the initial few positional arguments. Add ALIGNMENT constant to each module. Add a script to generate all other modules from aegis256x4.py.
This commit is contained in:
@@ -18,6 +18,7 @@ NPUBBYTES = _lib.aegis128l_npubbytes()
|
||||
ABYTES_MIN = _lib.aegis128l_abytes_min()
|
||||
ABYTES_MAX = _lib.aegis128l_abytes_max()
|
||||
TAILBYTES_MAX = _lib.aegis128l_tailbytes_max()
|
||||
ALIGNMENT = 32
|
||||
|
||||
|
||||
def _ptr(buf):
|
||||
@@ -33,10 +34,11 @@ def _ptr(buf):
|
||||
|
||||
|
||||
def encrypt_detached(
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
message: Buffer,
|
||||
ad: Buffer | None = None,
|
||||
*,
|
||||
maclen: int = ABYTES_MIN,
|
||||
ct_into: Buffer | None = None,
|
||||
mac_into: Buffer | None = None,
|
||||
@@ -44,8 +46,8 @@ def encrypt_detached(
|
||||
"""Encrypt message with associated data, returning ciphertext and MAC separately.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
message: The plaintext message to encrypt.
|
||||
ad: Associated data (optional).
|
||||
maclen: MAC length (16 or 32, default 16).
|
||||
@@ -99,18 +101,19 @@ def encrypt_detached(
|
||||
|
||||
|
||||
def decrypt_detached(
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
ct: Buffer,
|
||||
mac: Buffer,
|
||||
ad: Buffer | None = None,
|
||||
*,
|
||||
into: Buffer | None = None,
|
||||
) -> memoryview:
|
||||
"""Decrypt ciphertext with detached MAC and associated data.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
ct: The ciphertext to decrypt.
|
||||
mac: The MAC to verify.
|
||||
ad: Associated data (optional).
|
||||
@@ -158,18 +161,19 @@ def decrypt_detached(
|
||||
|
||||
|
||||
def encrypt(
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
message: Buffer,
|
||||
ad: Buffer | None = None,
|
||||
*,
|
||||
maclen: int = ABYTES_MIN,
|
||||
into: Buffer | None = None,
|
||||
) -> memoryview:
|
||||
"""Encrypt message with associated data, returning ciphertext with appended MAC.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
message: The plaintext message to encrypt.
|
||||
ad: Associated data (optional).
|
||||
maclen: MAC length (16 or 32, default 16).
|
||||
@@ -216,18 +220,19 @@ def encrypt(
|
||||
|
||||
|
||||
def decrypt(
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
ct: Buffer,
|
||||
ad: Buffer | None = None,
|
||||
*,
|
||||
maclen: int = ABYTES_MIN,
|
||||
into: Buffer | None = None,
|
||||
) -> memoryview:
|
||||
"""Decrypt ciphertext with appended MAC and associated data.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
ct: The ciphertext with MAC to decrypt.
|
||||
ad: Associated data (optional).
|
||||
maclen: MAC length (16 or 32, default 16).
|
||||
@@ -274,16 +279,17 @@ def decrypt(
|
||||
|
||||
|
||||
def stream(
|
||||
nonce: Buffer | None,
|
||||
key: Buffer,
|
||||
nonce: Buffer | None,
|
||||
length: int | None = None,
|
||||
*,
|
||||
into: Buffer | None = None,
|
||||
) -> memoryview:
|
||||
"""Generate a stream of pseudorandom bytes.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes, uses zeroes for nonce if None).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes, uses zeroes for nonce if None).
|
||||
length: Number of bytes to generate (required if into is None).
|
||||
into: Buffer to write stream into (default: bytearray created).
|
||||
|
||||
@@ -314,17 +320,18 @@ def stream(
|
||||
|
||||
|
||||
def encrypt_unauthenticated(
|
||||
message: Buffer,
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
message: Buffer,
|
||||
*,
|
||||
into: Buffer | None = None,
|
||||
) -> memoryview:
|
||||
"""Encrypt message without authentication (for testing/debugging).
|
||||
|
||||
Args:
|
||||
message: The plaintext message to encrypt.
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
message: The plaintext message to encrypt.
|
||||
into: Buffer to write ciphertext into (default: bytearray created).
|
||||
|
||||
Returns:
|
||||
@@ -356,17 +363,18 @@ def encrypt_unauthenticated(
|
||||
|
||||
|
||||
def decrypt_unauthenticated(
|
||||
ct: Buffer,
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
ct: Buffer,
|
||||
*,
|
||||
into: Buffer | None = None,
|
||||
) -> memoryview:
|
||||
"""Decrypt ciphertext without authentication (for testing/debugging).
|
||||
|
||||
Args:
|
||||
ct: The ciphertext to decrypt.
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
ct: The ciphertext to decrypt.
|
||||
into: Buffer to write plaintext into (default: bytearray created).
|
||||
|
||||
Returns:
|
||||
@@ -399,56 +407,56 @@ def decrypt_unauthenticated(
|
||||
|
||||
# This is missing from C API but convenient to have here
|
||||
def mac(
|
||||
data: Buffer,
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
data: Buffer,
|
||||
maclen: int = ABYTES_MIN,
|
||||
) -> memoryview:
|
||||
"""Compute a MAC for the given data in one shot.
|
||||
|
||||
Args:
|
||||
data: Data to MAC
|
||||
nonce: Nonce (32 bytes)
|
||||
key: Key (32 bytes)
|
||||
nonce: Nonce (32 bytes)
|
||||
data: Data to MAC
|
||||
maclen: MAC length (16 or 32, default 16)
|
||||
|
||||
Returns:
|
||||
MAC bytes
|
||||
"""
|
||||
mac_state = Mac(nonce, key)
|
||||
mac_state = Mac(key, nonce)
|
||||
mac_state.update(data)
|
||||
return mac_state.final(maclen)
|
||||
|
||||
|
||||
class Mac:
|
||||
"""AEGIS-256X4 MAC state wrapper.
|
||||
"""AEGIS-128L MAC state wrapper.
|
||||
|
||||
Usage:
|
||||
mac = Mac(nonce, key)
|
||||
mac = Mac(key, nonce)
|
||||
mac.update(data)
|
||||
tag = mac.final() # defaults to 16-byte MAC
|
||||
# or verify:
|
||||
mac2 = Mac(nonce, key); mac2.update(data); mac2.verify(tag)
|
||||
mac2 = Mac(key, nonce); mac2.update(data); mac2.verify(tag)
|
||||
"""
|
||||
|
||||
__slots__ = ("_st", "_nonce", "_key")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
_other=None,
|
||||
) -> None:
|
||||
"""Initialize a MAC state with a nonce and key.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
|
||||
Raises:
|
||||
TypeError: If key or nonce lengths are invalid.
|
||||
"""
|
||||
raw = alloc_aligned(ffi.sizeof("aegis128l_mac_state"), 32)
|
||||
raw = alloc_aligned(ffi.sizeof("aegis128l_mac_state"), ALIGNMENT)
|
||||
st = ffi.cast("aegis128l_mac_state *", raw)
|
||||
self._st = ffi.gc(st, libc.free)
|
||||
if _other is not None:
|
||||
@@ -553,12 +561,12 @@ class Encryptor:
|
||||
|
||||
__slots__ = ("_st",)
|
||||
|
||||
def __init__(self, nonce: Buffer, key: Buffer, ad: Buffer | None = None):
|
||||
def __init__(self, key: Buffer, nonce: Buffer, ad: Buffer | None = None):
|
||||
"""Create an incremental encryptor.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
ad: Associated data to bind to the encryption (optional).
|
||||
|
||||
Raises:
|
||||
@@ -570,7 +578,7 @@ class Encryptor:
|
||||
raise TypeError(f"key length must be {KEYBYTES}")
|
||||
if nonce.nbytes != NPUBBYTES:
|
||||
raise TypeError(f"nonce length must be {NPUBBYTES}")
|
||||
raw = alloc_aligned(ffi.sizeof("aegis128l_state"), 32)
|
||||
raw = alloc_aligned(ffi.sizeof("aegis128l_state"), ALIGNMENT)
|
||||
st = ffi.cast("aegis128l_state *", raw)
|
||||
st = ffi.gc(st, libc.free)
|
||||
_lib.aegis128l_state_init(
|
||||
@@ -704,12 +712,12 @@ class Decryptor:
|
||||
|
||||
__slots__ = ("_st",)
|
||||
|
||||
def __init__(self, nonce: Buffer, key: Buffer, ad: Buffer | None = None):
|
||||
def __init__(self, key: Buffer, nonce: Buffer, ad: Buffer | None = None):
|
||||
"""Create an incremental decryptor for detached tags.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
ad: Associated data used during encryption (optional).
|
||||
|
||||
Raises:
|
||||
@@ -721,7 +729,7 @@ class Decryptor:
|
||||
raise TypeError(f"key length must be {KEYBYTES}")
|
||||
if nonce.nbytes != NPUBBYTES:
|
||||
raise TypeError(f"nonce length must be {NPUBBYTES}")
|
||||
raw = alloc_aligned(ffi.sizeof("aegis128l_state"), 32)
|
||||
raw = alloc_aligned(ffi.sizeof("aegis128l_state"), ALIGNMENT)
|
||||
st = ffi.cast("aegis128l_state *", raw)
|
||||
st = ffi.gc(st, libc.free)
|
||||
_lib.aegis128l_state_init(
|
||||
@@ -812,15 +820,15 @@ def new_state():
|
||||
|
||||
The returned object is an ffi cdata pointer with automatic finalizer.
|
||||
"""
|
||||
# Allocate with 64-byte alignment using libc.posix_memalign
|
||||
raw = alloc_aligned(ffi.sizeof("aegis128l_state"), 32)
|
||||
# Allocate with required alignment using libc.posix_memalign
|
||||
raw = alloc_aligned(ffi.sizeof("aegis128l_state"), ALIGNMENT)
|
||||
ptr = ffi.cast("aegis128l_state *", raw)
|
||||
return ffi.gc(ptr, libc.free)
|
||||
|
||||
|
||||
def new_mac_state():
|
||||
"""Allocate and return a new aegis128l_mac_state* with proper alignment."""
|
||||
raw = alloc_aligned(ffi.sizeof("aegis128l_mac_state"), 32)
|
||||
raw = alloc_aligned(ffi.sizeof("aegis128l_mac_state"), ALIGNMENT)
|
||||
ptr = ffi.cast("aegis128l_mac_state *", raw)
|
||||
return ffi.gc(ptr, libc.free)
|
||||
|
||||
@@ -832,6 +840,7 @@ __all__ = [
|
||||
"ABYTES_MIN",
|
||||
"ABYTES_MAX",
|
||||
"TAILBYTES_MAX",
|
||||
"ALIGNMENT",
|
||||
# one-shot functions
|
||||
"encrypt_detached",
|
||||
"decrypt_detached",
|
||||
|
||||
@@ -18,6 +18,7 @@ NPUBBYTES = _lib.aegis128x2_npubbytes()
|
||||
ABYTES_MIN = _lib.aegis128x2_abytes_min()
|
||||
ABYTES_MAX = _lib.aegis128x2_abytes_max()
|
||||
TAILBYTES_MAX = _lib.aegis128x2_tailbytes_max()
|
||||
ALIGNMENT = 64
|
||||
|
||||
|
||||
def _ptr(buf):
|
||||
@@ -33,10 +34,11 @@ def _ptr(buf):
|
||||
|
||||
|
||||
def encrypt_detached(
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
message: Buffer,
|
||||
ad: Buffer | None = None,
|
||||
*,
|
||||
maclen: int = ABYTES_MIN,
|
||||
ct_into: Buffer | None = None,
|
||||
mac_into: Buffer | None = None,
|
||||
@@ -44,8 +46,8 @@ def encrypt_detached(
|
||||
"""Encrypt message with associated data, returning ciphertext and MAC separately.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
message: The plaintext message to encrypt.
|
||||
ad: Associated data (optional).
|
||||
maclen: MAC length (16 or 32, default 16).
|
||||
@@ -99,18 +101,19 @@ def encrypt_detached(
|
||||
|
||||
|
||||
def decrypt_detached(
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
ct: Buffer,
|
||||
mac: Buffer,
|
||||
ad: Buffer | None = None,
|
||||
*,
|
||||
into: Buffer | None = None,
|
||||
) -> memoryview:
|
||||
"""Decrypt ciphertext with detached MAC and associated data.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
ct: The ciphertext to decrypt.
|
||||
mac: The MAC to verify.
|
||||
ad: Associated data (optional).
|
||||
@@ -158,18 +161,19 @@ def decrypt_detached(
|
||||
|
||||
|
||||
def encrypt(
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
message: Buffer,
|
||||
ad: Buffer | None = None,
|
||||
*,
|
||||
maclen: int = ABYTES_MIN,
|
||||
into: Buffer | None = None,
|
||||
) -> memoryview:
|
||||
"""Encrypt message with associated data, returning ciphertext with appended MAC.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
message: The plaintext message to encrypt.
|
||||
ad: Associated data (optional).
|
||||
maclen: MAC length (16 or 32, default 16).
|
||||
@@ -216,18 +220,19 @@ def encrypt(
|
||||
|
||||
|
||||
def decrypt(
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
ct: Buffer,
|
||||
ad: Buffer | None = None,
|
||||
*,
|
||||
maclen: int = ABYTES_MIN,
|
||||
into: Buffer | None = None,
|
||||
) -> memoryview:
|
||||
"""Decrypt ciphertext with appended MAC and associated data.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
ct: The ciphertext with MAC to decrypt.
|
||||
ad: Associated data (optional).
|
||||
maclen: MAC length (16 or 32, default 16).
|
||||
@@ -274,16 +279,17 @@ def decrypt(
|
||||
|
||||
|
||||
def stream(
|
||||
nonce: Buffer | None,
|
||||
key: Buffer,
|
||||
nonce: Buffer | None,
|
||||
length: int | None = None,
|
||||
*,
|
||||
into: Buffer | None = None,
|
||||
) -> memoryview:
|
||||
"""Generate a stream of pseudorandom bytes.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes, uses zeroes for nonce if None).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes, uses zeroes for nonce if None).
|
||||
length: Number of bytes to generate (required if into is None).
|
||||
into: Buffer to write stream into (default: bytearray created).
|
||||
|
||||
@@ -314,17 +320,18 @@ def stream(
|
||||
|
||||
|
||||
def encrypt_unauthenticated(
|
||||
message: Buffer,
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
message: Buffer,
|
||||
*,
|
||||
into: Buffer | None = None,
|
||||
) -> memoryview:
|
||||
"""Encrypt message without authentication (for testing/debugging).
|
||||
|
||||
Args:
|
||||
message: The plaintext message to encrypt.
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
message: The plaintext message to encrypt.
|
||||
into: Buffer to write ciphertext into (default: bytearray created).
|
||||
|
||||
Returns:
|
||||
@@ -356,17 +363,18 @@ def encrypt_unauthenticated(
|
||||
|
||||
|
||||
def decrypt_unauthenticated(
|
||||
ct: Buffer,
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
ct: Buffer,
|
||||
*,
|
||||
into: Buffer | None = None,
|
||||
) -> memoryview:
|
||||
"""Decrypt ciphertext without authentication (for testing/debugging).
|
||||
|
||||
Args:
|
||||
ct: The ciphertext to decrypt.
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
ct: The ciphertext to decrypt.
|
||||
into: Buffer to write plaintext into (default: bytearray created).
|
||||
|
||||
Returns:
|
||||
@@ -399,56 +407,56 @@ def decrypt_unauthenticated(
|
||||
|
||||
# This is missing from C API but convenient to have here
|
||||
def mac(
|
||||
data: Buffer,
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
data: Buffer,
|
||||
maclen: int = ABYTES_MIN,
|
||||
) -> memoryview:
|
||||
"""Compute a MAC for the given data in one shot.
|
||||
|
||||
Args:
|
||||
data: Data to MAC
|
||||
nonce: Nonce (32 bytes)
|
||||
key: Key (32 bytes)
|
||||
nonce: Nonce (32 bytes)
|
||||
data: Data to MAC
|
||||
maclen: MAC length (16 or 32, default 16)
|
||||
|
||||
Returns:
|
||||
MAC bytes
|
||||
"""
|
||||
mac_state = Mac(nonce, key)
|
||||
mac_state = Mac(key, nonce)
|
||||
mac_state.update(data)
|
||||
return mac_state.final(maclen)
|
||||
|
||||
|
||||
class Mac:
|
||||
"""AEGIS-256X4 MAC state wrapper.
|
||||
"""AEGIS-128X2 MAC state wrapper.
|
||||
|
||||
Usage:
|
||||
mac = Mac(nonce, key)
|
||||
mac = Mac(key, nonce)
|
||||
mac.update(data)
|
||||
tag = mac.final() # defaults to 16-byte MAC
|
||||
# or verify:
|
||||
mac2 = Mac(nonce, key); mac2.update(data); mac2.verify(tag)
|
||||
mac2 = Mac(key, nonce); mac2.update(data); mac2.verify(tag)
|
||||
"""
|
||||
|
||||
__slots__ = ("_st", "_nonce", "_key")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
_other=None,
|
||||
) -> None:
|
||||
"""Initialize a MAC state with a nonce and key.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
|
||||
Raises:
|
||||
TypeError: If key or nonce lengths are invalid.
|
||||
"""
|
||||
raw = alloc_aligned(ffi.sizeof("aegis128x2_mac_state"), 64)
|
||||
raw = alloc_aligned(ffi.sizeof("aegis128x2_mac_state"), ALIGNMENT)
|
||||
st = ffi.cast("aegis128x2_mac_state *", raw)
|
||||
self._st = ffi.gc(st, libc.free)
|
||||
if _other is not None:
|
||||
@@ -553,12 +561,12 @@ class Encryptor:
|
||||
|
||||
__slots__ = ("_st",)
|
||||
|
||||
def __init__(self, nonce: Buffer, key: Buffer, ad: Buffer | None = None):
|
||||
def __init__(self, key: Buffer, nonce: Buffer, ad: Buffer | None = None):
|
||||
"""Create an incremental encryptor.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
ad: Associated data to bind to the encryption (optional).
|
||||
|
||||
Raises:
|
||||
@@ -570,7 +578,7 @@ class Encryptor:
|
||||
raise TypeError(f"key length must be {KEYBYTES}")
|
||||
if nonce.nbytes != NPUBBYTES:
|
||||
raise TypeError(f"nonce length must be {NPUBBYTES}")
|
||||
raw = alloc_aligned(ffi.sizeof("aegis128x2_state"), 64)
|
||||
raw = alloc_aligned(ffi.sizeof("aegis128x2_state"), ALIGNMENT)
|
||||
st = ffi.cast("aegis128x2_state *", raw)
|
||||
st = ffi.gc(st, libc.free)
|
||||
_lib.aegis128x2_state_init(
|
||||
@@ -704,12 +712,12 @@ class Decryptor:
|
||||
|
||||
__slots__ = ("_st",)
|
||||
|
||||
def __init__(self, nonce: Buffer, key: Buffer, ad: Buffer | None = None):
|
||||
def __init__(self, key: Buffer, nonce: Buffer, ad: Buffer | None = None):
|
||||
"""Create an incremental decryptor for detached tags.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
ad: Associated data used during encryption (optional).
|
||||
|
||||
Raises:
|
||||
@@ -721,7 +729,7 @@ class Decryptor:
|
||||
raise TypeError(f"key length must be {KEYBYTES}")
|
||||
if nonce.nbytes != NPUBBYTES:
|
||||
raise TypeError(f"nonce length must be {NPUBBYTES}")
|
||||
raw = alloc_aligned(ffi.sizeof("aegis128x2_state"), 64)
|
||||
raw = alloc_aligned(ffi.sizeof("aegis128x2_state"), ALIGNMENT)
|
||||
st = ffi.cast("aegis128x2_state *", raw)
|
||||
st = ffi.gc(st, libc.free)
|
||||
_lib.aegis128x2_state_init(
|
||||
@@ -812,15 +820,15 @@ def new_state():
|
||||
|
||||
The returned object is an ffi cdata pointer with automatic finalizer.
|
||||
"""
|
||||
# Allocate with 64-byte alignment using libc.posix_memalign
|
||||
raw = alloc_aligned(ffi.sizeof("aegis128x2_state"), 64)
|
||||
# Allocate with required alignment using libc.posix_memalign
|
||||
raw = alloc_aligned(ffi.sizeof("aegis128x2_state"), ALIGNMENT)
|
||||
ptr = ffi.cast("aegis128x2_state *", raw)
|
||||
return ffi.gc(ptr, libc.free)
|
||||
|
||||
|
||||
def new_mac_state():
|
||||
"""Allocate and return a new aegis128x2_mac_state* with proper alignment."""
|
||||
raw = alloc_aligned(ffi.sizeof("aegis128x2_mac_state"), 64)
|
||||
raw = alloc_aligned(ffi.sizeof("aegis128x2_mac_state"), ALIGNMENT)
|
||||
ptr = ffi.cast("aegis128x2_mac_state *", raw)
|
||||
return ffi.gc(ptr, libc.free)
|
||||
|
||||
@@ -832,6 +840,7 @@ __all__ = [
|
||||
"ABYTES_MIN",
|
||||
"ABYTES_MAX",
|
||||
"TAILBYTES_MAX",
|
||||
"ALIGNMENT",
|
||||
# one-shot functions
|
||||
"encrypt_detached",
|
||||
"decrypt_detached",
|
||||
|
||||
@@ -18,6 +18,7 @@ NPUBBYTES = _lib.aegis128x4_npubbytes()
|
||||
ABYTES_MIN = _lib.aegis128x4_abytes_min()
|
||||
ABYTES_MAX = _lib.aegis128x4_abytes_max()
|
||||
TAILBYTES_MAX = _lib.aegis128x4_tailbytes_max()
|
||||
ALIGNMENT = 64
|
||||
|
||||
|
||||
def _ptr(buf):
|
||||
@@ -33,10 +34,11 @@ def _ptr(buf):
|
||||
|
||||
|
||||
def encrypt_detached(
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
message: Buffer,
|
||||
ad: Buffer | None = None,
|
||||
*,
|
||||
maclen: int = ABYTES_MIN,
|
||||
ct_into: Buffer | None = None,
|
||||
mac_into: Buffer | None = None,
|
||||
@@ -44,8 +46,8 @@ def encrypt_detached(
|
||||
"""Encrypt message with associated data, returning ciphertext and MAC separately.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
message: The plaintext message to encrypt.
|
||||
ad: Associated data (optional).
|
||||
maclen: MAC length (16 or 32, default 16).
|
||||
@@ -99,18 +101,19 @@ def encrypt_detached(
|
||||
|
||||
|
||||
def decrypt_detached(
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
ct: Buffer,
|
||||
mac: Buffer,
|
||||
ad: Buffer | None = None,
|
||||
*,
|
||||
into: Buffer | None = None,
|
||||
) -> memoryview:
|
||||
"""Decrypt ciphertext with detached MAC and associated data.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
ct: The ciphertext to decrypt.
|
||||
mac: The MAC to verify.
|
||||
ad: Associated data (optional).
|
||||
@@ -158,18 +161,19 @@ def decrypt_detached(
|
||||
|
||||
|
||||
def encrypt(
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
message: Buffer,
|
||||
ad: Buffer | None = None,
|
||||
*,
|
||||
maclen: int = ABYTES_MIN,
|
||||
into: Buffer | None = None,
|
||||
) -> memoryview:
|
||||
"""Encrypt message with associated data, returning ciphertext with appended MAC.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
message: The plaintext message to encrypt.
|
||||
ad: Associated data (optional).
|
||||
maclen: MAC length (16 or 32, default 16).
|
||||
@@ -216,18 +220,19 @@ def encrypt(
|
||||
|
||||
|
||||
def decrypt(
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
ct: Buffer,
|
||||
ad: Buffer | None = None,
|
||||
*,
|
||||
maclen: int = ABYTES_MIN,
|
||||
into: Buffer | None = None,
|
||||
) -> memoryview:
|
||||
"""Decrypt ciphertext with appended MAC and associated data.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
ct: The ciphertext with MAC to decrypt.
|
||||
ad: Associated data (optional).
|
||||
maclen: MAC length (16 or 32, default 16).
|
||||
@@ -274,16 +279,17 @@ def decrypt(
|
||||
|
||||
|
||||
def stream(
|
||||
nonce: Buffer | None,
|
||||
key: Buffer,
|
||||
nonce: Buffer | None,
|
||||
length: int | None = None,
|
||||
*,
|
||||
into: Buffer | None = None,
|
||||
) -> memoryview:
|
||||
"""Generate a stream of pseudorandom bytes.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes, uses zeroes for nonce if None).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes, uses zeroes for nonce if None).
|
||||
length: Number of bytes to generate (required if into is None).
|
||||
into: Buffer to write stream into (default: bytearray created).
|
||||
|
||||
@@ -314,17 +320,18 @@ def stream(
|
||||
|
||||
|
||||
def encrypt_unauthenticated(
|
||||
message: Buffer,
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
message: Buffer,
|
||||
*,
|
||||
into: Buffer | None = None,
|
||||
) -> memoryview:
|
||||
"""Encrypt message without authentication (for testing/debugging).
|
||||
|
||||
Args:
|
||||
message: The plaintext message to encrypt.
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
message: The plaintext message to encrypt.
|
||||
into: Buffer to write ciphertext into (default: bytearray created).
|
||||
|
||||
Returns:
|
||||
@@ -356,17 +363,18 @@ def encrypt_unauthenticated(
|
||||
|
||||
|
||||
def decrypt_unauthenticated(
|
||||
ct: Buffer,
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
ct: Buffer,
|
||||
*,
|
||||
into: Buffer | None = None,
|
||||
) -> memoryview:
|
||||
"""Decrypt ciphertext without authentication (for testing/debugging).
|
||||
|
||||
Args:
|
||||
ct: The ciphertext to decrypt.
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
ct: The ciphertext to decrypt.
|
||||
into: Buffer to write plaintext into (default: bytearray created).
|
||||
|
||||
Returns:
|
||||
@@ -399,56 +407,56 @@ def decrypt_unauthenticated(
|
||||
|
||||
# This is missing from C API but convenient to have here
|
||||
def mac(
|
||||
data: Buffer,
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
data: Buffer,
|
||||
maclen: int = ABYTES_MIN,
|
||||
) -> memoryview:
|
||||
"""Compute a MAC for the given data in one shot.
|
||||
|
||||
Args:
|
||||
data: Data to MAC
|
||||
nonce: Nonce (32 bytes)
|
||||
key: Key (32 bytes)
|
||||
nonce: Nonce (32 bytes)
|
||||
data: Data to MAC
|
||||
maclen: MAC length (16 or 32, default 16)
|
||||
|
||||
Returns:
|
||||
MAC bytes
|
||||
"""
|
||||
mac_state = Mac(nonce, key)
|
||||
mac_state = Mac(key, nonce)
|
||||
mac_state.update(data)
|
||||
return mac_state.final(maclen)
|
||||
|
||||
|
||||
class Mac:
|
||||
"""AEGIS-256X4 MAC state wrapper.
|
||||
"""AEGIS-128X4 MAC state wrapper.
|
||||
|
||||
Usage:
|
||||
mac = Mac(nonce, key)
|
||||
mac = Mac(key, nonce)
|
||||
mac.update(data)
|
||||
tag = mac.final() # defaults to 16-byte MAC
|
||||
# or verify:
|
||||
mac2 = Mac(nonce, key); mac2.update(data); mac2.verify(tag)
|
||||
mac2 = Mac(key, nonce); mac2.update(data); mac2.verify(tag)
|
||||
"""
|
||||
|
||||
__slots__ = ("_st", "_nonce", "_key")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
_other=None,
|
||||
) -> None:
|
||||
"""Initialize a MAC state with a nonce and key.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
|
||||
Raises:
|
||||
TypeError: If key or nonce lengths are invalid.
|
||||
"""
|
||||
raw = alloc_aligned(ffi.sizeof("aegis128x4_mac_state"), 64)
|
||||
raw = alloc_aligned(ffi.sizeof("aegis128x4_mac_state"), ALIGNMENT)
|
||||
st = ffi.cast("aegis128x4_mac_state *", raw)
|
||||
self._st = ffi.gc(st, libc.free)
|
||||
if _other is not None:
|
||||
@@ -553,12 +561,12 @@ class Encryptor:
|
||||
|
||||
__slots__ = ("_st",)
|
||||
|
||||
def __init__(self, nonce: Buffer, key: Buffer, ad: Buffer | None = None):
|
||||
def __init__(self, key: Buffer, nonce: Buffer, ad: Buffer | None = None):
|
||||
"""Create an incremental encryptor.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
ad: Associated data to bind to the encryption (optional).
|
||||
|
||||
Raises:
|
||||
@@ -570,7 +578,7 @@ class Encryptor:
|
||||
raise TypeError(f"key length must be {KEYBYTES}")
|
||||
if nonce.nbytes != NPUBBYTES:
|
||||
raise TypeError(f"nonce length must be {NPUBBYTES}")
|
||||
raw = alloc_aligned(ffi.sizeof("aegis128x4_state"), 64)
|
||||
raw = alloc_aligned(ffi.sizeof("aegis128x4_state"), ALIGNMENT)
|
||||
st = ffi.cast("aegis128x4_state *", raw)
|
||||
st = ffi.gc(st, libc.free)
|
||||
_lib.aegis128x4_state_init(
|
||||
@@ -704,12 +712,12 @@ class Decryptor:
|
||||
|
||||
__slots__ = ("_st",)
|
||||
|
||||
def __init__(self, nonce: Buffer, key: Buffer, ad: Buffer | None = None):
|
||||
def __init__(self, key: Buffer, nonce: Buffer, ad: Buffer | None = None):
|
||||
"""Create an incremental decryptor for detached tags.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
ad: Associated data used during encryption (optional).
|
||||
|
||||
Raises:
|
||||
@@ -721,7 +729,7 @@ class Decryptor:
|
||||
raise TypeError(f"key length must be {KEYBYTES}")
|
||||
if nonce.nbytes != NPUBBYTES:
|
||||
raise TypeError(f"nonce length must be {NPUBBYTES}")
|
||||
raw = alloc_aligned(ffi.sizeof("aegis128x4_state"), 64)
|
||||
raw = alloc_aligned(ffi.sizeof("aegis128x4_state"), ALIGNMENT)
|
||||
st = ffi.cast("aegis128x4_state *", raw)
|
||||
st = ffi.gc(st, libc.free)
|
||||
_lib.aegis128x4_state_init(
|
||||
@@ -812,15 +820,15 @@ def new_state():
|
||||
|
||||
The returned object is an ffi cdata pointer with automatic finalizer.
|
||||
"""
|
||||
# Allocate with 64-byte alignment using libc.posix_memalign
|
||||
raw = alloc_aligned(ffi.sizeof("aegis128x4_state"), 64)
|
||||
# Allocate with required alignment using libc.posix_memalign
|
||||
raw = alloc_aligned(ffi.sizeof("aegis128x4_state"), ALIGNMENT)
|
||||
ptr = ffi.cast("aegis128x4_state *", raw)
|
||||
return ffi.gc(ptr, libc.free)
|
||||
|
||||
|
||||
def new_mac_state():
|
||||
"""Allocate and return a new aegis128x4_mac_state* with proper alignment."""
|
||||
raw = alloc_aligned(ffi.sizeof("aegis128x4_mac_state"), 64)
|
||||
raw = alloc_aligned(ffi.sizeof("aegis128x4_mac_state"), ALIGNMENT)
|
||||
ptr = ffi.cast("aegis128x4_mac_state *", raw)
|
||||
return ffi.gc(ptr, libc.free)
|
||||
|
||||
@@ -832,6 +840,7 @@ __all__ = [
|
||||
"ABYTES_MIN",
|
||||
"ABYTES_MAX",
|
||||
"TAILBYTES_MAX",
|
||||
"ALIGNMENT",
|
||||
# one-shot functions
|
||||
"encrypt_detached",
|
||||
"decrypt_detached",
|
||||
|
||||
@@ -18,6 +18,7 @@ NPUBBYTES = _lib.aegis256_npubbytes()
|
||||
ABYTES_MIN = _lib.aegis256_abytes_min()
|
||||
ABYTES_MAX = _lib.aegis256_abytes_max()
|
||||
TAILBYTES_MAX = _lib.aegis256_tailbytes_max()
|
||||
ALIGNMENT = 16
|
||||
|
||||
|
||||
def _ptr(buf):
|
||||
@@ -33,10 +34,11 @@ def _ptr(buf):
|
||||
|
||||
|
||||
def encrypt_detached(
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
message: Buffer,
|
||||
ad: Buffer | None = None,
|
||||
*,
|
||||
maclen: int = ABYTES_MIN,
|
||||
ct_into: Buffer | None = None,
|
||||
mac_into: Buffer | None = None,
|
||||
@@ -44,8 +46,8 @@ def encrypt_detached(
|
||||
"""Encrypt message with associated data, returning ciphertext and MAC separately.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
message: The plaintext message to encrypt.
|
||||
ad: Associated data (optional).
|
||||
maclen: MAC length (16 or 32, default 16).
|
||||
@@ -99,18 +101,19 @@ def encrypt_detached(
|
||||
|
||||
|
||||
def decrypt_detached(
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
ct: Buffer,
|
||||
mac: Buffer,
|
||||
ad: Buffer | None = None,
|
||||
*,
|
||||
into: Buffer | None = None,
|
||||
) -> memoryview:
|
||||
"""Decrypt ciphertext with detached MAC and associated data.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
ct: The ciphertext to decrypt.
|
||||
mac: The MAC to verify.
|
||||
ad: Associated data (optional).
|
||||
@@ -158,18 +161,19 @@ def decrypt_detached(
|
||||
|
||||
|
||||
def encrypt(
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
message: Buffer,
|
||||
ad: Buffer | None = None,
|
||||
*,
|
||||
maclen: int = ABYTES_MIN,
|
||||
into: Buffer | None = None,
|
||||
) -> memoryview:
|
||||
"""Encrypt message with associated data, returning ciphertext with appended MAC.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
message: The plaintext message to encrypt.
|
||||
ad: Associated data (optional).
|
||||
maclen: MAC length (16 or 32, default 16).
|
||||
@@ -216,18 +220,19 @@ def encrypt(
|
||||
|
||||
|
||||
def decrypt(
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
ct: Buffer,
|
||||
ad: Buffer | None = None,
|
||||
*,
|
||||
maclen: int = ABYTES_MIN,
|
||||
into: Buffer | None = None,
|
||||
) -> memoryview:
|
||||
"""Decrypt ciphertext with appended MAC and associated data.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
ct: The ciphertext with MAC to decrypt.
|
||||
ad: Associated data (optional).
|
||||
maclen: MAC length (16 or 32, default 16).
|
||||
@@ -274,16 +279,17 @@ def decrypt(
|
||||
|
||||
|
||||
def stream(
|
||||
nonce: Buffer | None,
|
||||
key: Buffer,
|
||||
nonce: Buffer | None,
|
||||
length: int | None = None,
|
||||
*,
|
||||
into: Buffer | None = None,
|
||||
) -> memoryview:
|
||||
"""Generate a stream of pseudorandom bytes.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes, uses zeroes for nonce if None).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes, uses zeroes for nonce if None).
|
||||
length: Number of bytes to generate (required if into is None).
|
||||
into: Buffer to write stream into (default: bytearray created).
|
||||
|
||||
@@ -314,17 +320,18 @@ def stream(
|
||||
|
||||
|
||||
def encrypt_unauthenticated(
|
||||
message: Buffer,
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
message: Buffer,
|
||||
*,
|
||||
into: Buffer | None = None,
|
||||
) -> memoryview:
|
||||
"""Encrypt message without authentication (for testing/debugging).
|
||||
|
||||
Args:
|
||||
message: The plaintext message to encrypt.
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
message: The plaintext message to encrypt.
|
||||
into: Buffer to write ciphertext into (default: bytearray created).
|
||||
|
||||
Returns:
|
||||
@@ -356,17 +363,18 @@ def encrypt_unauthenticated(
|
||||
|
||||
|
||||
def decrypt_unauthenticated(
|
||||
ct: Buffer,
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
ct: Buffer,
|
||||
*,
|
||||
into: Buffer | None = None,
|
||||
) -> memoryview:
|
||||
"""Decrypt ciphertext without authentication (for testing/debugging).
|
||||
|
||||
Args:
|
||||
ct: The ciphertext to decrypt.
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
ct: The ciphertext to decrypt.
|
||||
into: Buffer to write plaintext into (default: bytearray created).
|
||||
|
||||
Returns:
|
||||
@@ -399,56 +407,56 @@ def decrypt_unauthenticated(
|
||||
|
||||
# This is missing from C API but convenient to have here
|
||||
def mac(
|
||||
data: Buffer,
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
data: Buffer,
|
||||
maclen: int = ABYTES_MIN,
|
||||
) -> memoryview:
|
||||
"""Compute a MAC for the given data in one shot.
|
||||
|
||||
Args:
|
||||
data: Data to MAC
|
||||
nonce: Nonce (32 bytes)
|
||||
key: Key (32 bytes)
|
||||
nonce: Nonce (32 bytes)
|
||||
data: Data to MAC
|
||||
maclen: MAC length (16 or 32, default 16)
|
||||
|
||||
Returns:
|
||||
MAC bytes
|
||||
"""
|
||||
mac_state = Mac(nonce, key)
|
||||
mac_state = Mac(key, nonce)
|
||||
mac_state.update(data)
|
||||
return mac_state.final(maclen)
|
||||
|
||||
|
||||
class Mac:
|
||||
"""AEGIS-256X4 MAC state wrapper.
|
||||
"""AEGIS-256 MAC state wrapper.
|
||||
|
||||
Usage:
|
||||
mac = Mac(nonce, key)
|
||||
mac = Mac(key, nonce)
|
||||
mac.update(data)
|
||||
tag = mac.final() # defaults to 16-byte MAC
|
||||
# or verify:
|
||||
mac2 = Mac(nonce, key); mac2.update(data); mac2.verify(tag)
|
||||
mac2 = Mac(key, nonce); mac2.update(data); mac2.verify(tag)
|
||||
"""
|
||||
|
||||
__slots__ = ("_st", "_nonce", "_key")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
_other=None,
|
||||
) -> None:
|
||||
"""Initialize a MAC state with a nonce and key.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
|
||||
Raises:
|
||||
TypeError: If key or nonce lengths are invalid.
|
||||
"""
|
||||
raw = alloc_aligned(ffi.sizeof("aegis256_mac_state"), 16)
|
||||
raw = alloc_aligned(ffi.sizeof("aegis256_mac_state"), ALIGNMENT)
|
||||
st = ffi.cast("aegis256_mac_state *", raw)
|
||||
self._st = ffi.gc(st, libc.free)
|
||||
if _other is not None:
|
||||
@@ -553,12 +561,12 @@ class Encryptor:
|
||||
|
||||
__slots__ = ("_st",)
|
||||
|
||||
def __init__(self, nonce: Buffer, key: Buffer, ad: Buffer | None = None):
|
||||
def __init__(self, key: Buffer, nonce: Buffer, ad: Buffer | None = None):
|
||||
"""Create an incremental encryptor.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
ad: Associated data to bind to the encryption (optional).
|
||||
|
||||
Raises:
|
||||
@@ -570,7 +578,7 @@ class Encryptor:
|
||||
raise TypeError(f"key length must be {KEYBYTES}")
|
||||
if nonce.nbytes != NPUBBYTES:
|
||||
raise TypeError(f"nonce length must be {NPUBBYTES}")
|
||||
raw = alloc_aligned(ffi.sizeof("aegis256_state"), 16)
|
||||
raw = alloc_aligned(ffi.sizeof("aegis256_state"), ALIGNMENT)
|
||||
st = ffi.cast("aegis256_state *", raw)
|
||||
st = ffi.gc(st, libc.free)
|
||||
_lib.aegis256_state_init(
|
||||
@@ -704,12 +712,12 @@ class Decryptor:
|
||||
|
||||
__slots__ = ("_st",)
|
||||
|
||||
def __init__(self, nonce: Buffer, key: Buffer, ad: Buffer | None = None):
|
||||
def __init__(self, key: Buffer, nonce: Buffer, ad: Buffer | None = None):
|
||||
"""Create an incremental decryptor for detached tags.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
ad: Associated data used during encryption (optional).
|
||||
|
||||
Raises:
|
||||
@@ -721,7 +729,7 @@ class Decryptor:
|
||||
raise TypeError(f"key length must be {KEYBYTES}")
|
||||
if nonce.nbytes != NPUBBYTES:
|
||||
raise TypeError(f"nonce length must be {NPUBBYTES}")
|
||||
raw = alloc_aligned(ffi.sizeof("aegis256_state"), 16)
|
||||
raw = alloc_aligned(ffi.sizeof("aegis256_state"), ALIGNMENT)
|
||||
st = ffi.cast("aegis256_state *", raw)
|
||||
st = ffi.gc(st, libc.free)
|
||||
_lib.aegis256_state_init(
|
||||
@@ -812,15 +820,15 @@ def new_state():
|
||||
|
||||
The returned object is an ffi cdata pointer with automatic finalizer.
|
||||
"""
|
||||
# Allocate with 64-byte alignment using libc.posix_memalign
|
||||
raw = alloc_aligned(ffi.sizeof("aegis256_state"), 16)
|
||||
# Allocate with required alignment using libc.posix_memalign
|
||||
raw = alloc_aligned(ffi.sizeof("aegis256_state"), ALIGNMENT)
|
||||
ptr = ffi.cast("aegis256_state *", raw)
|
||||
return ffi.gc(ptr, libc.free)
|
||||
|
||||
|
||||
def new_mac_state():
|
||||
"""Allocate and return a new aegis256_mac_state* with proper alignment."""
|
||||
raw = alloc_aligned(ffi.sizeof("aegis256_mac_state"), 16)
|
||||
raw = alloc_aligned(ffi.sizeof("aegis256_mac_state"), ALIGNMENT)
|
||||
ptr = ffi.cast("aegis256_mac_state *", raw)
|
||||
return ffi.gc(ptr, libc.free)
|
||||
|
||||
@@ -832,6 +840,7 @@ __all__ = [
|
||||
"ABYTES_MIN",
|
||||
"ABYTES_MAX",
|
||||
"TAILBYTES_MAX",
|
||||
"ALIGNMENT",
|
||||
# one-shot functions
|
||||
"encrypt_detached",
|
||||
"decrypt_detached",
|
||||
|
||||
@@ -18,6 +18,7 @@ NPUBBYTES = _lib.aegis256x2_npubbytes()
|
||||
ABYTES_MIN = _lib.aegis256x2_abytes_min()
|
||||
ABYTES_MAX = _lib.aegis256x2_abytes_max()
|
||||
TAILBYTES_MAX = _lib.aegis256x2_tailbytes_max()
|
||||
ALIGNMENT = 32
|
||||
|
||||
|
||||
def _ptr(buf):
|
||||
@@ -33,10 +34,11 @@ def _ptr(buf):
|
||||
|
||||
|
||||
def encrypt_detached(
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
message: Buffer,
|
||||
ad: Buffer | None = None,
|
||||
*,
|
||||
maclen: int = ABYTES_MIN,
|
||||
ct_into: Buffer | None = None,
|
||||
mac_into: Buffer | None = None,
|
||||
@@ -44,8 +46,8 @@ def encrypt_detached(
|
||||
"""Encrypt message with associated data, returning ciphertext and MAC separately.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
message: The plaintext message to encrypt.
|
||||
ad: Associated data (optional).
|
||||
maclen: MAC length (16 or 32, default 16).
|
||||
@@ -99,18 +101,19 @@ def encrypt_detached(
|
||||
|
||||
|
||||
def decrypt_detached(
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
ct: Buffer,
|
||||
mac: Buffer,
|
||||
ad: Buffer | None = None,
|
||||
*,
|
||||
into: Buffer | None = None,
|
||||
) -> memoryview:
|
||||
"""Decrypt ciphertext with detached MAC and associated data.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
ct: The ciphertext to decrypt.
|
||||
mac: The MAC to verify.
|
||||
ad: Associated data (optional).
|
||||
@@ -158,18 +161,19 @@ def decrypt_detached(
|
||||
|
||||
|
||||
def encrypt(
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
message: Buffer,
|
||||
ad: Buffer | None = None,
|
||||
*,
|
||||
maclen: int = ABYTES_MIN,
|
||||
into: Buffer | None = None,
|
||||
) -> memoryview:
|
||||
"""Encrypt message with associated data, returning ciphertext with appended MAC.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
message: The plaintext message to encrypt.
|
||||
ad: Associated data (optional).
|
||||
maclen: MAC length (16 or 32, default 16).
|
||||
@@ -216,18 +220,19 @@ def encrypt(
|
||||
|
||||
|
||||
def decrypt(
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
ct: Buffer,
|
||||
ad: Buffer | None = None,
|
||||
*,
|
||||
maclen: int = ABYTES_MIN,
|
||||
into: Buffer | None = None,
|
||||
) -> memoryview:
|
||||
"""Decrypt ciphertext with appended MAC and associated data.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
ct: The ciphertext with MAC to decrypt.
|
||||
ad: Associated data (optional).
|
||||
maclen: MAC length (16 or 32, default 16).
|
||||
@@ -274,16 +279,17 @@ def decrypt(
|
||||
|
||||
|
||||
def stream(
|
||||
nonce: Buffer | None,
|
||||
key: Buffer,
|
||||
nonce: Buffer | None,
|
||||
length: int | None = None,
|
||||
*,
|
||||
into: Buffer | None = None,
|
||||
) -> memoryview:
|
||||
"""Generate a stream of pseudorandom bytes.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes, uses zeroes for nonce if None).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes, uses zeroes for nonce if None).
|
||||
length: Number of bytes to generate (required if into is None).
|
||||
into: Buffer to write stream into (default: bytearray created).
|
||||
|
||||
@@ -314,17 +320,18 @@ def stream(
|
||||
|
||||
|
||||
def encrypt_unauthenticated(
|
||||
message: Buffer,
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
message: Buffer,
|
||||
*,
|
||||
into: Buffer | None = None,
|
||||
) -> memoryview:
|
||||
"""Encrypt message without authentication (for testing/debugging).
|
||||
|
||||
Args:
|
||||
message: The plaintext message to encrypt.
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
message: The plaintext message to encrypt.
|
||||
into: Buffer to write ciphertext into (default: bytearray created).
|
||||
|
||||
Returns:
|
||||
@@ -356,17 +363,18 @@ def encrypt_unauthenticated(
|
||||
|
||||
|
||||
def decrypt_unauthenticated(
|
||||
ct: Buffer,
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
ct: Buffer,
|
||||
*,
|
||||
into: Buffer | None = None,
|
||||
) -> memoryview:
|
||||
"""Decrypt ciphertext without authentication (for testing/debugging).
|
||||
|
||||
Args:
|
||||
ct: The ciphertext to decrypt.
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
ct: The ciphertext to decrypt.
|
||||
into: Buffer to write plaintext into (default: bytearray created).
|
||||
|
||||
Returns:
|
||||
@@ -399,56 +407,56 @@ def decrypt_unauthenticated(
|
||||
|
||||
# This is missing from C API but convenient to have here
|
||||
def mac(
|
||||
data: Buffer,
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
data: Buffer,
|
||||
maclen: int = ABYTES_MIN,
|
||||
) -> memoryview:
|
||||
"""Compute a MAC for the given data in one shot.
|
||||
|
||||
Args:
|
||||
data: Data to MAC
|
||||
nonce: Nonce (32 bytes)
|
||||
key: Key (32 bytes)
|
||||
nonce: Nonce (32 bytes)
|
||||
data: Data to MAC
|
||||
maclen: MAC length (16 or 32, default 16)
|
||||
|
||||
Returns:
|
||||
MAC bytes
|
||||
"""
|
||||
mac_state = Mac(nonce, key)
|
||||
mac_state = Mac(key, nonce)
|
||||
mac_state.update(data)
|
||||
return mac_state.final(maclen)
|
||||
|
||||
|
||||
class Mac:
|
||||
"""AEGIS-256X4 MAC state wrapper.
|
||||
"""AEGIS-256X2 MAC state wrapper.
|
||||
|
||||
Usage:
|
||||
mac = Mac(nonce, key)
|
||||
mac = Mac(key, nonce)
|
||||
mac.update(data)
|
||||
tag = mac.final() # defaults to 16-byte MAC
|
||||
# or verify:
|
||||
mac2 = Mac(nonce, key); mac2.update(data); mac2.verify(tag)
|
||||
mac2 = Mac(key, nonce); mac2.update(data); mac2.verify(tag)
|
||||
"""
|
||||
|
||||
__slots__ = ("_st", "_nonce", "_key")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
_other=None,
|
||||
) -> None:
|
||||
"""Initialize a MAC state with a nonce and key.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
|
||||
Raises:
|
||||
TypeError: If key or nonce lengths are invalid.
|
||||
"""
|
||||
raw = alloc_aligned(ffi.sizeof("aegis256x2_mac_state"), 32)
|
||||
raw = alloc_aligned(ffi.sizeof("aegis256x2_mac_state"), ALIGNMENT)
|
||||
st = ffi.cast("aegis256x2_mac_state *", raw)
|
||||
self._st = ffi.gc(st, libc.free)
|
||||
if _other is not None:
|
||||
@@ -553,12 +561,12 @@ class Encryptor:
|
||||
|
||||
__slots__ = ("_st",)
|
||||
|
||||
def __init__(self, nonce: Buffer, key: Buffer, ad: Buffer | None = None):
|
||||
def __init__(self, key: Buffer, nonce: Buffer, ad: Buffer | None = None):
|
||||
"""Create an incremental encryptor.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
ad: Associated data to bind to the encryption (optional).
|
||||
|
||||
Raises:
|
||||
@@ -570,7 +578,7 @@ class Encryptor:
|
||||
raise TypeError(f"key length must be {KEYBYTES}")
|
||||
if nonce.nbytes != NPUBBYTES:
|
||||
raise TypeError(f"nonce length must be {NPUBBYTES}")
|
||||
raw = alloc_aligned(ffi.sizeof("aegis256x2_state"), 32)
|
||||
raw = alloc_aligned(ffi.sizeof("aegis256x2_state"), ALIGNMENT)
|
||||
st = ffi.cast("aegis256x2_state *", raw)
|
||||
st = ffi.gc(st, libc.free)
|
||||
_lib.aegis256x2_state_init(
|
||||
@@ -704,12 +712,12 @@ class Decryptor:
|
||||
|
||||
__slots__ = ("_st",)
|
||||
|
||||
def __init__(self, nonce: Buffer, key: Buffer, ad: Buffer | None = None):
|
||||
def __init__(self, key: Buffer, nonce: Buffer, ad: Buffer | None = None):
|
||||
"""Create an incremental decryptor for detached tags.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
ad: Associated data used during encryption (optional).
|
||||
|
||||
Raises:
|
||||
@@ -721,7 +729,7 @@ class Decryptor:
|
||||
raise TypeError(f"key length must be {KEYBYTES}")
|
||||
if nonce.nbytes != NPUBBYTES:
|
||||
raise TypeError(f"nonce length must be {NPUBBYTES}")
|
||||
raw = alloc_aligned(ffi.sizeof("aegis256x2_state"), 32)
|
||||
raw = alloc_aligned(ffi.sizeof("aegis256x2_state"), ALIGNMENT)
|
||||
st = ffi.cast("aegis256x2_state *", raw)
|
||||
st = ffi.gc(st, libc.free)
|
||||
_lib.aegis256x2_state_init(
|
||||
@@ -812,15 +820,15 @@ def new_state():
|
||||
|
||||
The returned object is an ffi cdata pointer with automatic finalizer.
|
||||
"""
|
||||
# Allocate with 64-byte alignment using libc.posix_memalign
|
||||
raw = alloc_aligned(ffi.sizeof("aegis256x2_state"), 32)
|
||||
# Allocate with required alignment using libc.posix_memalign
|
||||
raw = alloc_aligned(ffi.sizeof("aegis256x2_state"), ALIGNMENT)
|
||||
ptr = ffi.cast("aegis256x2_state *", raw)
|
||||
return ffi.gc(ptr, libc.free)
|
||||
|
||||
|
||||
def new_mac_state():
|
||||
"""Allocate and return a new aegis256x2_mac_state* with proper alignment."""
|
||||
raw = alloc_aligned(ffi.sizeof("aegis256x2_mac_state"), 32)
|
||||
raw = alloc_aligned(ffi.sizeof("aegis256x2_mac_state"), ALIGNMENT)
|
||||
ptr = ffi.cast("aegis256x2_mac_state *", raw)
|
||||
return ffi.gc(ptr, libc.free)
|
||||
|
||||
@@ -832,6 +840,7 @@ __all__ = [
|
||||
"ABYTES_MIN",
|
||||
"ABYTES_MAX",
|
||||
"TAILBYTES_MAX",
|
||||
"ALIGNMENT",
|
||||
# one-shot functions
|
||||
"encrypt_detached",
|
||||
"decrypt_detached",
|
||||
|
||||
@@ -18,6 +18,7 @@ NPUBBYTES = _lib.aegis256x4_npubbytes()
|
||||
ABYTES_MIN = _lib.aegis256x4_abytes_min()
|
||||
ABYTES_MAX = _lib.aegis256x4_abytes_max()
|
||||
TAILBYTES_MAX = _lib.aegis256x4_tailbytes_max()
|
||||
ALIGNMENT = 64
|
||||
|
||||
|
||||
def _ptr(buf):
|
||||
@@ -33,10 +34,11 @@ def _ptr(buf):
|
||||
|
||||
|
||||
def encrypt_detached(
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
message: Buffer,
|
||||
ad: Buffer | None = None,
|
||||
*,
|
||||
maclen: int = ABYTES_MIN,
|
||||
ct_into: Buffer | None = None,
|
||||
mac_into: Buffer | None = None,
|
||||
@@ -44,8 +46,8 @@ def encrypt_detached(
|
||||
"""Encrypt message with associated data, returning ciphertext and MAC separately.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
message: The plaintext message to encrypt.
|
||||
ad: Associated data (optional).
|
||||
maclen: MAC length (16 or 32, default 16).
|
||||
@@ -99,18 +101,19 @@ def encrypt_detached(
|
||||
|
||||
|
||||
def decrypt_detached(
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
ct: Buffer,
|
||||
mac: Buffer,
|
||||
ad: Buffer | None = None,
|
||||
*,
|
||||
into: Buffer | None = None,
|
||||
) -> memoryview:
|
||||
"""Decrypt ciphertext with detached MAC and associated data.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
ct: The ciphertext to decrypt.
|
||||
mac: The MAC to verify.
|
||||
ad: Associated data (optional).
|
||||
@@ -158,18 +161,19 @@ def decrypt_detached(
|
||||
|
||||
|
||||
def encrypt(
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
message: Buffer,
|
||||
ad: Buffer | None = None,
|
||||
*,
|
||||
maclen: int = ABYTES_MIN,
|
||||
into: Buffer | None = None,
|
||||
) -> memoryview:
|
||||
"""Encrypt message with associated data, returning ciphertext with appended MAC.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
message: The plaintext message to encrypt.
|
||||
ad: Associated data (optional).
|
||||
maclen: MAC length (16 or 32, default 16).
|
||||
@@ -216,18 +220,19 @@ def encrypt(
|
||||
|
||||
|
||||
def decrypt(
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
ct: Buffer,
|
||||
ad: Buffer | None = None,
|
||||
*,
|
||||
maclen: int = ABYTES_MIN,
|
||||
into: Buffer | None = None,
|
||||
) -> memoryview:
|
||||
"""Decrypt ciphertext with appended MAC and associated data.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
ct: The ciphertext with MAC to decrypt.
|
||||
ad: Associated data (optional).
|
||||
maclen: MAC length (16 or 32, default 16).
|
||||
@@ -274,16 +279,17 @@ def decrypt(
|
||||
|
||||
|
||||
def stream(
|
||||
nonce: Buffer | None,
|
||||
key: Buffer,
|
||||
nonce: Buffer | None,
|
||||
length: int | None = None,
|
||||
*,
|
||||
into: Buffer | None = None,
|
||||
) -> memoryview:
|
||||
"""Generate a stream of pseudorandom bytes.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes, uses zeroes for nonce if None).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes, uses zeroes for nonce if None).
|
||||
length: Number of bytes to generate (required if into is None).
|
||||
into: Buffer to write stream into (default: bytearray created).
|
||||
|
||||
@@ -314,17 +320,18 @@ def stream(
|
||||
|
||||
|
||||
def encrypt_unauthenticated(
|
||||
message: Buffer,
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
message: Buffer,
|
||||
*,
|
||||
into: Buffer | None = None,
|
||||
) -> memoryview:
|
||||
"""Encrypt message without authentication (for testing/debugging).
|
||||
|
||||
Args:
|
||||
message: The plaintext message to encrypt.
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
message: The plaintext message to encrypt.
|
||||
into: Buffer to write ciphertext into (default: bytearray created).
|
||||
|
||||
Returns:
|
||||
@@ -356,17 +363,18 @@ def encrypt_unauthenticated(
|
||||
|
||||
|
||||
def decrypt_unauthenticated(
|
||||
ct: Buffer,
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
ct: Buffer,
|
||||
*,
|
||||
into: Buffer | None = None,
|
||||
) -> memoryview:
|
||||
"""Decrypt ciphertext without authentication (for testing/debugging).
|
||||
|
||||
Args:
|
||||
ct: The ciphertext to decrypt.
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
ct: The ciphertext to decrypt.
|
||||
into: Buffer to write plaintext into (default: bytearray created).
|
||||
|
||||
Returns:
|
||||
@@ -399,23 +407,23 @@ def decrypt_unauthenticated(
|
||||
|
||||
# This is missing from C API but convenient to have here
|
||||
def mac(
|
||||
data: Buffer,
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
data: Buffer,
|
||||
maclen: int = ABYTES_MIN,
|
||||
) -> memoryview:
|
||||
"""Compute a MAC for the given data in one shot.
|
||||
|
||||
Args:
|
||||
data: Data to MAC
|
||||
nonce: Nonce (32 bytes)
|
||||
key: Key (32 bytes)
|
||||
nonce: Nonce (32 bytes)
|
||||
data: Data to MAC
|
||||
maclen: MAC length (16 or 32, default 16)
|
||||
|
||||
Returns:
|
||||
MAC bytes
|
||||
"""
|
||||
mac_state = Mac(nonce, key)
|
||||
mac_state = Mac(key, nonce)
|
||||
mac_state.update(data)
|
||||
return mac_state.final(maclen)
|
||||
|
||||
@@ -424,31 +432,31 @@ class Mac:
|
||||
"""AEGIS-256X4 MAC state wrapper.
|
||||
|
||||
Usage:
|
||||
mac = Mac(nonce, key)
|
||||
mac = Mac(key, nonce)
|
||||
mac.update(data)
|
||||
tag = mac.final() # defaults to 16-byte MAC
|
||||
# or verify:
|
||||
mac2 = Mac(nonce, key); mac2.update(data); mac2.verify(tag)
|
||||
mac2 = Mac(key, nonce); mac2.update(data); mac2.verify(tag)
|
||||
"""
|
||||
|
||||
__slots__ = ("_st", "_nonce", "_key")
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
nonce: Buffer,
|
||||
key: Buffer,
|
||||
nonce: Buffer,
|
||||
_other=None,
|
||||
) -> None:
|
||||
"""Initialize a MAC state with a nonce and key.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
|
||||
Raises:
|
||||
TypeError: If key or nonce lengths are invalid.
|
||||
"""
|
||||
raw = alloc_aligned(ffi.sizeof("aegis256x4_mac_state"), 64)
|
||||
raw = alloc_aligned(ffi.sizeof("aegis256x4_mac_state"), ALIGNMENT)
|
||||
st = ffi.cast("aegis256x4_mac_state *", raw)
|
||||
self._st = ffi.gc(st, libc.free)
|
||||
if _other is not None:
|
||||
@@ -553,12 +561,12 @@ class Encryptor:
|
||||
|
||||
__slots__ = ("_st",)
|
||||
|
||||
def __init__(self, nonce: Buffer, key: Buffer, ad: Buffer | None = None):
|
||||
def __init__(self, key: Buffer, nonce: Buffer, ad: Buffer | None = None):
|
||||
"""Create an incremental encryptor.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
ad: Associated data to bind to the encryption (optional).
|
||||
|
||||
Raises:
|
||||
@@ -570,7 +578,7 @@ class Encryptor:
|
||||
raise TypeError(f"key length must be {KEYBYTES}")
|
||||
if nonce.nbytes != NPUBBYTES:
|
||||
raise TypeError(f"nonce length must be {NPUBBYTES}")
|
||||
raw = alloc_aligned(ffi.sizeof("aegis256x4_state"), 64)
|
||||
raw = alloc_aligned(ffi.sizeof("aegis256x4_state"), ALIGNMENT)
|
||||
st = ffi.cast("aegis256x4_state *", raw)
|
||||
st = ffi.gc(st, libc.free)
|
||||
_lib.aegis256x4_state_init(
|
||||
@@ -704,12 +712,12 @@ class Decryptor:
|
||||
|
||||
__slots__ = ("_st",)
|
||||
|
||||
def __init__(self, nonce: Buffer, key: Buffer, ad: Buffer | None = None):
|
||||
def __init__(self, key: Buffer, nonce: Buffer, ad: Buffer | None = None):
|
||||
"""Create an incremental decryptor for detached tags.
|
||||
|
||||
Args:
|
||||
nonce: Nonce (32 bytes).
|
||||
key: Key (32 bytes).
|
||||
nonce: Nonce (32 bytes).
|
||||
ad: Associated data used during encryption (optional).
|
||||
|
||||
Raises:
|
||||
@@ -721,7 +729,7 @@ class Decryptor:
|
||||
raise TypeError(f"key length must be {KEYBYTES}")
|
||||
if nonce.nbytes != NPUBBYTES:
|
||||
raise TypeError(f"nonce length must be {NPUBBYTES}")
|
||||
raw = alloc_aligned(ffi.sizeof("aegis256x4_state"), 64)
|
||||
raw = alloc_aligned(ffi.sizeof("aegis256x4_state"), ALIGNMENT)
|
||||
st = ffi.cast("aegis256x4_state *", raw)
|
||||
st = ffi.gc(st, libc.free)
|
||||
_lib.aegis256x4_state_init(
|
||||
@@ -812,15 +820,15 @@ def new_state():
|
||||
|
||||
The returned object is an ffi cdata pointer with automatic finalizer.
|
||||
"""
|
||||
# Allocate with 64-byte alignment using libc.posix_memalign
|
||||
raw = alloc_aligned(ffi.sizeof("aegis256x4_state"), 64)
|
||||
# Allocate with required alignment using libc.posix_memalign
|
||||
raw = alloc_aligned(ffi.sizeof("aegis256x4_state"), ALIGNMENT)
|
||||
ptr = ffi.cast("aegis256x4_state *", raw)
|
||||
return ffi.gc(ptr, libc.free)
|
||||
|
||||
|
||||
def new_mac_state():
|
||||
"""Allocate and return a new aegis256x4_mac_state* with proper alignment."""
|
||||
raw = alloc_aligned(ffi.sizeof("aegis256x4_mac_state"), 64)
|
||||
raw = alloc_aligned(ffi.sizeof("aegis256x4_mac_state"), ALIGNMENT)
|
||||
ptr = ffi.cast("aegis256x4_mac_state *", raw)
|
||||
return ffi.gc(ptr, libc.free)
|
||||
|
||||
@@ -832,6 +840,7 @@ __all__ = [
|
||||
"ABYTES_MIN",
|
||||
"ABYTES_MAX",
|
||||
"TAILBYTES_MAX",
|
||||
"ALIGNMENT",
|
||||
# one-shot functions
|
||||
"encrypt_detached",
|
||||
"decrypt_detached",
|
||||
|
||||
@@ -30,9 +30,9 @@ def demo():
|
||||
|
||||
# Detached encrypt/decrypt
|
||||
ciphertext, mac = a.encrypt_detached(
|
||||
nonce, key, message, associated_data, maclen=16
|
||||
key, nonce, message, associated_data, maclen=16
|
||||
)
|
||||
plaintext = a.decrypt_detached(nonce, key, ciphertext, mac, associated_data)
|
||||
plaintext = a.decrypt_detached(key, nonce, ciphertext, mac, associated_data)
|
||||
print(
|
||||
"detached enc: c=",
|
||||
hx(ciphertext),
|
||||
@@ -43,30 +43,30 @@ def demo():
|
||||
)
|
||||
|
||||
# Attached encrypt/decrypt
|
||||
ciphertext_with_tag = a.encrypt(nonce, key, message, associated_data, maclen=32)
|
||||
plaintext2 = a.decrypt(nonce, key, ciphertext_with_tag, associated_data, maclen=32)
|
||||
ciphertext_with_tag = a.encrypt(key, nonce, message, associated_data, maclen=32)
|
||||
plaintext2 = a.decrypt(key, nonce, ciphertext_with_tag, associated_data, maclen=32)
|
||||
print(
|
||||
"attached enc: ct=", hx(ciphertext_with_tag), " dec_ok=", plaintext2 == message
|
||||
)
|
||||
|
||||
# Stream generation (None nonce allowed) -> deterministic for a given key
|
||||
stream = bytearray(64)
|
||||
a.stream(None, key, into=stream)
|
||||
a.stream(key, None, into=stream)
|
||||
print("stream (first 16 bytes):", hx(stream, 16))
|
||||
|
||||
# Unauthenticated mode round-trip (INSECURE; compatibility only)
|
||||
c2 = bytearray(len(message))
|
||||
a.encrypt_unauthenticated(message, nonce, key, into=c2)
|
||||
a.encrypt_unauthenticated(key, nonce, message, into=c2)
|
||||
m2 = bytearray(len(message))
|
||||
a.decrypt_unauthenticated(c2, nonce, key, into=m2)
|
||||
a.decrypt_unauthenticated(key, nonce, c2, into=m2)
|
||||
print("unauth round-trip ok:", bytes(m2) == message)
|
||||
|
||||
# MAC: compute then verify
|
||||
mac_state = a.Mac(nonce, key)
|
||||
mac_state = a.Mac(key, nonce)
|
||||
mac_state.update(message)
|
||||
mac32 = mac_state.final(32)
|
||||
|
||||
mac_verify_state = a.Mac(nonce, key)
|
||||
mac_verify_state = a.Mac(key, nonce)
|
||||
mac_verify_state.update(message)
|
||||
try:
|
||||
mac_verify_state.verify(mac32)
|
||||
@@ -81,7 +81,7 @@ def demo():
|
||||
src = bytearray(total)
|
||||
dst = bytearray(total)
|
||||
t0 = time.perf_counter()
|
||||
a.encrypt_unauthenticated(src, nonce, key, into=dst)
|
||||
a.encrypt_unauthenticated(key, nonce, src, into=dst)
|
||||
t1 = time.perf_counter()
|
||||
secs = t1 - t0
|
||||
gib = total / float(1 << 30)
|
||||
|
||||
@@ -45,7 +45,7 @@ def bench_encrypt(alg_name: str, a) -> None:
|
||||
|
||||
t0 = time.perf_counter()
|
||||
for _ in range(ITERATIONS):
|
||||
a.encrypt(nonce, key, mview, None, maclen=maclen, into=buf)
|
||||
a.encrypt(key, nonce, mview, None, maclen=maclen, into=buf)
|
||||
t1 = time.perf_counter()
|
||||
|
||||
# Prevent any unrealistic optimization assumptions
|
||||
@@ -66,7 +66,7 @@ def bench_mac(alg_name: str, a) -> None:
|
||||
buf = bytearray(MSG_LEN)
|
||||
buf[:] = _random_bytes(len(buf))
|
||||
|
||||
mac0 = a.Mac(nonce, key)
|
||||
mac0 = a.Mac(key, nonce)
|
||||
mac_out = bytearray(a.ABYTES_MAX)
|
||||
|
||||
t0 = time.perf_counter()
|
||||
|
||||
107
tools/gen_modules.py
Normal file
107
tools/gen_modules.py
Normal file
@@ -0,0 +1,107 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Regenerate aegis*.py modules from the canonical template aegis256x4.py.
|
||||
|
||||
Changes per variant:
|
||||
- Replace module name (aegis256x4 -> target)
|
||||
- Replace label (AEGIS-256X4 -> target label like AEGIS-128L)
|
||||
- Replace only the ALIGNMENT = <int> value
|
||||
|
||||
We do not touch alloc_aligned(...) calls or any code formatting. Blank lines
|
||||
after ALIGNMENT are preserved.
|
||||
"""
|
||||
|
||||
import pathlib
|
||||
import re
|
||||
import sys
|
||||
|
||||
# Template and target locations
|
||||
ROOT = (
|
||||
pathlib.Path(__file__).resolve().parents[2]
|
||||
if (pathlib.Path(__file__).resolve().parents[0].name == "tools")
|
||||
else pathlib.Path.cwd()
|
||||
)
|
||||
PY_DIR = ROOT / "python"
|
||||
AEGIS_DIR = PY_DIR / "aegis"
|
||||
TEMPLATE = AEGIS_DIR / "aegis256x4.py"
|
||||
|
||||
# Variants to generate (template excluded) and their ALIGNMENT values
|
||||
VARIANT_ALIGN = {
|
||||
"aegis256": 16,
|
||||
"aegis256x2": 32,
|
||||
"aegis256x4": 64,
|
||||
"aegis128l": 32,
|
||||
"aegis128x2": 64,
|
||||
"aegis128x4": 64,
|
||||
}
|
||||
|
||||
TEMPLATE_NAME = "aegis256x4"
|
||||
TEMPLATE_LABEL = "AEGIS-256X4"
|
||||
|
||||
ALIGNMENT_LINE_RE = re.compile(r"^(ALIGNMENT\s*=\s*)(\d+)(\s*)$", re.MULTILINE)
|
||||
|
||||
|
||||
def set_alignment_only(text: str, value: int) -> str:
|
||||
"""Replace only the numeric ALIGNMENT value, preserving surrounding whitespace and lines.
|
||||
|
||||
This preserves any empty lines following the ALIGNMENT assignment because
|
||||
the line ending is not part of the match; we keep any trailing spaces too.
|
||||
"""
|
||||
|
||||
def _sub(m: re.Match[str]) -> str:
|
||||
prefix, _num, suffix = m.group(1), m.group(2), m.group(3)
|
||||
return f"{prefix}{value}{suffix}"
|
||||
|
||||
return ALIGNMENT_LINE_RE.sub(_sub, text)
|
||||
|
||||
|
||||
def algo_label(name: str) -> str:
|
||||
"""Return the canonical label like AEGIS-256X4 for a module name like aegis256x4."""
|
||||
if not name.startswith("aegis"):
|
||||
raise ValueError(f"Unexpected algorithm name: {name}")
|
||||
return "AEGIS-" + name[5:].upper()
|
||||
|
||||
|
||||
def generate_variant(template_src: str, variant: str) -> str:
|
||||
# 1) replace lowercase template name
|
||||
s = template_src.replace(TEMPLATE_NAME, variant)
|
||||
# 2) replace uppercase label
|
||||
s = s.replace(TEMPLATE_LABEL, algo_label(variant))
|
||||
# 3) set ALIGNMENT constant value using fallback map
|
||||
align_value = VARIANT_ALIGN.get(variant, 64)
|
||||
s = set_alignment_only(s, align_value)
|
||||
return s
|
||||
|
||||
|
||||
def main() -> int:
|
||||
if not TEMPLATE.exists():
|
||||
print(f"Template not found: {TEMPLATE}", file=sys.stderr)
|
||||
return 2
|
||||
template_src = TEMPLATE.read_text(encoding="utf-8")
|
||||
|
||||
# Safety: ensure we are working from an up-to-date template that contains expected tokens
|
||||
if TEMPLATE_NAME not in template_src or TEMPLATE_LABEL not in template_src:
|
||||
print(
|
||||
"Template file does not contain expected identifiers; aborting.",
|
||||
file=sys.stderr,
|
||||
)
|
||||
return 3
|
||||
|
||||
wrote = []
|
||||
for variant in VARIANT_ALIGN.keys():
|
||||
# Skip the template itself; recreate all other modules
|
||||
if variant == TEMPLATE_NAME:
|
||||
continue
|
||||
dst = AEGIS_DIR / f"{variant}.py"
|
||||
content = generate_variant(template_src, variant)
|
||||
dst.write_text(content, encoding="utf-8")
|
||||
wrote.append(dst.relative_to(ROOT))
|
||||
|
||||
print("Generated modules:")
|
||||
for p in wrote:
|
||||
print(" -", p)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Reference in New Issue
Block a user