Source code for securid.utils
#!/usr/bin/env python
from datetime import date, datetime
from typing import Optional, Union
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
try: # pragma: no cover
from secrets import SystemRandom # (Python >= 3.6) type: ignore
except ImportError: # pragma: no cover
from random import SystemRandom
__all__ = [
"AES_BLOCK_SIZE",
"AES_KEY_SIZE",
"Bytes",
"BytesStr",
"random",
"Bytearray",
"aes_ecb_encrypt",
"aes_ecb_decrypt",
"xor_block",
"cbc_hash",
"fromisoformat",
]
AES_BLOCK_SIZE = 16
AES_KEY_SIZE = 16
Bytes = Union[bytes, bytearray, "Bytearray"]
BytesStr = Union[bytes, bytearray, str, "Bytearray"]
random = SystemRandom()
[docs]
class Bytearray(bytearray):
def arrayset(self, c: int, n: int, dest_offset: int = 0) -> None:
self[dest_offset : dest_offset + n] = [c] * n
def arraycpy(self, src: BytesStr, n: Optional[int] = None, dest_offset: int = 0) -> None:
if isinstance(src, str):
src = bytes(src, "ascii")
if n is None:
n = len(src)
n = min(n, len(self) - dest_offset, len(src))
self[dest_offset : dest_offset + n] = src[0:n]
[docs]
def aes_ecb_encrypt(key: Bytes, data: Bytes) -> bytes:
"""
Encrypt data with the key using AES-128 ECB
"""
cipher = Cipher(algorithms.AES(bytes(key)), modes.ECB())
encryptor = cipher.encryptor() # type: ignore
return encryptor.update(bytes(data)) # type: ignore
[docs]
def aes_ecb_decrypt(key: Bytes, data: Bytes) -> bytes:
"""
Decrypt data with the key using AES-128 ECB
"""
cipher = Cipher(algorithms.AES(bytes(key)), modes.ECB())
decryptor = cipher.decryptor() # type: ignore
return decryptor.update(bytes(data)) # type: ignore
def xor_block(a: Bytes, b: Bytes) -> bytes:
return bytes(a[i] ^ (b[i] if i < len(b) else 0) for i in range(0, len(a)))
[docs]
def cbc_hash(key: Bytes, iv: Bytes, data: Bytes) -> bytes:
"""
Calculate cipher block chaining message authentication code
"""
result = bytes(iv)
while len(data) > 0:
result = aes_ecb_encrypt(key, xor_block(result, data))
data = data[AES_BLOCK_SIZE:]
return bytes(result)