Source code for mimesis.providers.cryptographic
"""Pseudo-cryptographic data provider."""
import hashlib
import json
import time
import typing as t
from base64 import urlsafe_b64encode
from uuid import UUID
from mimesis.datasets.int.cryptographic import WORDLIST
from mimesis.enums import Algorithm
from mimesis.providers.base import BaseProvider
__all__ = ["Cryptographic"]
[docs]
class Cryptographic(BaseProvider):
"""Class that provides **pseudo**-cryptographic data."""
class Meta:
name = "cryptographic"
[docs]
def uuid_object(self) -> UUID:
"""Generates UUID4 object.
:return: UUID4 object.
"""
rand_bits = self.random.getrandbits(128)
return UUID(int=rand_bits, version=4)
[docs]
def uuid(self) -> str:
"""Generates UUID4 string.
:return: UUID4 as string.
"""
return str(self.uuid_object())
[docs]
def hash(self, algorithm: Algorithm | None = None) -> str: # noqa: A003
"""Generates random hash.
To change hashing algorithm, pass parameter ``algorithm``
with needed value of the enum object :class:`~mimesis.enums.Algorithm`
:param algorithm: Enum object :class:`~mimesis.enums.Algorithm`.
:return: Hash.
:raises NonEnumerableError: When algorithm is unsupported.
"""
key = self.validate_enum(algorithm, Algorithm)
func = getattr(hashlib, key)
value = func(self.uuid().encode())
if key in ("shake_128", "shake_256"):
return str(value.hexdigest(32))
return str(value.hexdigest())
[docs]
def token_bytes(self, entropy: int = 32) -> bytes:
"""Generates byte string containing ``entropy`` bytes.
The string has ``entropy`` random bytes, each byte
converted to two hex digits.
:param entropy: Number of bytes (default: 32).
:return: Random bytes.
"""
return bytes([self.random.randint(0, 255) for _ in range(entropy)])
[docs]
def token_hex(self, entropy: int = 32) -> str:
"""Generates a random text string, in hexadecimal.
The string has *entropy* random bytes, each byte converted to two
hex digits. If *entropy* is ``None`` or not supplied, a reasonable
default is used.
:param entropy: Number of bytes (default: 32).
:return: Token.
"""
return self.token_bytes(entropy).hex()
[docs]
def token_urlsafe(self, entropy: int = 32) -> str:
"""Generates a random URL-safe text string, in Base64 encoding.
The string has *entropy* random bytes. If *entropy* is ``None``
or not supplied, a reasonable default is used.
:param entropy: Number of bytes (default: 32).
:return: URL-safe token.
"""
token = self.token_bytes(entropy)
return urlsafe_b64encode(token).rstrip(b"=").decode()
[docs]
def mnemonic_phrase(self) -> str:
"""Generates BIP-39 looking mnemonic phrase.
:return: Mnemonic phrase.
"""
length = self.random.choice([12, 24])
phrases = self.random.choices(WORDLIST, k=length)
return " ".join(phrases)
[docs]
def jwt(
self, payload: dict[str, t.Any] | None = None, algorithm: str = "HS256"
) -> str:
"""Generate JWT-like token structure for testing.
:param payload: JWT payload (claims).
:param algorithm: JWT algorithm (default: HS256).
If None, generates default payload.
:return: JWT-like token string.
Example:
>>> from mimesis import Cryptographic
>>> crypto = Cryptographic()
>>> crypto.jwt()
'eyJhbGc...'
>>> crypto.jwt(payload={'user_id': 123, 'role': 'admin'})
'eyJhbGc...'
"""
header = {
"alg": algorithm,
"typ": "JWT",
}
if payload is None:
payload = {
"sub": self.uuid(),
"name": "Test User",
"iat": int(time.time()),
"exp": int(time.time()) + 3600,
}
header_b64 = urlsafe_b64encode(json.dumps(header).encode()).decode().rstrip("=")
payload_b64 = (
urlsafe_b64encode(json.dumps(payload).encode()).decode().rstrip("=")
)
signature = urlsafe_b64encode(self.token_bytes(32)).decode().rstrip("=")
return f"{header_b64}.{payload_b64}.{signature}"
[docs]
def api_key(self, prefix: str = "", length: int = 32, fmt: str = "hex") -> str:
"""Generate API key.
:param prefix: Optional prefix (e.g., `sk_`, `pk_`, `api_`).
:param length: Length of the random part (default: 32).
:param fmt: Format of the key - 'hex' or 'base64' (default: 'hex').
:return: API key string.
:raises ValueError: If format is not 'hex' or 'base64'.
Example:
>>> from mimesis import Cryptographic
>>> crypto = Cryptographic()
>>> crypto.api_key()
'a3d2f5e8b9c1d4e7f0a2b5c8d1e4f7a0'
>>> crypto.api_key(prefix='sk_')
'sk_a3d2f5e8b9c1d4e7f0a2b5c8d1e4f7a0'
>>> crypto.api_key(prefix='pk_', format='base64')
'pk_dGVzdGluZ3Rlc3Rpbmc'
"""
if fmt == "hex":
key = self.token_hex(length // 2)
elif fmt == "base64":
key = self.token_urlsafe(length)[:length]
else:
raise ValueError(f"Unknown format: {fmt}. Use 'hex' or 'base64'.")
return f"{prefix}{key}" if prefix else key
[docs]
def certificate_fingerprint(self, algorithm: str = "sha256") -> str:
"""Generate certificate fingerprint.
:param algorithm: Hash algorithm - 'sha256' or 'sha1'.
:return: Certificate fingerprint in colon-separated hex format.
:raises ValueError: If algorithm is not supported.
Example:
>>> from mimesis import Cryptographic
>>> crypto = Cryptographic()
>>> crypto.certificate_fingerprint()
'A3:D2:F5:E8:B9:C1:D4:E7:F0:A2:B5:C8:D1:E4:F7:A0'
>>> crypto.certificate_fingerprint(algorithm='sha1')
'A3:D2:F5:E8:B9:C1:D4:E7:F0:A2:B5:C8:D1:E4:F7:A0:B1:C2:D3:E4'
"""
if algorithm == "sha256":
hex_str = self.token_hex(32)
elif algorithm == "sha1":
hex_str = self.token_hex(20)
else:
raise ValueError(f"Unknown algorithm: {algorithm}. Use 'sha256' or 'sha1'.")
return ":".join(hex_str[i : i + 2] for i in range(0, len(hex_str), 2)).upper()