impuls/lib/python3.11/site-packages/nacl/bindings/crypto_aead.py

560 lines
15 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 typing import Optional
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: int = (
lib.crypto_aead_chacha20poly1305_ietf_keybytes()
)
crypto_aead_chacha20poly1305_ietf_NSECBYTES: int = (
lib.crypto_aead_chacha20poly1305_ietf_nsecbytes()
)
crypto_aead_chacha20poly1305_ietf_NPUBBYTES: int = (
lib.crypto_aead_chacha20poly1305_ietf_npubbytes()
)
crypto_aead_chacha20poly1305_ietf_ABYTES: int = (
lib.crypto_aead_chacha20poly1305_ietf_abytes()
)
crypto_aead_chacha20poly1305_ietf_MESSAGEBYTES_MAX: int = (
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: int = (
lib.crypto_aead_chacha20poly1305_keybytes()
)
crypto_aead_chacha20poly1305_NSECBYTES: int = (
lib.crypto_aead_chacha20poly1305_nsecbytes()
)
crypto_aead_chacha20poly1305_NPUBBYTES: int = (
lib.crypto_aead_chacha20poly1305_npubbytes()
)
crypto_aead_chacha20poly1305_ABYTES: int = (
lib.crypto_aead_chacha20poly1305_abytes()
)
crypto_aead_chacha20poly1305_MESSAGEBYTES_MAX: int = (
lib.crypto_aead_chacha20poly1305_messagebytes_max()
)
_aead_chacha20poly1305_CRYPTBYTES_MAX = (
crypto_aead_chacha20poly1305_MESSAGEBYTES_MAX
+ crypto_aead_chacha20poly1305_ABYTES
)
crypto_aead_xchacha20poly1305_ietf_KEYBYTES: int = (
lib.crypto_aead_xchacha20poly1305_ietf_keybytes()
)
crypto_aead_xchacha20poly1305_ietf_NSECBYTES: int = (
lib.crypto_aead_xchacha20poly1305_ietf_nsecbytes()
)
crypto_aead_xchacha20poly1305_ietf_NPUBBYTES: int = (
lib.crypto_aead_xchacha20poly1305_ietf_npubbytes()
)
crypto_aead_xchacha20poly1305_ietf_ABYTES: int = (
lib.crypto_aead_xchacha20poly1305_ietf_abytes()
)
crypto_aead_xchacha20poly1305_ietf_MESSAGEBYTES_MAX: int = (
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: bytes, aad: Optional[bytes], nonce: bytes, key: bytes
) -> bytes:
"""
Encrypt the given ``message`` using the IETF ratified chacha20poly1305
construction described in RFC7539.
:param message:
:type message: bytes
:param aad:
:type aad: Optional[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 {} 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 {} 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 {} 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: bytes, aad: Optional[bytes], nonce: bytes, key: bytes
) -> bytes:
"""
Decrypt the given ``ciphertext`` using the IETF ratified chacha20poly1305
construction described in RFC7539.
:param ciphertext:
:type ciphertext: bytes
:param aad:
:type aad: Optional[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 {} 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 {} 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 {} 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: bytes, aad: Optional[bytes], nonce: bytes, key: bytes
) -> bytes:
"""
Encrypt the given ``message`` using the "legacy" construction
described in draft-agl-tls-chacha20poly1305.
:param message:
:type message: bytes
:param aad:
:type aad: Optional[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 {} 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 {} 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 {} 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: bytes, aad: Optional[bytes], nonce: bytes, key: bytes
) -> bytes:
"""
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: Optional[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 {} 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 {} 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 {} 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: bytes, aad: Optional[bytes], nonce: bytes, key: bytes
) -> bytes:
"""
Encrypt the given ``message`` using the long-nonces xchacha20poly1305
construction.
:param message:
:type message: bytes
:param aad:
:type aad: Optional[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 {} 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 {} 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 {} 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: bytes, aad: Optional[bytes], nonce: bytes, key: bytes
) -> bytes:
"""
Decrypt the given ``ciphertext`` using the long-nonces xchacha20poly1305
construction.
:param ciphertext: authenticated ciphertext
:type ciphertext: bytes
:param aad:
:type aad: Optional[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 {} 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 {} 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 {} 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])[:]