tuxbot-bot/venv/lib/python3.7/site-packages/nacl/bindings/crypto_aead.py
2019-12-16 18:12:10 +01:00

485 lines
17 KiB
Python

# 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
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_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])[:]
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])[:]
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])[:]
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])[:]
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])[:]