def crypto_kx_seed_keypair(seed): """ Generate a keypair with a given seed. This is functionally the same as crypto_box_seed_keypair, however it uses the blake2b hash primitive instead of sha512. It is included mainly for api consistency when using crypto_kx. :param seed: random seed :type seed: bytes :return: (public_key, secret_key) :rtype: (bytes, bytes) """ public_key = ffi.new("unsigned char[]", crypto_kx_PUBLIC_KEY_BYTES) secret_key = ffi.new("unsigned char[]", crypto_kx_SECRET_KEY_BYTES) ensure( isinstance(seed, bytes) and len(seed) == crypto_kx_SEED_BYTES, "Seed must be a {} byte long bytes sequence".format( crypto_kx_SEED_BYTES), raising=exc.TypeError, ) res = lib.crypto_kx_seed_keypair(public_key, secret_key, seed) ensure(res == 0, "Key generation failed.", raising=exc.CryptoError) return ( ffi.buffer(public_key, crypto_kx_PUBLIC_KEY_BYTES)[:], ffi.buffer(secret_key, crypto_kx_SECRET_KEY_BYTES)[:], )
def crypto_box_seed_keypair(seed): """ Returns a (public, secret) keypair deterministically generated from an input ``seed``. .. warning:: The seed **must** be high-entropy; therefore, its generator **must** be a cryptographic quality random function like, for example, :func:`~nacl.utils.random`. .. warning:: The seed **must** be protected and remain secret. Anyone who knows the seed is really in possession of the corresponding PrivateKey. :param seed: bytes :rtype: (bytes(public_key), bytes(secret_key)) """ ensure(isinstance(seed, bytes), "seed must be bytes", raising=TypeError) if len(seed) != crypto_box_SEEDBYTES: raise exc.ValueError("Invalid seed") pk = ffi.new("unsigned char[]", crypto_box_PUBLICKEYBYTES) sk = ffi.new("unsigned char[]", crypto_box_SECRETKEYBYTES) rc = lib.crypto_box_seed_keypair(pk, sk, seed) ensure(rc == 0, "Unexpected library error", raising=exc.RuntimeError) return ( ffi.buffer(pk, crypto_box_PUBLICKEYBYTES)[:], ffi.buffer(sk, crypto_box_SECRETKEYBYTES)[:], )
def crypto_kx_client_session_keys( client_public_key, client_secret_key, server_public_key ): """ Generate session keys for the client. :param client_public_key: :type client_public_key: bytes :param client_secret_key: :type client_secret_key: bytes :param server_public_key: :type server_public_key: bytes :return: (rx_key, tx_key) :rtype: (bytes, bytes) """ ensure( isinstance(client_public_key, bytes) and len(client_public_key) == crypto_kx_PUBLIC_KEY_BYTES, "Client public key must be a {0} bytes long bytes sequence".format( crypto_kx_PUBLIC_KEY_BYTES ), raising=exc.TypeError, ) ensure( isinstance(client_secret_key, bytes) and len(client_secret_key) == crypto_kx_SECRET_KEY_BYTES, "Client secret key must be a {0} bytes long bytes sequence".format( crypto_kx_PUBLIC_KEY_BYTES ), raising=exc.TypeError, ) ensure( isinstance(server_public_key, bytes) and len(server_public_key) == crypto_kx_PUBLIC_KEY_BYTES, "Server public key must be a {0} bytes long bytes sequence".format( crypto_kx_PUBLIC_KEY_BYTES ), raising=exc.TypeError, ) rx_key = ffi.new("unsigned char[]", crypto_kx_SESSION_KEY_BYTES) tx_key = ffi.new("unsigned char[]", crypto_kx_SESSION_KEY_BYTES) res = lib.crypto_kx_client_session_keys( rx_key, tx_key, client_public_key, client_secret_key, server_public_key ) ensure( res == 0, "Client session key generation failed.", raising=exc.CryptoError, ) return ( ffi.buffer(rx_key, crypto_kx_SESSION_KEY_BYTES)[:], ffi.buffer(tx_key, crypto_kx_SESSION_KEY_BYTES)[:], )
def crypto_sign_keypair_not_random(self, seed): if len(seed) != self.crypto_sign_SEEDBYTES: raise ValueError("Invalid seed") pk = ffi.new("unsigned char[]", self.crypto_sign_PUBLICKEYBYTES) sk = ffi.new("unsigned char[]", self.crypto_sign_SECRETKEYBYTES) rc = lib.crypto_sign_seed_keypair(pk, sk, seed) ensure(rc == 0, 'Unexpected library error', raising=exc.RuntimeError) return (ffi.buffer(pk, self.crypto_sign_PUBLICKEYBYTES)[:], ffi.buffer(sk, self.crypto_sign_SECRETKEYBYTES)[:], )
def crypto_kx_keypair(): """ Generate a keypair. This is a duplicate crypto_box_keypair, but is included for api consistency. :return: (public_key, secret_key) :rtype: (bytes, bytes) """ public_key = ffi.new("unsigned char[]", crypto_kx_PUBLIC_KEY_BYTES) secret_key = ffi.new("unsigned char[]", crypto_kx_SECRET_KEY_BYTES) res = lib.crypto_kx_keypair(public_key, secret_key) ensure(res == 0, "Key generation failed.", raising=exc.CryptoError) return (ffi.buffer(public_key, crypto_kx_PUBLIC_KEY_BYTES)[:], ffi.buffer(secret_key, crypto_kx_SECRET_KEY_BYTES)[:])
def crypto_core_ed25519_scalar_complement(s): """ Return the complement of integer ``s`` modulo ``L``, i.e. an integer ``c`` such that ``s + c = 1 (mod L)``, where ``L`` is the order of the main subgroup. :param s: a :py:data:`.crypto_core_ed25519_SCALARBYTES` long bytes sequence representing an integer :type s: bytes :return: an integer represented as a :py:data:`.crypto_core_ed25519_SCALARBYTES` long bytes sequence :rtype: bytes :raises nacl.exceptions.UnavailableError: If called when using a minimal build of libsodium. """ ensure( has_crypto_core_ed25519, "Not available in minimal build", raising=exc.UnavailableError, ) ensure( isinstance(s, bytes) and len(s) == crypto_core_ed25519_SCALARBYTES, "Integer s must be a {} long bytes sequence".format( "crypto_core_ed25519_SCALARBYTES" ), raising=exc.TypeError, ) r = ffi.new("unsigned char[]", crypto_core_ed25519_SCALARBYTES) lib.crypto_core_ed25519_scalar_complement(r, s) return ffi.buffer(r, crypto_core_ed25519_SCALARBYTES)[:]
def crypto_core_ed25519_sub(p, q): """ Subtract a point from another on the edwards25519 curve. :param p: a :py:data:`.crypto_core_ed25519_BYTES` long bytes sequence representing a point on the edwards25519 curve :type p: bytes :param q: a :py:data:`.crypto_core_ed25519_BYTES` long bytes sequence representing a point on the edwards25519 curve :type q: bytes :return: a point on the edwards25519 curve represented as a :py:data:`.crypto_core_ed25519_BYTES` long bytes sequence :rtype: bytes """ ensure(isinstance(p, bytes) and isinstance(q, bytes) and len(p) == crypto_core_ed25519_BYTES and len(q) == crypto_core_ed25519_BYTES, 'Each point must be a {} long bytes sequence'.format( 'crypto_core_ed25519_BYTES'), raising=exc.TypeError) r = ffi.new("unsigned char[]", crypto_core_ed25519_BYTES) rc = lib.crypto_core_ed25519_sub(r, p, q) ensure(rc == 0, 'Unexpected library error', raising=exc.RuntimeError) return ffi.buffer(r, crypto_core_ed25519_BYTES)[:]
def crypto_scalarmult_ed25519_base(n): """ Computes and returns the scalar product of a standard group element and an integer ``n`` on the edwards25519 curve. :param n: a :py:data:`.crypto_scalarmult_ed25519_SCALARBYTES` long bytes sequence representing a scalar :type n: bytes :return: a point on the edwards25519 curve, represented as a :py:data:`.crypto_scalarmult_ed25519_BYTES` long bytes sequence :rtype: bytes """ ensure(isinstance(n, bytes) and len(n) == crypto_scalarmult_ed25519_SCALARBYTES, 'Input must be a {} long bytes sequence'.format( 'crypto_scalarmult_ed25519_SCALARBYTES'), raising=exc.TypeError) q = ffi.new("unsigned char[]", crypto_scalarmult_ed25519_BYTES) rc = lib.crypto_scalarmult_ed25519_base(q, n) ensure(rc == 0, 'Unexpected library error', raising=exc.RuntimeError) return ffi.buffer(q, crypto_scalarmult_ed25519_BYTES)[:]
def crypto_sign_ed25519ph_final_create(edph, sk): """ Create a signature for the data hashed in edph using the secret key sk :param edph: the ed25519ph state for the data being signed :type edph: crypto_sign_ed25519ph_state :param sk: the ed25519 secret part of the signing key :type sk: bytes :return: ed25519ph signature :rtype: bytes """ ensure(isinstance(edph, crypto_sign_ed25519ph_state), 'edph parameter must be a ed25519ph_state object', raising=exc.TypeError) ensure(isinstance(sk, bytes), 'secret key parameter must be a bytes object', raising=exc.TypeError) ensure(len(sk) == crypto_sign_SECRETKEYBYTES, ('secret key must be {0} ' 'bytes long').format(crypto_sign_SECRETKEYBYTES), raising=exc.TypeError) signature = ffi.new("unsigned char[]", crypto_sign_BYTES) rc = lib.crypto_sign_ed25519ph_final_create(edph.state, signature, ffi.NULL, sk) ensure(rc == 0, 'Unexpected library error', raising=exc.RuntimeError) return ffi.buffer(signature, crypto_sign_BYTES)[:]
def crypto_shorthash_siphashx24(data, key): """Compute a fast, cryptographic quality, keyed hash of the input data :param data: :type data: bytes :param key: len(key) must be equal to :py:data:`.XKEYBYTES` (16) :type key: bytes :raises nacl.exceptions.UnavailableError: If called when using a minimal build of libsodium. """ ensure( has_crypto_shorthash_siphashx24, "Not available in minimal build", raising=exc.UnavailableError, ) if len(key) != XKEYBYTES: raise exc.ValueError( "Key length must be exactly {0} bytes".format(XKEYBYTES)) digest = ffi.new("unsigned char[]", XBYTES) rc = lib.crypto_shorthash_siphashx24(digest, data, len(data), key) ensure(rc == 0, raising=exc.RuntimeError) return ffi.buffer(digest, XBYTES)[:]
def crypto_box_open_afternm(ciphertext, nonce, k): """ 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") padded = (b"\x00" * crypto_box_BOXZEROBYTES) + ciphertext plaintext = ffi.new("unsigned char[]", len(padded)) res = lib.crypto_box_open_afternm(plaintext, padded, len(padded), nonce, k) ensure(res == 0, "An error occurred trying to decrypt the message", raising=exc.CryptoError) return ffi.buffer(plaintext, len(padded))[crypto_box_ZEROBYTES:]
def sodium_add(a, b): """ Given a couple of *same-sized* byte sequences, interpreted as the little-endian representation of two unsigned integers, compute the modular addition of the represented values, in constant time for a given common length of the byte sequences. :param a: input bytes buffer :type a: bytes :param b: input bytes buffer :type b: bytes :return: a byte-sequence representing, as a little-endian big integer, the integer value of ``(to_int(a) + to_int(b)) mod 2^(8*len(a))`` :rtype: bytes """ ensure(isinstance(a, bytes), raising=exc.TypeError) ensure(isinstance(b, bytes), raising=exc.TypeError) ln = len(a) ensure(len(b) == ln, raising=exc.TypeError) buf_a = ffi.new("unsigned char []", ln) buf_b = ffi.new("unsigned char []", ln) ffi.memmove(buf_a, a, ln) ffi.memmove(buf_b, b, ln) lib.sodium_add(buf_a, buf_b, ln) return ffi.buffer(buf_a, ln)[:]
def sodium_pad(s, blocksize): """ Pad the input bytearray ``s`` to a multiple of ``blocksize`` using the ISO/IEC 7816-4 algorithm :param s: input bytes string :type s: bytes :param blocksize: :type blocksize: int :return: padded string :rtype: bytes """ ensure(isinstance(s, bytes), raising=exc.TypeError) ensure(isinstance(blocksize, integer_types), raising=exc.TypeError) if blocksize <= 0: raise exc.ValueError s_len = len(s) m_len = s_len + blocksize buf = ffi.new("unsigned char []", m_len) p_len = ffi.new("size_t []", 1) ffi.memmove(buf, s, s_len) rc = lib.sodium_pad(p_len, buf, s_len, blocksize, m_len) ensure(rc == 0, "Padding failure", raising=exc.CryptoError) return ffi.buffer(buf, p_len[0])[:]
def crypto_box_afternm(message, nonce, k): """ 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") padded = b"\x00" * crypto_box_ZEROBYTES + message ciphertext = ffi.new("unsigned char[]", len(padded)) rc = lib.crypto_box_afternm(ciphertext, padded, len(padded), nonce, k) ensure(rc == 0, 'Unexpected library error', raising=exc.RuntimeError) return ffi.buffer(ciphertext, len(padded))[crypto_box_BOXZEROBYTES:]
def crypto_box_open_afternm(ciphertext, nonce, k): """ 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") padded = (b"\x00" * crypto_box_BOXZEROBYTES) + ciphertext plaintext = ffi.new("unsigned char[]", len(padded)) res = lib.crypto_box_open_afternm( plaintext, padded, len(padded), nonce, k) ensure(res == 0, "An error occurred trying to decrypt the message", raising=exc.CryptoError) return ffi.buffer(plaintext, len(padded))[crypto_box_ZEROBYTES:]
def crypto_box_keypair(): """ Returns a randomly generated public and secret key. :rtype: (bytes(public_key), bytes(secret_key)) """ pk = ffi.new("unsigned char[]", crypto_box_PUBLICKEYBYTES) sk = ffi.new("unsigned char[]", crypto_box_SECRETKEYBYTES) rc = lib.crypto_box_keypair(pk, sk) ensure(rc == 0, 'Unexpected library error', raising=exc.RuntimeError) return ( ffi.buffer(pk, crypto_box_PUBLICKEYBYTES)[:], ffi.buffer(sk, crypto_box_SECRETKEYBYTES)[:], )
def crypto_core_ed25519_scalar_mul(p, q): """ Multiply integers ``p`` and ``q`` modulo ``L``, where ``L`` is the order of the main subgroup. :param p: a :py:data:`.crypto_core_ed25519_SCALARBYTES` long bytes sequence representing an integer :type p: bytes :param q: a :py:data:`.crypto_core_ed25519_SCALARBYTES` long bytes sequence representing an integer :type q: bytes :return: an integer represented as a :py:data:`.crypto_core_ed25519_SCALARBYTES` long bytes sequence :rtype: bytes """ ensure(isinstance(p, bytes) and isinstance(q, bytes) and len(p) == crypto_core_ed25519_SCALARBYTES and len(q) == crypto_core_ed25519_SCALARBYTES, 'Each integer must be a {} long bytes sequence'.format( 'crypto_core_ed25519_SCALARBYTES'), raising=exc.TypeError) r = ffi.new("unsigned char[]", crypto_core_ed25519_SCALARBYTES) lib.crypto_core_ed25519_scalar_mul(r, p, q) return ffi.buffer(r, crypto_core_ed25519_SCALARBYTES)[:]
def crypto_box(message, nonce, pk, sk): """ 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") padded = (b"\x00" * crypto_box_ZEROBYTES) + message ciphertext = ffi.new("unsigned char[]", len(padded)) rc = lib.crypto_box(ciphertext, padded, len(padded), nonce, pk, sk) ensure(rc == 0, 'Unexpected library error', raising=exc.RuntimeError) return ffi.buffer(ciphertext, len(padded))[crypto_box_BOXZEROBYTES:]
def crypto_box_open(ciphertext, nonce, pk, sk): """ 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") padded = (b"\x00" * crypto_box_BOXZEROBYTES) + ciphertext plaintext = ffi.new("unsigned char[]", len(padded)) res = lib.crypto_box_open(plaintext, padded, len(padded), nonce, pk, sk) ensure(res == 0, "An error occurred trying to decrypt the message", raising=exc.CryptoError) return ffi.buffer(plaintext, len(padded))[crypto_box_ZEROBYTES:]
def crypto_secretbox_open(ciphertext, nonce, key): """ Decrypt and returns the encrypted message ``ciphertext`` with the secret ``key`` and the nonce ``nonce``. :param ciphertext: bytes :param nonce: bytes :param key: bytes :rtype: bytes """ if len(key) != crypto_secretbox_KEYBYTES: raise exc.ValueError("Invalid key") if len(nonce) != crypto_secretbox_NONCEBYTES: raise exc.ValueError("Invalid nonce") padded = b"\x00" * crypto_secretbox_BOXZEROBYTES + ciphertext plaintext = ffi.new("unsigned char[]", len(padded)) res = lib.crypto_secretbox_open(plaintext, padded, len(padded), nonce, key) ensure(res == 0, "Decryption failed. Ciphertext failed verification", raising=exc.CryptoError) plaintext = ffi.buffer(plaintext, len(padded)) return plaintext[crypto_secretbox_ZEROBYTES:]
def crypto_box_keypair(): """ Returns a randomly generated public and secret key. :rtype: (bytes(public_key), bytes(secret_key)) """ pk = ffi.new("unsigned char[]", crypto_box_PUBLICKEYBYTES) sk = ffi.new("unsigned char[]", crypto_box_SECRETKEYBYTES) rc = lib.crypto_box_keypair(pk, sk) assert rc == 0 return ( ffi.buffer(pk, crypto_box_PUBLICKEYBYTES)[:], ffi.buffer(sk, crypto_box_SECRETKEYBYTES)[:], )
def crypto_core_ed25519_sub(p, q): """ Subtract a point from another on the edwards25519 curve. :param p: a :py:data:`.crypto_core_ed25519_BYTES` long bytes sequence representing a point on the edwards25519 curve :type p: bytes :param q: a :py:data:`.crypto_core_ed25519_BYTES` long bytes sequence representing a point on the edwards25519 curve :type q: bytes :return: a point on the edwards25519 curve represented as a :py:data:`.crypto_core_ed25519_BYTES` long bytes sequence :rtype: bytes :raises nacl.exceptions.UnavailableError: If called when using a minimal build of libsodium. """ ensure(has_crypto_core_ed25519, 'Not available in minimal build', raising=exc.UnavailableError) ensure(isinstance(p, bytes) and isinstance(q, bytes) and len(p) == crypto_core_ed25519_BYTES and len(q) == crypto_core_ed25519_BYTES, 'Each point must be a {} long bytes sequence'.format( 'crypto_core_ed25519_BYTES'), raising=exc.TypeError) r = ffi.new("unsigned char[]", crypto_core_ed25519_BYTES) rc = lib.crypto_core_ed25519_sub(r, p, q) ensure(rc == 0, 'Unexpected library error', raising=exc.RuntimeError) return ffi.buffer(r, crypto_core_ed25519_BYTES)[:]
def crypto_core_ed25519_scalar_mul(p, q): """ Multiply integers ``p`` and ``q`` modulo ``L``, where ``L`` is the order of the main subgroup. :param p: a :py:data:`.crypto_core_ed25519_SCALARBYTES` long bytes sequence representing an integer :type p: bytes :param q: a :py:data:`.crypto_core_ed25519_SCALARBYTES` long bytes sequence representing an integer :type q: bytes :return: an integer represented as a :py:data:`.crypto_core_ed25519_SCALARBYTES` long bytes sequence :rtype: bytes :raises nacl.exceptions.UnavailableError: If called when using a minimal build of libsodium. """ ensure(has_crypto_core_ed25519, 'Not available in minimal build', raising=exc.UnavailableError) ensure(isinstance(p, bytes) and isinstance(q, bytes) and len(p) == crypto_core_ed25519_SCALARBYTES and len(q) == crypto_core_ed25519_SCALARBYTES, 'Each integer must be a {} long bytes sequence'.format( 'crypto_core_ed25519_SCALARBYTES'), raising=exc.TypeError) r = ffi.new("unsigned char[]", crypto_core_ed25519_SCALARBYTES) lib.crypto_core_ed25519_scalar_mul(r, p, q) return ffi.buffer(r, crypto_core_ed25519_SCALARBYTES)[:]
def crypto_core_ed25519_scalar_reduce(s): """ Reduce integer ``s`` to ``s`` modulo ``L``, where ``L`` is the order of the main subgroup. :param s: a :py:data:`.crypto_core_ed25519_NONREDUCEDSCALARBYTES` long bytes sequence representing an integer :type s: bytes :return: an integer represented as a :py:data:`.crypto_core_ed25519_SCALARBYTES` long bytes sequence :rtype: bytes :raises nacl.exceptions.UnavailableError: If called when using a minimal build of libsodium. """ ensure(has_crypto_core_ed25519, 'Not available in minimal build', raising=exc.UnavailableError) ensure(isinstance(s, bytes) and len(s) == crypto_core_ed25519_NONREDUCEDSCALARBYTES, 'Integer s must be a {} long bytes sequence'.format( 'crypto_core_ed25519_NONREDUCEDSCALARBYTES'), raising=exc.TypeError) r = ffi.new("unsigned char[]", crypto_core_ed25519_SCALARBYTES) lib.crypto_core_ed25519_scalar_reduce(r, s) return ffi.buffer(r, crypto_core_ed25519_SCALARBYTES)[:]
def crypto_secretbox_open(ciphertext, nonce, key): """ Decrypt and returns the encrypted message ``ciphertext`` with the secret ``key`` and the nonce ``nonce``. :param ciphertext: bytes :param nonce: bytes :param key: bytes :rtype: bytes """ if len(key) != crypto_secretbox_KEYBYTES: raise exc.ValueError("Invalid key") if len(nonce) != crypto_secretbox_NONCEBYTES: raise exc.ValueError("Invalid nonce") padded = b"\x00" * crypto_secretbox_BOXZEROBYTES + ciphertext plaintext = ffi.new("unsigned char[]", len(padded)) res = lib.crypto_secretbox_open( plaintext, padded, len(padded), nonce, key) ensure(res == 0, "Decryption failed. Ciphertext failed verification", raising=exc.CryptoError) plaintext = ffi.buffer(plaintext, len(padded)) return plaintext[crypto_secretbox_ZEROBYTES:]
def crypto_core_ed25519_scalar_invert(s): """ Return the multiplicative inverse of integer ``s`` modulo ``L``, i.e an integer ``i`` such that ``s * i = 1 (mod L)``, where ``L`` is the order of the main subgroup. Raises a ``exc.RuntimeError`` if ``s`` is the integer zero. :param s: a :py:data:`.crypto_core_ed25519_SCALARBYTES` long bytes sequence representing an integer :type s: bytes :return: an integer represented as a :py:data:`.crypto_core_ed25519_SCALARBYTES` long bytes sequence :rtype: bytes :raises nacl.exceptions.UnavailableError: If called when using a minimal build of libsodium. """ ensure(has_crypto_core_ed25519, 'Not available in minimal build', raising=exc.UnavailableError) ensure(isinstance(s, bytes) and len(s) == crypto_core_ed25519_SCALARBYTES, 'Integer s must be a {} long bytes sequence'.format( 'crypto_core_ed25519_SCALARBYTES'), raising=exc.TypeError) r = ffi.new("unsigned char[]", crypto_core_ed25519_SCALARBYTES) rc = lib.crypto_core_ed25519_scalar_invert(r, s) ensure(rc == 0, 'Unexpected library error', raising=exc.RuntimeError) return ffi.buffer(r, crypto_core_ed25519_SCALARBYTES)[:]
def crypto_box_seal(message, pk): """ Encrypts and returns a message ``message`` using an ephemeral secret key and the public key ``pk``. The ephemeral public key, which is embedded in the sealed box, is also used, in combination with ``pk``, to derive the nonce needed for the underlying box construct. :param message: bytes :param pk: bytes :rtype: bytes .. versionadded:: 1.2 """ ensure(isinstance(message, bytes), "input message must be bytes", raising=TypeError) ensure(isinstance(pk, bytes), "public key must be bytes", raising=TypeError) if len(pk) != crypto_box_PUBLICKEYBYTES: raise exc.ValueError("Invalid public key") _mlen = len(message) _clen = crypto_box_SEALBYTES + _mlen ciphertext = ffi.new("unsigned char[]", _clen) rc = lib.crypto_box_seal(ciphertext, message, _mlen, pk) ensure(rc == 0, 'Unexpected library error', raising=exc.RuntimeError) return ffi.buffer(ciphertext, _clen)[:]
def crypto_scalarmult_ed25519_base(n): """ Computes and returns the scalar product of a standard group element and an integer ``n`` on the edwards25519 curve. :param n: a :py:data:`.crypto_scalarmult_ed25519_SCALARBYTES` long bytes sequence representing a scalar :type n: bytes :return: a point on the edwards25519 curve, represented as a :py:data:`.crypto_scalarmult_ed25519_BYTES` long bytes sequence :rtype: bytes :raises nacl.exceptions.UnavailableError: If called when using a minimal build of libsodium. """ ensure( has_crypto_scalarmult_ed25519, "Not available in minimal build", raising=exc.UnavailableError, ) ensure( isinstance(n, bytes) and len(n) == crypto_scalarmult_ed25519_SCALARBYTES, "Input must be a {} long bytes sequence".format( "crypto_scalarmult_ed25519_SCALARBYTES"), raising=exc.TypeError, ) q = ffi.new("unsigned char[]", crypto_scalarmult_ed25519_BYTES) rc = lib.crypto_scalarmult_ed25519_base(q, n) ensure(rc == 0, "Unexpected library error", raising=exc.RuntimeError) return ffi.buffer(q, crypto_scalarmult_ed25519_BYTES)[:]
def crypto_auth_hmacsha512256(message, k): a = ffi.new("unsigned char[]", crypto_auth_hmacsha512256_BYTES) rc = lib.crypto_auth_hmacsha512256(a, message, len(message), k) assert rc == 0 return ffi.buffer(a, crypto_auth_hmacsha512256_BYTES)[:]
def crypto_aead_aes256gcm_decrypt( cipher, tag, nonce, key, additional_data, additional_data_len): if len(key) != crypto_aead_aes256gcm_KEYBYTES: raise ValueError("Invalid key") if len(nonce) != crypto_aead_aes256gcm_NPUBBYTES: raise ValueError("Invalid nonce") plaintext = ffi.new("unsigned char[]", len(cipher)) decrypted_len = ffi.new("unsigned long long *") ciphertext = cipher + tag if additional_data is None: additional_data = ffi.NULL if (lib.crypto_aead_aes256gcm_decrypt( plaintext, decrypted_len, ffi.NULL, ciphertext, len(ciphertext), additional_data, additional_data_len, nonce, key) != 0): raise CryptoError("Decryption failed. Ciphertext failed verification") plaintext = ffi.buffer(plaintext, len(cipher)) return plaintext
def crypto_box_open(ciphertext, nonce, pk, sk): """ 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 ValueError("Invalid nonce size") if len(pk) != crypto_box_PUBLICKEYBYTES: raise ValueError("Invalid public key") if len(sk) != crypto_box_SECRETKEYBYTES: raise ValueError("Invalid secret key") padded = (b"\x00" * crypto_box_BOXZEROBYTES) + ciphertext plaintext = ffi.new("unsigned char[]", len(padded)) if lib.crypto_box_open(plaintext, padded, len(padded), nonce, pk, sk) != 0: raise CryptoError("An error occurred trying to decrypt the message") return ffi.buffer(plaintext, len(padded))[crypto_box_ZEROBYTES:]
def crypto_box(message, nonce, pk, sk): """ 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 ValueError("Invalid nonce size") if len(pk) != crypto_box_PUBLICKEYBYTES: raise ValueError("Invalid public key") if len(sk) != crypto_box_SECRETKEYBYTES: raise ValueError("Invalid secret key") padded = (b"\x00" * crypto_box_ZEROBYTES) + message ciphertext = ffi.new("unsigned char[]", len(padded)) rc = lib.crypto_box(ciphertext, padded, len(padded), nonce, pk, sk) assert rc == 0 return ffi.buffer(ciphertext, len(padded))[crypto_box_BOXZEROBYTES:]
def crypto_core_hsalsa20(message, k, sigma): """ :param message: bytes :rtype: bytes """ q = ffi.new("unsigned char[]", crypto_core_hsalsa20_output_BYTES) rc = lib.crypto_core_hsalsa20(q, message, k, sigma) assert rc == 0 return ffi.buffer(q, crypto_core_hsalsa20_output_BYTES)[:]
def crypto_sign_keypair(): """ Returns a randomly generated public key and secret key. :rtype: (bytes(public_key), bytes(secret_key)) """ pk = ffi.new("unsigned char[]", crypto_sign_PUBLICKEYBYTES) sk = ffi.new("unsigned char[]", crypto_sign_SECRETKEYBYTES) rc = lib.crypto_sign_keypair(pk, sk) ensure(rc == 0, 'Unexpected library error', raising=exc.RuntimeError) return ( ffi.buffer(pk, crypto_sign_PUBLICKEYBYTES)[:], ffi.buffer(sk, crypto_sign_SECRETKEYBYTES)[:], )
def crypto_box_seal_open(ciphertext, pk, sk): """ Decrypts and returns an encrypted message ``ciphertext``, using the recipent's secret key ``sk`` and the sender's ephemeral public key embedded in the sealed box. The box contruct nonce is derived from the recipient's public key ``pk`` and the sender's public key. :param ciphertext: bytes :param pk: bytes :param sk: bytes :rtype: bytes .. versionadded:: 1.2 """ ensure( isinstance(ciphertext, bytes), "input ciphertext must be bytes", raising=TypeError, ) ensure( isinstance(pk, bytes), "public key must be bytes", raising=TypeError ) ensure( isinstance(sk, bytes), "secret key must be bytes", raising=TypeError ) 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_SEALBYTES, ("Input cyphertext must be " "at least {} long").format( crypto_box_SEALBYTES ), raising=exc.TypeError, ) _mlen = _clen - crypto_box_SEALBYTES # zero-length malloc results are implementation.dependent plaintext = ffi.new("unsigned char[]", max(1, _mlen)) res = lib.crypto_box_seal_open(plaintext, ciphertext, _clen, pk, sk) ensure( res == 0, "An error occurred trying to decrypt the message", raising=exc.CryptoError, ) return ffi.buffer(plaintext, _mlen)[:]
def crypto_pwhash_scryptsalsa208sha256_ll(passwd, salt, n, r, p, dklen=64, maxmem=SCRYPT_MAX_MEM): """ Derive a cryptographic key using the ``passwd`` and ``salt`` given as input. The work factor can be tuned by by picking different values for the parameters :param bytes passwd: :param bytes salt: :param bytes salt: *must* be *exactly* :py:const:`.SALTBYTES` long :param int dklen: :param int opslimit: :param int n: :param int r: block size, :param int p: the parallelism factor :param int maxmem: the maximum available memory available for scrypt's operations :rtype: bytes :raises nacl.exceptions.UnavailableError: If called when using a minimal build of libsodium. """ ensure( has_crypto_pwhash_scryptsalsa208sha256, "Not available in minimal build", raising=exc.UnavailableError, ) ensure(isinstance(n, int), raising=TypeError) ensure(isinstance(r, int), raising=TypeError) ensure(isinstance(p, int), raising=TypeError) ensure(isinstance(passwd, bytes), raising=TypeError) ensure(isinstance(salt, bytes), raising=TypeError) _check_memory_occupation(n, r, p, maxmem) buf = ffi.new("uint8_t[]", dklen) ret = lib.crypto_pwhash_scryptsalsa208sha256_ll(passwd, len(passwd), salt, len(salt), n, r, p, buf, dklen) ensure( ret == 0, "Unexpected failure in key derivation", raising=exc.RuntimeError, ) return ffi.buffer(ffi.cast("char *", buf), dklen)[:]
def crypto_auth_hmacsha256(message, k): """ :param message: bytes :param k: bytes :rtype: bytes """ q = ffi.new("unsigned char[]", crypto_auth_hmacsha256_BYTES) rc = lib.crypto_auth_hmacsha256(q, message, len(message), k) assert rc == 0 return ffi.buffer(q, crypto_auth_hmacsha256_BYTES)[:]
def crypto_stream_chacha20_keygen(): """ Generate a key for use with chacha20. :rtype: bytes """ keybuf = ffi.new("unsigned char[]", crypto_stream_chacha20_KEYBYTES) lib.crypto_stream_chacha20_keygen(keybuf) return ffi.buffer(keybuf, crypto_stream_chacha20_KEYBYTES)[:]
def crypto_kx_client_session_keys(client_public_key, client_secret_key, server_public_key): """ Generate session keys for the client. :param client_public_key: :type client_public_key: bytes :param client_secret_key: :type client_secret_key: bytes :param server_public_key: :type server_public_key: bytes :return: (rx_key, tx_key) :rtype: (bytes, bytes) """ ensure(isinstance(client_public_key, bytes) and len(client_public_key) == crypto_kx_PUBLIC_KEY_BYTES, 'Client public key must be a {0} bytes long bytes sequence'.format( crypto_kx_PUBLIC_KEY_BYTES), raising=exc.TypeError) ensure(isinstance(client_secret_key, bytes) and len(client_secret_key) == crypto_kx_SECRET_KEY_BYTES, 'Client secret key must be a {0} bytes long bytes sequence'.format( crypto_kx_PUBLIC_KEY_BYTES), raising=exc.TypeError) ensure(isinstance(server_public_key, bytes) and len(server_public_key) == crypto_kx_PUBLIC_KEY_BYTES, 'Server public key must be a {0} bytes long bytes sequence'.format( crypto_kx_PUBLIC_KEY_BYTES), raising=exc.TypeError) rx_key = ffi.new("unsigned char[]", crypto_kx_SESSION_KEY_BYTES) tx_key = ffi.new("unsigned char[]", crypto_kx_SESSION_KEY_BYTES) res = lib.crypto_kx_client_session_keys(rx_key, tx_key, client_public_key, client_secret_key, server_public_key) ensure(res == 0, "Client session key generation failed.", raising=exc.CryptoError) return (ffi.buffer(rx_key, crypto_kx_SESSION_KEY_BYTES)[:], ffi.buffer(tx_key, crypto_kx_SESSION_KEY_BYTES)[:])
def crypto_pwhash_alg(outlen, passwd, salt, opslimit, memlimit, alg): """ Derive a raw cryptographic key using the ``passwd`` and the ``salt`` given as input to the ``alg`` algorithm. :param outlen: the length of the derived key :type outlen: int :param passwd: The input password :type passwd: bytes :param opslimit: computational cost :type opslimit: int :param memlimit: memory cost :type memlimit: int :param alg: algorithm identifier :type alg: int :return: derived key :rtype: bytes """ ensure(isinstance(outlen, integer_types), raising=exc.TypeError) ensure(isinstance(opslimit, integer_types), raising=exc.TypeError) ensure(isinstance(memlimit, integer_types), raising=exc.TypeError) ensure(isinstance(alg, integer_types), raising=exc.TypeError) ensure(isinstance(passwd, bytes), raising=exc.TypeError) if len(salt) != crypto_pwhash_SALTBYTES: raise exc.ValueError("salt must be exactly {0} bytes long".format( crypto_pwhash_SALTBYTES)) if outlen < crypto_pwhash_BYTES_MIN: raise exc.ValueError( 'derived key must be at least {0} bytes long'.format( crypto_pwhash_BYTES_MIN)) elif outlen > crypto_pwhash_BYTES_MAX: raise exc.ValueError( 'derived key must be at most {0} bytes long'.format( crypto_pwhash_BYTES_MAX)) _check_argon2_limits_alg(opslimit, memlimit, alg) outbuf = ffi.new("unsigned char[]", outlen) ret = lib.crypto_pwhash(outbuf, outlen, passwd, len(passwd), salt, opslimit, memlimit, alg) ensure(ret == 0, 'Unexpected failure in key derivation', raising=exc.RuntimeError) return ffi.buffer(outbuf, outlen)[:]
def crypto_sign_seed_keypair(seed): """ Computes and returns the public key and secret key using the seed ``seed``. :param seed: bytes :rtype: (bytes(public_key), bytes(secret_key)) """ if len(seed) != crypto_sign_SEEDBYTES: raise ValueError("Invalid seed") pk = ffi.new("unsigned char[]", crypto_sign_PUBLICKEYBYTES) sk = ffi.new("unsigned char[]", crypto_sign_SECRETKEYBYTES) rc = lib.crypto_sign_seed_keypair(pk, sk, seed) assert rc == 0 return ( ffi.buffer(pk, crypto_sign_PUBLICKEYBYTES)[:], ffi.buffer(sk, crypto_sign_SECRETKEYBYTES)[:], )
def crypto_hash_sha512(message): """ Hashes and returns the message ``message``. :param message: bytes :rtype: bytes """ digest = ffi.new("unsigned char[]", crypto_hash_sha512_BYTES) rc = lib.crypto_hash_sha512(digest, message, len(message)) assert rc == 0 return ffi.buffer(digest, crypto_hash_sha512_BYTES)[:]
def randombytes(size): """ Returns ``size`` number of random bytes from a cryptographically secure random source. :param size: int :rtype: bytes """ buf = ffi.new("unsigned char[]", size) lib.randombytes(buf, size) return ffi.buffer(buf, size)[:]
def crypto_secretstream_xchacha20poly1305_keygen(): """ Generate a key for use with :func:`.crypto_secretstream_xchacha20poly1305_init_push`. """ keybuf = ffi.new( "unsigned char[]", crypto_secretstream_xchacha20poly1305_KEYBYTES, ) lib.crypto_secretstream_xchacha20poly1305_keygen(keybuf) return ffi.buffer(keybuf)[:]
def crypto_hash_sha512(message): """ Hashes and returns the message ``message``. :param message: bytes :rtype: bytes """ digest = ffi.new("unsigned char[]", crypto_hash_sha512_BYTES) rc = lib.crypto_hash_sha512(digest, message, len(message)) ensure(rc == 0, 'Unexpected library error', raising=exc.RuntimeError) return ffi.buffer(digest, crypto_hash_sha512_BYTES)[:]
def crypto_sign_seed_keypair(seed): """ Computes and returns the public key and secret key using the seed ``seed``. :param seed: bytes :rtype: (bytes(public_key), bytes(secret_key)) """ if len(seed) != crypto_sign_SEEDBYTES: raise exc.ValueError("Invalid seed") pk = ffi.new("unsigned char[]", crypto_sign_PUBLICKEYBYTES) sk = ffi.new("unsigned char[]", crypto_sign_SECRETKEYBYTES) rc = lib.crypto_sign_seed_keypair(pk, sk, seed) ensure(rc == 0, 'Unexpected library error', raising=exc.RuntimeError) return ( ffi.buffer(pk, crypto_sign_PUBLICKEYBYTES)[:], ffi.buffer(sk, crypto_sign_SECRETKEYBYTES)[:], )
def crypto_scalarmult_base(n): """ Computes and returns the scalar product of a standard group element and an integer ``n``. :param n: bytes :rtype: bytes """ q = ffi.new("unsigned char[]", crypto_scalarmult_BYTES) rc = lib.crypto_scalarmult_base(q, n) assert rc == 0 return ffi.buffer(q, crypto_scalarmult_SCALARBYTES)[:]
def crypto_kx_seed_keypair(seed): """ Generate a keypair with a given seed. This is functionally the same as crypto_box_seed_keypair, however it uses the blake2b hash primitive instead of sha512. It is included mainly for api consistency when using crypto_kx. :param seed: random seed :type seed: bytes :return: (public_key, secret_key) :rtype: (bytes, bytes) """ public_key = ffi.new("unsigned char[]", crypto_kx_PUBLIC_KEY_BYTES) secret_key = ffi.new("unsigned char[]", crypto_kx_SECRET_KEY_BYTES) ensure(isinstance(seed, bytes) and len(seed) == crypto_kx_SEED_BYTES, 'Seed must be a {0} byte long bytes sequence'.format( crypto_kx_SEED_BYTES), raising=exc.TypeError) res = lib.crypto_kx_seed_keypair(public_key, secret_key, seed) ensure(res == 0, "Key generation failed.", raising=exc.CryptoError) return (ffi.buffer(public_key, crypto_kx_PUBLIC_KEY_BYTES)[:], ffi.buffer(secret_key, crypto_kx_SECRET_KEY_BYTES)[:])
def crypto_box_seal_open(ciphertext, pk, sk): """ Decrypts and returns an encrypted message ``ciphertext``, using the recipent's secret key ``sk`` and the sender's ephemeral public key embedded in the sealed box. The box contruct nonce is derived from the recipient's public key ``pk`` and the sender's public key. :param ciphertext: bytes :param pk: bytes :param sk: bytes :rtype: bytes .. versionadded:: 1.2 """ ensure(isinstance(ciphertext, bytes), "input ciphertext must be bytes", raising=TypeError) ensure(isinstance(pk, bytes), "public key must be bytes", raising=TypeError) ensure(isinstance(sk, bytes), "secret key must be bytes", raising=TypeError) 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_SEALBYTES, ("Input cyphertext must be " "at least {} long").format(crypto_box_SEALBYTES), raising=exc.TypeError) _mlen = _clen - crypto_box_SEALBYTES # zero-length malloc results are implementation.dependent plaintext = ffi.new("unsigned char[]", max(1, _mlen)) res = lib.crypto_box_seal_open(plaintext, ciphertext, _clen, pk, sk) ensure(res == 0, "An error occurred trying to decrypt the message", raising=exc.CryptoError) return ffi.buffer(plaintext, _mlen)[:]
def generichash_blake2b_salt_personal(data, digest_size=crypto_generichash_BYTES, key=b'', salt=b'', person=b''): """One shot hash interface :param data: the input data to the hash function :param digest_size: must be at most :py:data:`.crypto_generichash_BYTES_MAX`; the default digest size is :py:data:`.crypto_generichash_BYTES` :type digest_size: int :param key: must be at most :py:data:`.crypto_generichash_KEYBYTES_MAX` long :type key: bytes :param salt: must be at most :py:data:`.crypto_generichash_SALTBYTES` long; will be zero-padded if needed :type salt: bytes :param person: must be at most :py:data:`.crypto_generichash_PERSONALBYTES` long: will be zero-padded if needed :type person: bytes :return: digest_size long digest :rtype: bytes """ _checkparams(digest_size, key, salt, person) ensure(isinstance(data, bytes), 'Input data must be a bytes sequence', raising=exc.TypeError) digest = ffi.new("unsigned char[]", digest_size) # both _salt and _personal must be zero-padded to the correct length _salt = ffi.new("unsigned char []", crypto_generichash_SALTBYTES) _person = ffi.new("unsigned char []", crypto_generichash_PERSONALBYTES) ffi.memmove(_salt, salt, len(salt)) ffi.memmove(_person, person, len(person)) rc = lib.crypto_generichash_blake2b_salt_personal(digest, digest_size, data, len(data), key, len(key), _salt, _person) ensure(rc == 0, 'Unexpected failure', raising=exc.RuntimeError) return ffi.buffer(digest, digest_size)[:]
def crypto_box_seed_keypair(seed): """ Returns a (public, secret) keypair deterministically generated from an input ``seed``. .. warning:: The seed **must** be high-entropy; therefore, its generator **must** be a cryptographic quality random function like, for example, :func:`~nacl.utils.random`. .. warning:: The seed **must** be protected and remain secret. Anyone who knows the seed is really in possession of the corresponding PrivateKey. :param seed: bytes :rtype: (bytes(public_key), bytes(secret_key)) """ ensure(isinstance(seed, bytes), "seed must be bytes", raising=TypeError) if len(seed) != crypto_box_SEEDBYTES: raise exc.ValueError("Invalid seed") pk = ffi.new("unsigned char[]", crypto_box_PUBLICKEYBYTES) sk = ffi.new("unsigned char[]", crypto_box_SECRETKEYBYTES) rc = lib.crypto_box_seed_keypair(pk, sk, seed) ensure(rc == 0, 'Unexpected library error', raising=exc.RuntimeError) return ( ffi.buffer(pk, crypto_box_PUBLICKEYBYTES)[:], ffi.buffer(sk, crypto_box_SECRETKEYBYTES)[:], )
def crypto_sign(message, sk): """ Signs the message ``message`` using the secret key ``sk`` and returns the signed message. :param message: bytes :param sk: bytes :rtype: bytes """ signed = ffi.new("unsigned char[]", len(message) + crypto_sign_BYTES) signed_len = ffi.new("unsigned long long *") rc = lib.crypto_sign(signed, signed_len, message, len(message), sk) assert rc == 0 return ffi.buffer(signed, signed_len[0])[:]
def crypto_scalarmult_base(n): """ Computes and returns the scalar product of a standard group element and an integer ``n``. :param n: bytes :rtype: bytes """ q = ffi.new("unsigned char[]", crypto_scalarmult_BYTES) rc = lib.crypto_scalarmult_base(q, n) ensure(rc == 0, 'Unexpected library error', raising=exc.RuntimeError) return ffi.buffer(q, crypto_scalarmult_SCALARBYTES)[:]