Source code for nacl.bindings.crypto_aead

# Copyright 2017 Donald Stufft and individual contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from __future__ import absolute_import, division, print_function

from nacl import exceptions as exc
from nacl._sodium import ffi, lib
from nacl.exceptions import ensure

"""
Implementations of authenticated encription with associated data (*AEAD*)
constructions building on the chacha20 stream cipher and the poly1305
authenticator
"""

crypto_aead_chacha20poly1305_ietf_KEYBYTES = \
    lib.crypto_aead_chacha20poly1305_ietf_keybytes()
crypto_aead_chacha20poly1305_ietf_NSECBYTES = \
    lib.crypto_aead_chacha20poly1305_ietf_nsecbytes()
crypto_aead_chacha20poly1305_ietf_NPUBBYTES = \
    lib.crypto_aead_chacha20poly1305_ietf_npubbytes()
crypto_aead_chacha20poly1305_ietf_ABYTES = \
    lib.crypto_aead_chacha20poly1305_ietf_abytes()
crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX = \
    lib.crypto_aead_chacha20poly1305_ietf_messagebytes_max()
_aead_chacha20poly1305_ietf_CRYPTBYTES_MAX = \
    crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX + \
    crypto_aead_chacha20poly1305_ietf_ABYTES

crypto_aead_chacha20poly1305_KEYBYTES = \
    lib.crypto_aead_chacha20poly1305_keybytes()
crypto_aead_chacha20poly1305_NSECBYTES = \
    lib.crypto_aead_chacha20poly1305_nsecbytes()
crypto_aead_chacha20poly1305_NPUBBYTES = \
    lib.crypto_aead_chacha20poly1305_npubbytes()
crypto_aead_chacha20poly1305_ABYTES = \
    lib.crypto_aead_chacha20poly1305_abytes()
crypto_aead_chacha20poly1305_MESSAGEBYTES_MAX = \
    lib.crypto_aead_chacha20poly1305_messagebytes_max()
_aead_chacha20poly1305_CRYPTBYTES_MAX = \
    crypto_aead_chacha20poly1305_MESSAGEBYTES_MAX + \
    crypto_aead_chacha20poly1305_ABYTES

crypto_aead_xchacha20poly1305_ietf_KEYBYTES = \
    lib.crypto_aead_xchacha20poly1305_ietf_keybytes()
crypto_aead_xchacha20poly1305_ietf_NSECBYTES = \
    lib.crypto_aead_xchacha20poly1305_ietf_nsecbytes()
crypto_aead_xchacha20poly1305_ietf_NPUBBYTES = \
    lib.crypto_aead_xchacha20poly1305_ietf_npubbytes()
crypto_aead_xchacha20poly1305_ietf_ABYTES = \
    lib.crypto_aead_xchacha20poly1305_ietf_abytes()
crypto_aead_xchacha20poly1305_ietf_MESSAGEBYTES_MAX = \
    lib.crypto_aead_xchacha20poly1305_ietf_messagebytes_max()
_aead_xchacha20poly1305_ietf_CRYPTBYTES_MAX = \
    crypto_aead_xchacha20poly1305_ietf_MESSAGEBYTES_MAX + \
    crypto_aead_xchacha20poly1305_ietf_ABYTES


[docs]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])[:]
[docs]def crypto_aead_chacha20poly1305_ietf_decrypt(ciphertext, aad, nonce, key): """ Decrypt the given ``ciphertext`` using the IETF ratified chacha20poly1305 construction described in RFC7539. :param 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_chacha20poly1305_ietf_CRYPTBYTES_MAX, 'Ciphertext must be at most {0} bytes long'.format( _aead_chacha20poly1305_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_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) mxout = clen - crypto_aead_chacha20poly1305_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_chacha20poly1305_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])[:]
[docs]def crypto_aead_chacha20poly1305_encrypt(message, aad, nonce, key): """ Encrypt the given ``message`` using the "legacy" construction described in draft-agl-tls-chacha20poly1305. :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_MESSAGEBYTES_MAX, 'Message must be at most {0} bytes long'.format( crypto_aead_chacha20poly1305_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_NPUBBYTES, 'Nonce must be a {0} bytes long bytes sequence'.format( crypto_aead_chacha20poly1305_NPUBBYTES), raising=exc.TypeError) ensure(isinstance(key, bytes) and len(key) == crypto_aead_chacha20poly1305_KEYBYTES, 'Key must be a {0} bytes long bytes sequence'.format( crypto_aead_chacha20poly1305_KEYBYTES), raising=exc.TypeError) if aad: _aad = aad aalen = len(aad) else: _aad = ffi.NULL aalen = 0 mlen = len(message) mxout = mlen + crypto_aead_chacha20poly1305_ietf_ABYTES clen = ffi.new("unsigned long long *") ciphertext = ffi.new("unsigned char[]", mxout) res = lib.crypto_aead_chacha20poly1305_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])[:]
[docs]def crypto_aead_chacha20poly1305_decrypt(ciphertext, aad, nonce, key): """ Decrypt the given ``ciphertext`` using the "legacy" construction described in draft-agl-tls-chacha20poly1305. :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_chacha20poly1305_CRYPTBYTES_MAX, 'Ciphertext must be at most {0} bytes long'.format( _aead_chacha20poly1305_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_chacha20poly1305_NPUBBYTES, 'Nonce must be a {0} bytes long bytes sequence'.format( crypto_aead_chacha20poly1305_NPUBBYTES), raising=exc.TypeError) ensure(isinstance(key, bytes) and len(key) == crypto_aead_chacha20poly1305_KEYBYTES, 'Key must be a {0} bytes long bytes sequence'.format( crypto_aead_chacha20poly1305_KEYBYTES), raising=exc.TypeError) mxout = clen - crypto_aead_chacha20poly1305_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_chacha20poly1305_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])[:]
[docs]def crypto_aead_xchacha20poly1305_ietf_encrypt(message, aad, nonce, key): """ Encrypt the given ``message`` using the long-nonces xchacha20poly1305 construction. :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_xchacha20poly1305_ietf_MESSAGEBYTES_MAX, 'Message must be at most {0} bytes long'.format( crypto_aead_xchacha20poly1305_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_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) if aad: _aad = aad aalen = len(aad) else: _aad = ffi.NULL aalen = 0 mlen = len(message) mxout = mlen + crypto_aead_xchacha20poly1305_ietf_ABYTES clen = ffi.new("unsigned long long *") ciphertext = ffi.new("unsigned char[]", mxout) res = lib.crypto_aead_xchacha20poly1305_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])[:]
[docs]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])[:]