Source code for pyflocker.ciphers.backends.cryptodome_.symmetric
"""Cryptodome backend specific templates and tools for symmetric ciphers."""
from __future__ import annotations
import typing
from pyflocker.ciphers import base, exc
[docs]
class NonAEADCipherTemplate(base.BaseNonAEADCipher):
"""
Template class to provide the default behavior of BaseNonAEADCipher.
Subclasses need to provide:
- ``_encrypting``
- ``_update_func``
"""
# these are *not* class variables
_encrypting: bool
_update_func: typing.Callable | None
[docs]
def update(self, data: bytes) -> bytes:
if self._update_func is None:
raise exc.AlreadyFinalized
return self._update_func(data)
[docs]
def update_into(
self,
data: bytes,
out: bytearray | memoryview,
) -> None:
if self._update_func is None:
raise exc.AlreadyFinalized
self._update_func(data, out)
[docs]
def finalize(self) -> None:
if not self._update_func:
raise exc.AlreadyFinalized
self._update_func = None
[docs]
class AuthenticationMixin:
"""Mixin class to provide authentication behavior to ciphers.
Classes inheriting this must provide these attributes:
Attributes:
_updated:
A boolean indicating whether ``update()`` method of ``_cipher`` was
called.
_cipher:
A cipher from Cryptodome package that has ``update()`` and
``verify()`` methods.
_update_func:
A method of ``_cipher`` that encrypts/decrypts data. It is
generally ``_cipher.encrypt()`` or ``_cipher.decrypt()``.
_tag:
A byte sequence denoting the MAC tag generated by the cipher after
encryption.
"""
_updated: bool
_cipher: typing.Any
_update_func: typing.Callable
_tag: bytes | None
[docs]
def authenticate(self, data: bytes) -> None:
if self._update_func is None:
raise exc.AlreadyFinalized
if self._updated:
raise TypeError
assert self._cipher is not None
self._cipher.update(data)
[docs]
def finalize(self, tag: bytes | None = None) -> None:
if self._update_func is None:
raise exc.AlreadyFinalized
if self.is_encrypting(): # type: ignore
self._tag, self._cipher = self._cipher.digest(), None
self._update_func = None # type: ignore
return
if tag is None:
msg = "tag is required for finalization"
raise ValueError(msg)
cipher, self._cipher = self._cipher, None
self._update_func = None # type: ignore
try:
cipher.verify(tag)
except ValueError as e:
raise exc.DecryptionError from e
[docs]
def calculate_tag(self) -> bytes | None:
if self._update_func is not None:
raise exc.NotFinalized
return self._tag
authenticate.__doc__ = base.BaseAEADCipher.authenticate.__doc__
finalize.__doc__ = base.BaseAEADCipher.finalize.__doc__
calculate_tag.__doc__ = base.BaseAEADCipher.calculate_tag.__doc__
[docs]
class AEADCipherTemplate(AuthenticationMixin, base.BaseAEADCipher):
"""
Template class to provide the default behavior of BaseAEADCipher.
Subclasses need to provide the following attributes:
- ``_encrypting``
- ``_update_func``
- ``_cipher``
"""
_encrypting: bool
[docs]
def update(self, data: bytes) -> bytes:
self._updated = True
if self._update_func is None:
raise exc.AlreadyFinalized
return self._update_func(data)
[docs]
def update_into(
self,
data: bytes,
out: bytearray | memoryview,
) -> None:
self._updated = True
if self._update_func is None:
raise exc.AlreadyFinalized
self._update_func(data, out)