From 1c49a13e1bb362d12a152b560a5b46cc75086f57 Mon Sep 17 00:00:00 2001 From: gon Date: Thu, 15 Aug 2024 20:52:04 -0400 Subject: [PATCH] crypto_box_easy support --- src/bindings/crypto_box.h | 17 ++++ src/nacl/bindings/__init__.py | 8 ++ src/nacl/bindings/crypto_box.py | 151 ++++++++++++++++++++++++++++++++ src/nacl/public.py | 4 +- 4 files changed, 178 insertions(+), 2 deletions(-) diff --git a/src/bindings/crypto_box.h b/src/bindings/crypto_box.h index a8d425e00..bfe265434 100644 --- a/src/bindings/crypto_box.h +++ b/src/bindings/crypto_box.h @@ -21,6 +21,7 @@ size_t crypto_box_boxzerobytes(); size_t crypto_box_noncebytes(); size_t crypto_box_beforenmbytes(); size_t crypto_box_sealbytes(); +size_t crypto_box_macbytes(); int crypto_box_keypair(unsigned char *pk, unsigned char *sk); @@ -53,3 +54,19 @@ int crypto_box_seal(unsigned char *c, const unsigned char *m, int crypto_box_seal_open(unsigned char *m, const unsigned char *c, unsigned long long clen, const unsigned char *pk, const unsigned char *sk); + +int crypto_box_easy_afternm(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + const unsigned char *k); + +int crypto_box_easy(unsigned char *c, const unsigned char *m, + unsigned long long mlen, const unsigned char *n, + const unsigned char *pk, const unsigned char *sk); + +int crypto_box_open_easy_afternm(unsigned char *m, const unsigned char *c, + unsigned long long clen, const unsigned char *n, + const unsigned char *k); + +int crypto_box_open_easy(unsigned char *m, const unsigned char *c, + unsigned long long clen, const unsigned char *n, + const unsigned char *pk, const unsigned char *sk); diff --git a/src/nacl/bindings/__init__.py b/src/nacl/bindings/__init__.py index aebf4aa07..a7f58627e 100644 --- a/src/nacl/bindings/__init__.py +++ b/src/nacl/bindings/__init__.py @@ -51,6 +51,10 @@ crypto_box_keypair, crypto_box_open, crypto_box_open_afternm, + crypto_box_easy, + crypto_box_open_easy, + crypto_box_easy_afternm, + crypto_box_open_easy_afternm, crypto_box_seal, crypto_box_seal_open, crypto_box_seed_keypair, @@ -279,6 +283,10 @@ "crypto_box_beforenm", "crypto_box_afternm", "crypto_box_open_afternm", + "crypto_box_easy", + "crypto_box_easy_afternm", + "crypto_box_open_easy", + "crypto_box_open_easy_afternm", "crypto_box_seal", "crypto_box_seal_open", "crypto_box_seed_keypair", diff --git a/src/nacl/bindings/crypto_box.py b/src/nacl/bindings/crypto_box.py index 8d1c831b5..1618d9761 100644 --- a/src/nacl/bindings/crypto_box.py +++ b/src/nacl/bindings/crypto_box.py @@ -29,6 +29,7 @@ crypto_box_BOXZEROBYTES: int = lib.crypto_box_boxzerobytes() crypto_box_BEFORENMBYTES: int = lib.crypto_box_beforenmbytes() crypto_box_SEALBYTES: int = lib.crypto_box_sealbytes() +crypto_box_MACBYTES: int = lib.crypto_box_macbytes() def crypto_box_keypair() -> Tuple[bytes, bytes]: @@ -227,6 +228,156 @@ def crypto_box_open_afternm( return ffi.buffer(plaintext, len(padded))[crypto_box_ZEROBYTES:] +def crypto_box_easy(message: bytes, nonce: bytes, pk: bytes, sk: bytes) -> bytes: + """ + Encrypts and returns a message ``message`` using the secret key ``sk``, + public key ``pk``, and the nonce ``nonce``. + + :param message: bytes + :param nonce: bytes + :param pk: bytes + :param sk: bytes + :rtype: bytes + """ + if len(nonce) != crypto_box_NONCEBYTES: + raise exc.ValueError("Invalid nonce size") + + if len(pk) != crypto_box_PUBLICKEYBYTES: + raise exc.ValueError("Invalid public key") + + if len(sk) != crypto_box_SECRETKEYBYTES: + raise exc.ValueError("Invalid secret key") + + _mlen = len(message) + _clen = crypto_box_MACBYTES + _mlen + + ciphertext = ffi.new("unsigned char[]", _clen) + + rc = lib.crypto_box_easy(ciphertext, message, _mlen, nonce, pk, sk) + ensure(rc == 0, "Unexpected library error", raising=exc.RuntimeError) + + return ffi.buffer(ciphertext, _clen)[:] + + +def crypto_box_open_easy( + ciphertext: bytes, nonce: bytes, pk: bytes, sk: bytes +) -> bytes: + """ + Decrypts and returns an encrypted message ``ciphertext``, using the secret + key ``sk``, public key ``pk``, and the nonce ``nonce``. + + :param ciphertext: bytes + :param nonce: bytes + :param pk: bytes + :param sk: bytes + :rtype: bytes + """ + if len(nonce) != crypto_box_NONCEBYTES: + raise exc.ValueError("Invalid nonce size") + + if len(pk) != crypto_box_PUBLICKEYBYTES: + raise exc.ValueError("Invalid public key") + + if len(sk) != crypto_box_SECRETKEYBYTES: + raise exc.ValueError("Invalid secret key") + + _clen = len(ciphertext) + + ensure( + _clen >= crypto_box_MACBYTES, + "Input ciphertext must be at least {} long".format( + crypto_box_MACBYTES + ), + raising=exc.TypeError, + ) + + _mlen = _clen - crypto_box_MACBYTES + + plaintext = ffi.new("unsigned char[]", max(1, _mlen)) + + res = lib.crypto_box_open_easy( + plaintext, ciphertext, _clen, nonce, pk, sk + ) + ensure( + res == 0, + "An error occurred trying to decrypt the message", + raising=exc.CryptoError, + ) + + return ffi.buffer(plaintext, _mlen)[:] + + +def crypto_box_easy_afternm(message: bytes, nonce: bytes, k: bytes) -> bytes: + """ + Encrypts and returns the message ``message`` using the shared key ``k`` and + the nonce ``nonce``. + + :param message: bytes + :param nonce: bytes + :param k: bytes + :rtype: bytes + """ + if len(nonce) != crypto_box_NONCEBYTES: + raise exc.ValueError("Invalid nonce") + + if len(k) != crypto_box_BEFORENMBYTES: + raise exc.ValueError("Invalid shared key") + + _mlen = len(message) + _clen = crypto_box_MACBYTES + _mlen + + ciphertext = ffi.new("unsigned char[]", _clen) + + rc = lib.crypto_box_easy_afternm(ciphertext, message, _mlen, nonce, k) + ensure(rc == 0, "Unexpected library error", raising=exc.RuntimeError) + + return ffi.buffer(ciphertext, _clen)[:] + + +def crypto_box_open_easy_afternm( + ciphertext: bytes, nonce: bytes, k: bytes +) -> bytes: + """ + Decrypts and returns the encrypted message ``ciphertext``, using the shared + key ``k`` and the nonce ``nonce``. + + :param ciphertext: bytes + :param nonce: bytes + :param k: bytes + :rtype: bytes + """ + if len(nonce) != crypto_box_NONCEBYTES: + raise exc.ValueError("Invalid nonce") + + if len(k) != crypto_box_BEFORENMBYTES: + raise exc.ValueError("Invalid shared key") + + _clen = len(ciphertext) + + ensure( + _clen >= crypto_box_MACBYTES, + "Input ciphertext must be at least {} long".format( + crypto_box_MACBYTES + ), + raising=exc.TypeError, + ) + + _mlen = _clen - crypto_box_MACBYTES + + plaintext = ffi.new("unsigned char[]", max(1, _mlen)) + + res = lib.crypto_box_open_easy_afternm( + plaintext, ciphertext, _clen, nonce, k + ) + ensure( + res == 0, + "An error occurred trying to decrypt the message", + raising=exc.CryptoError, + ) + + return ffi.buffer(plaintext, _mlen)[:] + + def crypto_box_seal(message: bytes, pk: bytes) -> bytes: """ Encrypts and returns a message ``message`` using an ephemeral secret key diff --git a/src/nacl/public.py b/src/nacl/public.py index c63665ac5..ef2c2517c 100644 --- a/src/nacl/public.py +++ b/src/nacl/public.py @@ -251,7 +251,7 @@ def encrypt( "The nonce must be exactly %s bytes long" % self.NONCE_SIZE ) - ciphertext = nacl.bindings.crypto_box_afternm( + ciphertext = nacl.bindings.crypto_box_easy_afternm( plaintext, nonce, self._shared_key, @@ -296,7 +296,7 @@ def decrypt( "The nonce must be exactly %s bytes long" % self.NONCE_SIZE ) - plaintext = nacl.bindings.crypto_box_open_afternm( + plaintext = nacl.bindings.crypto_box_open_easy_afternm( ciphertext, nonce, self._shared_key,