Example #1
0
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)[:]
Example #2
0
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_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
Example #4
0
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)[:]
Example #5
0
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)[:])
Example #6
0
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)[:]
Example #7
0
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)[:]
Example #8
0
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)[:]
Example #9
0
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)[:]
Example #10
0
def generichash_blake2b_state_copy(statebuf):
    """Return a copy of the given blake2b hash state"""

    newstate = ffi.new("unsigned char[]", crypto_generichash_STATEBYTES)
    ffi.memmove(newstate, statebuf, crypto_generichash_STATEBYTES)

    return newstate
Example #11
0
def crypto_pwhash_scryptsalsa208sha256_str(
        passwd, opslimit=SCRYPT_OPSLIMIT_INTERACTIVE,
        memlimit=SCRYPT_MEMLIMIT_INTERACTIVE):
    """
    Derive a cryptographic key using the ``passwd`` and ``salt``
    given as input, returning a string representation which includes
    the salt and the tuning parameters.

    The returned string can be directly stored as a password hash.

    See :py:func:`.crypto_pwhash_scryptsalsa208sha256` for a short
    discussion about ``opslimit`` and ``memlimit`` values.

    :param bytes passwd:
    :param int opslimit:
    :param int memlimit:
    :return: serialized key hash, including salt and tuning parameters
    :rtype: bytes
    """
    buf = ffi.new("char[]", SCRYPT_STRBYTES)

    ret = lib.crypto_pwhash_scryptsalsa208sha256_str(buf, passwd,
                                                     len(passwd),
                                                     opslimit,
                                                     memlimit)

    ensure(ret == 0, 'Unexpected failure in password hashing',
           raising=exc.RuntimeError)

    return ffi.string(buf)
Example #12
0
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:]
Example #13
0
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:]
Example #14
0
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])[:]
Example #15
0
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)[:],
    )
Example #16
0
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:]
Example #17
0
def crypto_pwhash_str_alg(passwd, opslimit, memlimit, alg):
    """
    Derive a cryptographic key using the ``passwd`` given as input
    and a random ``salt``, returning a string representation which
    includes the salt, the tuning parameters and the used algorithm.

    :param passwd: The input password
    :type passwd: bytes
    :param opslimit: computational cost
    :type opslimit: int
    :param memlimit: memory cost
    :type memlimit: int
    :param alg: The algorithm to use
    :type alg: int
    :return: serialized derived key and parameters
    :rtype: bytes
    """
    ensure(isinstance(opslimit, integer_types),
           raising=TypeError)
    ensure(isinstance(memlimit, integer_types),
           raising=TypeError)
    ensure(isinstance(passwd, bytes),
           raising=TypeError)

    _check_argon2_limits_alg(opslimit, memlimit, alg)

    outbuf = ffi.new("char[]", 128)

    ret = lib.crypto_pwhash_str_alg(outbuf, passwd, len(passwd),
                                    opslimit, memlimit, alg)

    ensure(ret == 0, 'Unexpected failure in key derivation',
           raising=exc.RuntimeError)

    return ffi.string(outbuf)
Example #18
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:]
Example #19
0
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:]
Example #20
0
def crypto_sign_open(signed, pk):
    """
    Verifies the signature of the signed message ``signed`` using the public
    key ``pk`` and returns the unsigned message.

    :param signed: bytes
    :param pk: bytes
    :rtype: bytes
    """
    message = ffi.new("unsigned char[]", len(signed))
    message_len = ffi.new("unsigned long long *")

    if lib.crypto_sign_open(
            message, message_len, signed, len(signed), pk) != 0:
        raise exc.BadSignatureError("Signature was forged or corrupt")

    return ffi.buffer(message, message_len[0])[:]
Example #21
0
def generichash_blake2b_init(key=b'', salt=b'',
                             person=b'',
                             digest_size=crypto_generichash_BYTES):
    """
    Create a new initialized blake2b hash state

    :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
    :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
    :return: an initizialized state buffer
    :rtype: bytes
    """

    _checkparams(digest_size, key, salt, person)

    statebuf = ffi.new("unsigned char[]", crypto_generichash_STATEBYTES)

    # 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_init_salt_personal(statebuf,
                                                           key, len(key),
                                                           digest_size,
                                                           _salt, _person)
    ensure(rc == 0, 'Unexpected failure',
           raising=exc.RuntimeError)

    return statebuf
Example #22
0
    def __init__(self):
        self.state = ffi.new('unsigned char[]',
                             crypto_sign_ed25519ph_STATEBYTES)

        rc = lib.crypto_sign_ed25519ph_init(self.state)

        ensure(rc == 0,
               'Unexpected library error',
               raising=exc.RuntimeError)
Example #23
0
    def __init__(self):
        """ Initialize a clean state object."""
        self.statebuf = ffi.new(
            "unsigned char[]",
            crypto_secretstream_xchacha20poly1305_STATEBYTES,
        )

        self.rawbuf = None
        self.tagbuf = None
Example #24
0
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)[:],
    )
Example #25
0
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)
    ensure(rc == 0,
           'Unexpected library error',
           raising=exc.RuntimeError)

    return ffi.buffer(signed, signed_len[0])[:]
Example #26
0
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)[:])
Example #27
0
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)[:],
    )
Example #28
0
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)[:]
Example #29
0
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)[:]
Example #30
0
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)[:]
Example #31
0
def crypto_core_ed25519_add(p, q):
    """
    Add two points 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_add(r, p, q)
    ensure(rc == 0, "Unexpected library error", raising=exc.RuntimeError)

    return ffi.buffer(r, crypto_core_ed25519_BYTES)[:]
Example #32
0
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)[:]
Example #33
0
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)[:]
Example #34
0
def crypto_pwhash_scryptsalsa208sha256_str(
        passwd,
        opslimit=SCRYPT_OPSLIMIT_INTERACTIVE,
        memlimit=SCRYPT_MEMLIMIT_INTERACTIVE):
    """
    Derive a cryptographic key using the ``passwd`` and ``salt``
    given as input, returning a string representation which includes
    the salt and the tuning parameters.

    The returned string can be directly stored as a password hash.

    See :py:func:`.crypto_pwhash_scryptsalsa208sha256` for a short
    discussion about ``opslimit`` and ``memlimit`` values.

    :param bytes passwd:
    :param int opslimit:
    :param int memlimit:
    :return: serialized key hash, including salt and tuning parameters
    :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)

    buf = ffi.new("char[]", SCRYPT_STRBYTES)

    ret = lib.crypto_pwhash_scryptsalsa208sha256_str(buf, passwd, len(passwd),
                                                     opslimit, memlimit)

    ensure(ret == 0,
           'Unexpected failure in password hashing',
           raising=exc.RuntimeError)

    return ffi.string(buf)
Example #35
0
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 ValueError("Invalid nonce")

    if len(k) != crypto_box_BEFORENMBYTES:
        raise ValueError("Invalid shared key")

    padded = (b"\x00" * crypto_box_BOXZEROBYTES) + ciphertext
    plaintext = ffi.new("unsigned char[]", len(padded))

    if lib.crypto_box_open_afternm(
            plaintext, padded, len(padded), nonce, k) != 0:
        raise CryptoError("An error occurred trying to decrypt the message")

    return ffi.buffer(plaintext, len(padded))[crypto_box_ZEROBYTES:]
Example #36
0
def crypto_secretbox(message, nonce, key):
    """
    Encrypts and returns the message ``message`` with the secret ``key`` and
    the nonce ``nonce``.

    :param message: 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_ZEROBYTES + message
    ciphertext = ffi.new("unsigned char[]", len(padded))

    res = lib.crypto_secretbox(ciphertext, padded, len(padded), nonce, key)
    ensure(res == 0, "Encryption failed", raising=exc.CryptoError)

    ciphertext = ffi.buffer(ciphertext, len(padded))
    return ciphertext[crypto_secretbox_BOXZEROBYTES:]
Example #37
0
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)[:]
Example #38
0
def crypto_box_beforenm(pk, sk):
    """
    Computes and returns the shared key for the public key ``pk`` and the
    secret key ``sk``. This can be used to speed up operations where the same
    set of keys is going to be used multiple times.

    :param pk: bytes
    :param sk: bytes
    :rtype: bytes
    """
    if len(pk) != crypto_box_PUBLICKEYBYTES:
        raise exc.ValueError("Invalid public key")

    if len(sk) != crypto_box_SECRETKEYBYTES:
        raise exc.ValueError("Invalid secret key")

    k = ffi.new("unsigned char[]", crypto_box_BEFORENMBYTES)

    rc = lib.crypto_box_beforenm(k, pk, sk)
    ensure(rc == 0,
           'Unexpected library error',
           raising=exc.RuntimeError)

    return ffi.buffer(k, crypto_box_BEFORENMBYTES)[:]
Example #39
0
def crypto_sign_ed25519_sk_to_curve25519(secret_key_bytes):
    """
    Converts a secret Ed25519 key (encoded as bytes ``secret_key_bytes``) to
    a secret Curve25519 key as bytes.

    Raises a ValueError if ``secret_key_bytes``is not of length
    ``crypto_sign_SECRETKEYBYTES``

    :param public_key_bytes: bytes
    :rtype: bytes
    """
    if len(secret_key_bytes) != crypto_sign_SECRETKEYBYTES:
        raise exc.ValueError("Invalid curve public key")

    curve_secret_key_len = crypto_sign_curve25519_BYTES
    curve_secret_key = ffi.new("unsigned char[]", curve_secret_key_len)

    rc = lib.crypto_sign_ed25519_sk_to_curve25519(curve_secret_key,
                                                  secret_key_bytes)
    ensure(rc == 0,
           'Unexpected library error',
           raising=exc.RuntimeError)

    return ffi.buffer(curve_secret_key, curve_secret_key_len)[:]
Example #40
0
def crypto_scalarmult_ed25519_noclamp(n, p):
    """
    Computes and returns the scalar product of an integer ``n``
    and the given group element on the edwards25519 curve. The integer
    ``n`` is not clamped.

    :param n: a :py:data:`.crypto_scalarmult_ed25519_SCALARBYTES` long bytes
              sequence representing a scalar
    :type n: bytes
    :param p: a :py:data:`.crypto_scalarmult_ed25519_BYTES` long bytes sequence
              representing a point on the edwards25519 curve
    :type p: 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)

    ensure(isinstance(p, bytes) and
           len(p) == crypto_scalarmult_ed25519_BYTES,
           'Input must be a {} long bytes sequence'.format(
           'crypto_scalarmult_ed25519_BYTES'),
           raising=exc.TypeError)

    q = ffi.new("unsigned char[]", crypto_scalarmult_ed25519_BYTES)

    rc = lib.crypto_scalarmult_ed25519_noclamp(q, n, p)
    ensure(rc == 0,
           'Unexpected library error',
           raising=exc.RuntimeError)

    return ffi.buffer(q, crypto_scalarmult_ed25519_BYTES)[:]
Example #41
0
def crypto_stream_chacha20_keygen():
    outbuf = ffi.new("unsigned char[]", crypto_stream_chacha20_KEYBYTES)
    lib.crypto_stream_chacha20_keygen(outbuf)
    return ffi.buffer(outbuf, crypto_stream_chacha20_KEYBYTES)[:]
Example #42
0
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
    """
    ensure(isinstance(data, bytes),
           'Input data must be a bytes sequence',
           raising=exc.TypeError)

    ensure(isinstance(key, bytes),
           'Key must be a bytes sequence',
           raising=exc.TypeError)

    ensure(isinstance(salt, bytes),
           'Salt must be a bytes sequence',
           raising=exc.TypeError)

    ensure(isinstance(person, bytes),
           'Person must be a bytes sequence',
           raising=exc.TypeError)

    ensure(isinstance(digest_size, integer_types),
           'Digest size must be an integer number',
           raising=exc.TypeError)

    ensure(digest_size <= crypto_generichash_BYTES_MAX,
           _TOOBIG.format("Digest_size", crypto_generichash_BYTES_MAX),
           raising=exc.ValueError)

    ensure(len(key) <= crypto_generichash_KEYBYTES_MAX,
           _OVERLONG.format("Key", crypto_generichash_KEYBYTES_MAX),
           raising=exc.ValueError)

    ensure(len(salt) <= crypto_generichash_SALTBYTES,
           _OVERLONG.format("Salt", crypto_generichash_SALTBYTES),
           raising=exc.ValueError)

    ensure(len(person) <= crypto_generichash_PERSONALBYTES,
           _OVERLONG.format("Person", crypto_generichash_PERSONALBYTES),
           raising=exc.ValueError)

    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_secretstream_xchacha20poly1305_push(
    state,
    m,
    ad=None,
    tag=crypto_secretstream_xchacha20poly1305_TAG_MESSAGE,
):
    """
    Add an encrypted message to the secret stream.

    :param state: a secretstream state object
    :type state: crypto_secretstream_xchacha20poly1305_state
    :param m: the message to encrypt, the maximum length of an individual
              message is
              :data:`.crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX`.
    :type m: bytes
    :param ad: additional data to include in the authentication tag
    :type ad: bytes or None
    :param tag: the message tag, usually
                :data:`.crypto_secretstream_xchacha20poly1305_TAG_MESSAGE` or
                :data:`.crypto_secretstream_xchacha20poly1305_TAG_FINAL`.
    :type tag: int
    :return: ciphertext
    :rtype: bytes

    """
    ensure(
        isinstance(state, crypto_secretstream_xchacha20poly1305_state),
        'State must be a crypto_secretstream_xchacha20poly1305_state object',
        raising=exc.TypeError,
    )
    ensure(isinstance(m, bytes), 'Message is not bytes', raising=exc.TypeError)
    ensure(
        len(m) <= crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX,
        'Message is too long',
        raising=exc.ValueError,
    )
    ensure(
        ad is None or isinstance(ad, bytes),
        'Additional data must be bytes or None',
        raising=exc.TypeError,
    )

    clen = len(m) + crypto_secretstream_xchacha20poly1305_ABYTES
    if state.rawbuf is None or len(state.rawbuf) < clen:
        state.rawbuf = ffi.new('unsigned char[]', clen)

    if ad is None:
        ad = ffi.NULL
        adlen = 0
    else:
        adlen = len(ad)

    rc = lib.crypto_secretstream_xchacha20poly1305_push(
        state.statebuf,
        state.rawbuf,
        ffi.NULL,
        m,
        len(m),
        ad,
        adlen,
        tag,
    )
    ensure(rc == 0, 'Unexpected failure', raising=exc.RuntimeError)

    return ffi.buffer(state.rawbuf, clen)[:]
def crypto_aead_chacha20poly1305_ietf_encrypt(message, aad, nonce, key):
    """
    Encrypt the given ``message`` using the IETF ratified chacha20poly1305
    construction described in RFC7539.

    :param message:
    :type message: bytes
    :param aad:
    :type aad: bytes
    :param nonce:
    :type nonce: bytes
    :param key:
    :type key: bytes
    :return: authenticated ciphertext
    :rtype: bytes
    """
    ensure(
        isinstance(message, bytes),
        "Input message type must be bytes",
        raising=exc.TypeError,
    )

    mlen = len(message)

    ensure(
        mlen <= crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX,
        "Message must be at most {0} bytes long".format(
            crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX),
        raising=exc.ValueError,
    )

    ensure(
        isinstance(aad, bytes) or (aad is None),
        "Additional data must be bytes or None",
        raising=exc.TypeError,
    )

    ensure(
        isinstance(nonce, bytes)
        and len(nonce) == crypto_aead_chacha20poly1305_ietf_NPUBBYTES,
        "Nonce must be a {0} bytes long bytes sequence".format(
            crypto_aead_chacha20poly1305_ietf_NPUBBYTES),
        raising=exc.TypeError,
    )

    ensure(
        isinstance(key, bytes)
        and len(key) == crypto_aead_chacha20poly1305_ietf_KEYBYTES,
        "Key must be a {0} bytes long bytes sequence".format(
            crypto_aead_chacha20poly1305_ietf_KEYBYTES),
        raising=exc.TypeError,
    )

    if aad:
        _aad = aad
        aalen = len(aad)
    else:
        _aad = ffi.NULL
        aalen = 0

    mxout = mlen + crypto_aead_chacha20poly1305_ietf_ABYTES

    clen = ffi.new("unsigned long long *")

    ciphertext = ffi.new("unsigned char[]", mxout)

    res = lib.crypto_aead_chacha20poly1305_ietf_encrypt(
        ciphertext, clen, message, mlen, _aad, aalen, ffi.NULL, nonce, key)

    ensure(res == 0, "Encryption failed.", raising=exc.CryptoError)
    return ffi.buffer(ciphertext, clen[0])[:]
def crypto_aead_xchacha20poly1305_ietf_decrypt(ciphertext, aad, nonce, key):
    """
    Decrypt the given ``ciphertext`` using the long-nonces xchacha20poly1305
    construction.

    :param ciphertext: authenticated ciphertext
    :type ciphertext: bytes
    :param aad:
    :type aad: bytes
    :param nonce:
    :type nonce: bytes
    :param key:
    :type key: bytes
    :return: message
    :rtype: bytes
    """
    ensure(
        isinstance(ciphertext, bytes),
        "Input ciphertext type must be bytes",
        raising=exc.TypeError,
    )

    clen = len(ciphertext)

    ensure(
        clen <= _aead_xchacha20poly1305_ietf_CRYPTBYTES_MAX,
        "Ciphertext must be at most {0} bytes long".format(
            _aead_xchacha20poly1305_ietf_CRYPTBYTES_MAX),
        raising=exc.ValueError,
    )

    ensure(
        isinstance(aad, bytes) or (aad is None),
        "Additional data must be bytes or None",
        raising=exc.TypeError,
    )

    ensure(
        isinstance(nonce, bytes)
        and len(nonce) == crypto_aead_xchacha20poly1305_ietf_NPUBBYTES,
        "Nonce must be a {0} bytes long bytes sequence".format(
            crypto_aead_xchacha20poly1305_ietf_NPUBBYTES),
        raising=exc.TypeError,
    )

    ensure(
        isinstance(key, bytes)
        and len(key) == crypto_aead_xchacha20poly1305_ietf_KEYBYTES,
        "Key must be a {0} bytes long bytes sequence".format(
            crypto_aead_xchacha20poly1305_ietf_KEYBYTES),
        raising=exc.TypeError,
    )

    mxout = clen - crypto_aead_xchacha20poly1305_ietf_ABYTES
    mlen = ffi.new("unsigned long long *")
    message = ffi.new("unsigned char[]", mxout)

    if aad:
        _aad = aad
        aalen = len(aad)
    else:
        _aad = ffi.NULL
        aalen = 0

    res = lib.crypto_aead_xchacha20poly1305_ietf_decrypt(
        message, mlen, ffi.NULL, ciphertext, clen, _aad, aalen, nonce, key)

    ensure(res == 0, "Decryption failed.", raising=exc.CryptoError)

    return ffi.buffer(message, mlen[0])[:]
Example #46
0
def crypto_pwhash_argon2i(outlen, passwd, salt, opslimit, memlimit, alg):
    """
    Derive a raw cryptographic key using the ``passwd`` and the ``salt``
    given as input.

    :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_argon2i_SALTBYTES:
        raise exc.ValueError(
            ("salt must be exactly {0} "
             "bytes long").format(crypto_pwhash_argon2i_SALTBYTES))

    if outlen < crypto_pwhash_argon2i_BYTES_MIN:
        raise exc.ValueError((
            'derived key must be '
            'at least {0} bytes long').format(crypto_pwhash_argon2i_BYTES_MIN))

    elif outlen > crypto_pwhash_argon2i_BYTES_MAX:
        raise exc.ValueError(
            ('derived key must be '
             'at most {0} bytes long').format(crypto_pwhash_argon2i_BYTES_MAX))

    if memlimit < crypto_pwhash_argon2i_MEMLIMIT_MIN:
        raise exc.ValueError(
            ('memlimit must be '
             'at least {0} bytes').format(crypto_pwhash_argon2i_MEMLIMIT_MIN))

    elif memlimit > crypto_pwhash_argon2i_MEMLIMIT_MAX:
        raise exc.ValueError(
            ('memlimit must be '
             'at most {0} bytes').format(crypto_pwhash_argon2i_MEMLIMIT_MAX))

    if opslimit < crypto_pwhash_argon2i_OPSLIMIT_MIN:
        raise exc.ValueError(
            ('opslimit must be '
             'at least {0}').format(crypto_pwhash_argon2i_OPSLIMIT_MIN))

    elif opslimit > crypto_pwhash_argon2i_OPSLIMIT_MAX:
        raise exc.ValueError(
            ('opslimit must be '
             'at most {0}').format(crypto_pwhash_argon2i_OPSLIMIT_MAX))

    outbuf = ffi.new("unsigned char[]", outlen)

    ret = lib.crypto_pwhash_argon2i(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_secretstream_xchacha20poly1305_pull(state, c, ad=None):
    """
    Read a decrypted message from the secret stream.

    :param state: a secretstream state object
    :type state: crypto_secretstream_xchacha20poly1305_state
    :param c: the ciphertext to decrypt, the maximum length of an individual
              ciphertext is
              :data:`.crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX` +
              :data:`.crypto_secretstream_xchacha20poly1305_ABYTES`.
    :type c: bytes
    :param ad: additional data to include in the authentication tag
    :type ad: bytes or None
    :return: (message, tag)
    :rtype: (bytes, int)

    """
    ensure(
        isinstance(state, crypto_secretstream_xchacha20poly1305_state),
        'State must be a crypto_secretstream_xchacha20poly1305_state object',
        raising=exc.TypeError,
    )
    ensure(
        state.tagbuf is not None,
        ('State must be initialized using '
         'crypto_secretstream_xchacha20poly1305_init_pull'),
        raising=exc.ValueError,
    )
    ensure(
        isinstance(c, bytes),
        'Ciphertext is not bytes',
        raising=exc.TypeError,
    )
    ensure(
        len(c) > crypto_secretstream_xchacha20poly1305_ABYTES,
        'Ciphertext is too short',
        raising=exc.ValueError,
    )
    ensure(
        len(c) <= (crypto_secretstream_xchacha20poly1305_MESSAGEBYTES_MAX +
                   crypto_secretstream_xchacha20poly1305_ABYTES),
        'Ciphertext is too long',
        raising=exc.ValueError,
    )
    ensure(
        ad is None or isinstance(ad, bytes),
        'Additional data must be bytes or None',
        raising=exc.TypeError,
    )

    mlen = len(c) - crypto_secretstream_xchacha20poly1305_ABYTES
    if state.rawbuf is None or len(state.rawbuf) < mlen:
        state.rawbuf = ffi.new('unsigned char[]', mlen)

    if ad is None:
        ad = ffi.NULL
        adlen = 0
    else:
        adlen = len(ad)

    rc = lib.crypto_secretstream_xchacha20poly1305_pull(
        state.statebuf,
        state.rawbuf,
        ffi.NULL,
        state.tagbuf,
        c,
        len(c),
        ad,
        adlen,
    )
    ensure(rc == 0, 'Unexpected failure', raising=exc.RuntimeError)

    return (ffi.buffer(state.rawbuf, mlen)[:], int(state.tagbuf[0]))
Example #48
0
 def __init__(self, digest_size):
     self._statebuf = ffi.new("unsigned char[]",
                              crypto_generichash_STATEBYTES)
     self.digest_size = digest_size