Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions src/bindings/crypto_onetimeauth.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
int crypto_onetimeauth(unsigned char *out,
const unsigned char *in,
unsigned long long inlen,
const unsigned char *k);

int crypto_onetimeauth_verify(const unsigned char *h,
const unsigned char *in,
unsigned long long inlen,
const unsigned char *k);

size_t crypto_onetimeauth_bytes(void);
size_t crypto_onetimeauth_keybytes(void);
10 changes: 10 additions & 0 deletions src/nacl/bindings/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,12 @@
crypto_kx_seed_keypair,
crypto_kx_server_session_keys,
)
from nacl.bindings.crypto_onetimeauth import (
crypto_onetimeauth,
crypto_onetimeauth_verify,
crypto_onetimeauth_BYTES,
crypto_onetimeauth_KEYBYTES,
)
from nacl.bindings.crypto_pwhash import (
crypto_pwhash_ALG_ARGON2I13,
crypto_pwhash_ALG_ARGON2ID13,
Expand Down Expand Up @@ -378,6 +384,10 @@
"crypto_kx_SECRET_KEY_BYTES",
"crypto_kx_SEED_BYTES",
"crypto_kx_SESSION_KEY_BYTES",
"crypto_onetimeauth",
"crypto_onetimeauth_verify",
"crypto_onetimeauth_BYTES",
"crypto_onetimeauth_KEYBYTES",
"has_crypto_scalarmult_ed25519",
"crypto_scalarmult_BYTES",
"crypto_scalarmult_SCALARBYTES",
Expand Down
39 changes: 39 additions & 0 deletions src/nacl/bindings/crypto_onetimeauth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
from nacl._sodium import ffi, lib


crypto_onetimeauth_BYTES = lib.crypto_onetimeauth_bytes()
crypto_onetimeauth_KEYBYTES = lib.crypto_onetimeauth_keybytes()


def crypto_onetimeauth(message: bytes, key: bytes) -> bytes:
"""
Generate Poly1305 MAC over message with key.

:param message: data to authenticate
:param key: 32-bytes Poly1305 key
:return: 16-bytes MAC (tag)
"""
if len(key) != crypto_onetimeauth_KEYBYTES:
raise ValueError(f"Key must be {crypto_onetimeauth_KEYBYTES} bytes")

mac = ffi.new(f"unsigned char[{crypto_onetimeauth_BYTES}]")
lib.crypto_onetimeauth(mac, message, len(message), key)
return ffi.buffer(mac, crypto_onetimeauth_BYTES)[:]


def crypto_onetimeauth_verify(mac: bytes, message: bytes, key: bytes) -> bool:
"""
Verify if mac is valid for message and key.

:param mac: 16-bytes MAC/tag to check
:param message: data
:param key: 32-bytes key
:return: True on valid MAC, else False
"""
if len(mac) != crypto_onetimeauth_BYTES:
raise ValueError(f"MAC must be {crypto_onetimeauth_BYTES} bytes")
if len(key) != crypto_onetimeauth_KEYBYTES:
raise ValueError(f"Key must be {crypto_onetimeauth_KEYBYTES} bytes")

rc = lib.crypto_onetimeauth_verify(mac, message, len(message), key)
return rc == 0
27 changes: 27 additions & 0 deletions tests/test_bindings.py
Original file line number Diff line number Diff line change
Expand Up @@ -1020,3 +1020,30 @@ def test_scalarmult_ed25519_unavailable():
c.crypto_scalarmult_ed25519(zero, zero)
with pytest.raises(UnavailableError):
c.crypto_scalarmult_ed25519_noclamp(zero, zero)


def test_onetimeauth_wrong_length():
with pytest.raises(ValueError):
c.crypto_onetimeauth(b"", b"")
with pytest.raises(ValueError):
c.crypto_onetimeauth(b"message", b"")
with pytest.raises(ValueError):
c.crypto_onetimeauth_verify(b"", b"", b"")
with pytest.raises(ValueError):
c.crypto_onetimeauth_verify(
b"\x00" * c.crypto_onetimeauth_BYTES, b"message", b""
)
with pytest.raises(ValueError):
c.crypto_onetimeauth_verify(
b"", b"message", b"\x00" * c.crypto_onetimeauth_KEYBYTES
)


def test_onetimeauth():
key = b"\x01" * c.crypto_onetimeauth_KEYBYTES
msg = b"message"

mac = c.crypto_onetimeauth(msg, key)
assert tohex(mac) == "4cee137430de76761b1d11751b1d1175"

assert c.crypto_onetimeauth_verify(mac, msg, key)
Loading