콘텐츠로 이동

spakky-security

보안 — JWT, 암호화, 해시, 패스워드 해싱

JWT

spakky.plugins.security.jwt

JSON Web Token (JWT) utilities.

Provides utilities for creating, signing, verifying, and parsing JWT tokens with support for various HMAC algorithms and standard JWT claims.

JWT(token=None)

JSON Web Token (JWT) implementation.

Supports creating, signing, verifying, and parsing JWT tokens with standard claims (jti, iat, exp, etc.) and custom payload data.

Initialize JWT.

Parameters:

Name Type Description Default
token str | None

Existing JWT token string to parse, or None to create new.

None

Raises:

Type Description
InvalidJWTFormatError

If token format is invalid.

JWTDecodingError

If token cannot be decoded.

Source code in plugins/spakky-security/src/spakky/plugins/security/jwt.py
def __init__(self, token: str | None = None) -> None:
    """Initialize JWT.

    Args:
        token: Existing JWT token string to parse, or None to create new.

    Raises:
        InvalidJWTFormatError: If token format is invalid.
        JWTDecodingError: If token cannot be decoded.
    """
    if token is not None:
        parts: Sequence[str] = token.split(".")
        if len(parts) != 3:
            raise InvalidJWTFormatError
        header, body, signature = parts
        try:
            self.__header = json.loads(
                Base64Encoder.decode(b64=header, url_safe=True)
            )
            self.__payload = json.loads(
                Base64Encoder.decode(b64=body, url_safe=True)
            )
        except Exception as e:
            raise JWTDecodingError from e
        self.__signature = signature
        self.__is_signed = False
    else:
        current_time: datetime = datetime.now()
        self.__header = {
            "typ": "JWT",
            "alg": HMACType.HS256,
        }
        self.__payload = {
            "jti": str(uuid4()),
            "iat": self.__convert_unixtime(current_time),
        }
        self.__signature = None

hash_type property

Get the HMAC algorithm used for signing.

id property

Get the JWT ID (jti claim) as a UUID.

header property

Get a copy of the JWT header dictionary.

payload property

Get a copy of the JWT payload dictionary.

signature property

Get the JWT signature string.

issued_at property

Get the issued-at time (iat claim) as a datetime.

updated_at property

Get the updated-at time (updated_at claim) as a datetime.

last_authorized property

Get the last authorization time (auth_time claim) as a datetime.

is_expired property

Check if the JWT has expired based on the exp claim.

is_signed property

Check if the JWT has been signed.

set_header(**kwargs)

Set header fields.

Parameters:

Name Type Description Default
**kwargs Any

Header fields to set.

{}

Returns:

Type Description
Self

Self for method chaining.

Source code in plugins/spakky-security/src/spakky/plugins/security/jwt.py
def set_header(self, **kwargs: Any) -> Self:
    """Set header fields.

    Args:
        **kwargs: Header fields to set.

    Returns:
        Self for method chaining.
    """
    for key, value in kwargs.items():
        self.__header[key] = value
    # Mutating header claims invalidates the previous signature, so we
    # immediately re-sign to keep the token cryptographically consistent.
    if self.__is_signed:
        self.__sign()
    return self

set_payload(**kwargs)

Set payload fields.

Parameters:

Name Type Description Default
**kwargs Any

Payload fields to set.

{}

Returns:

Type Description
Self

Self for method chaining.

Source code in plugins/spakky-security/src/spakky/plugins/security/jwt.py
def set_payload(self, **kwargs: Any) -> Self:
    """Set payload fields.

    Args:
        **kwargs: Payload fields to set.

    Returns:
        Self for method chaining.
    """
    for key, value in kwargs.items():
        self.__payload[key] = value
    # Payload updates must refresh the signature as well, otherwise
    # consumers would observe stale token integrity data.
    if self.__is_signed:
        self.__sign()
    return self

set_hash_type(hash_type)

Set the HMAC hash algorithm.

Parameters:

Name Type Description Default
hash_type HMACType

HMAC algorithm to use for signing.

required

Returns:

Type Description
Self

Self for method chaining.

Source code in plugins/spakky-security/src/spakky/plugins/security/jwt.py
def set_hash_type(self, hash_type: HMACType) -> Self:
    """Set the HMAC hash algorithm.

    Args:
        hash_type: HMAC algorithm to use for signing.

    Returns:
        Self for method chaining.
    """
    self.__header["alg"] = hash_type
    # Changing the algorithm affects the signing key usage, so rebuild the
    # signature immediately when the token was already signed before.
    if self.__is_signed:
        self.__sign()
    return self

set_expiration(expire_after)

Set token expiration time.

Parameters:

Name Type Description Default
expire_after timedelta

Time duration until token expires.

required

Returns:

Type Description
Self

Self for method chaining.

Raises:

Type Description
JWTProcessingError

If 'iat' claim is missing.

Source code in plugins/spakky-security/src/spakky/plugins/security/jwt.py
def set_expiration(self, expire_after: timedelta) -> Self:
    """Set token expiration time.

    Args:
        expire_after: Time duration until token expires.

    Returns:
        Self for method chaining.

    Raises:
        JWTProcessingError: If 'iat' claim is missing.
    """
    iat_value: int | None = self.__payload.get("iat")
    if iat_value is None:
        raise JWTProcessingError("field named 'iat' does not exists in payload")
    iat: datetime = self.__convert_datetime(iat_value)
    exp: int = self.__convert_unixtime(iat + expire_after)
    self.__payload["exp"] = exp
    self.__payload["updated_at"] = self.__convert_unixtime(datetime.now())
    # Expiration bumps happen on long-lived tokens; re-signing keeps the
    # issued token aligned with the new expiry metadata.
    if self.__is_signed:
        self.__sign()
    return self

refresh(expire_after)

Refresh token with new expiration time.

Parameters:

Name Type Description Default
expire_after timedelta

Time duration until token expires.

required

Returns:

Type Description
Self

Self for method chaining.

Source code in plugins/spakky-security/src/spakky/plugins/security/jwt.py
def refresh(self, expire_after: timedelta) -> Self:
    """Refresh token with new expiration time.

    Args:
        expire_after: Time duration until token expires.

    Returns:
        Self for method chaining.
    """
    current_time: datetime = datetime.now()
    self.__payload["exp"] = self.__convert_unixtime(current_time + expire_after)
    self.__payload["updated_at"] = self.__convert_unixtime(current_time)
    # Refresh logic is invoked on already issued tokens, so always renew
    # the signature alongside the refreshed timestamps.
    if self.__is_signed:
        self.__sign()
    return self

sign(key)

Sign the JWT with a key.

Parameters:

Name Type Description Default
key Key

Cryptographic key to use for signing.

required

Returns:

Type Description
Self

Self for method chaining.

Source code in plugins/spakky-security/src/spakky/plugins/security/jwt.py
def sign(self, key: Key) -> Self:
    """Sign the JWT with a key.

    Args:
        key: Cryptographic key to use for signing.

    Returns:
        Self for method chaining.
    """
    self.__key = key
    self.__sign()
    return self

verify(key)

Verify JWT signature.

Parameters:

Name Type Description Default
key Key

Cryptographic key to use for verification.

required

Returns:

Type Description
bool

True if signature is valid, False otherwise.

Raises:

Type Description
JWTProcessingError

If signature or algorithm is missing.

Source code in plugins/spakky-security/src/spakky/plugins/security/jwt.py
def verify(self, key: Key) -> bool:
    """Verify JWT signature.

    Args:
        key: Cryptographic key to use for verification.

    Returns:
        True if signature is valid, False otherwise.

    Raises:
        JWTProcessingError: If signature or algorithm is missing.
    """
    self.__key = key
    header: str = Base64Encoder.encode(
        utf8=json.dumps(self.__header), url_safe=True
    )
    payload: str = Base64Encoder.encode(
        utf8=json.dumps(self.__payload), url_safe=True
    )
    content: str = f"{header}.{payload}"
    sign_algorithm: HMACType | None = self.__header.get("alg")
    if self.__signature is None:
        raise JWTProcessingError("signature cannot be None")
    if sign_algorithm is None:  # pragma: no cover
        raise JWTProcessingError("field named 'alg' does not exists in header")
    verification_result: bool = HMAC.verify(
        key=self.__key,
        hmac_type=sign_algorithm,
        content=content,
        signature=self.__signature,
        url_safe=True,
    )
    if verification_result:
        self.__payload["auth_time"] = self.__convert_unixtime(datetime.now())
        self.__is_signed = verification_result
    return verification_result

export()

Export JWT as a token string.

Returns:

Type Description
str

JWT token string in format "header.payload.signature".

Raises:

Type Description
JWTProcessingError

If token is not signed.

Source code in plugins/spakky-security/src/spakky/plugins/security/jwt.py
def export(self) -> str:
    """Export JWT as a token string.

    Returns:
        JWT token string in format "header.payload.signature".

    Raises:
        JWTProcessingError: If token is not signed.
    """
    if self.__is_signed:
        header: str = Base64Encoder.encode(
            utf8=json.dumps(self.__header), url_safe=True
        )
        payload: str = Base64Encoder.encode(
            json.dumps(self.__payload), url_safe=True
        )
        return f"{header}.{payload}.{self.__signature}"
    raise JWTProcessingError("Token must be signed")

options: show_root_heading: false

Key Management

spakky.plugins.security.key

Cryptographic key management utilities.

Provides utilities for generating, storing, and converting cryptographic keys in various formats including binary, Base64, and hexadecimal.

Key(size=None, binary=None, base64=None, url_safe=False)

Key(*, size: int)
Key(*, binary: bytes)
Key(*, base64: str, url_safe: bool = False)

Cryptographic key wrapper with format conversion utilities.

Supports creating keys from random generation, binary data, or Base64 encoding. Provides properties for converting keys to different formats.

Initialize a cryptographic key.

Parameters:

Name Type Description Default
size int | None

Generate a random key of specified byte size.

None
binary bytes | None

Create key from binary data.

None
base64 str | None

Create key from Base64-encoded string.

None
url_safe bool

Use URL-safe Base64 decoding when base64 is provided.

False

Raises:

Type Description
ValueError

If no valid initialization method is provided.

Source code in plugins/spakky-security/src/spakky/plugins/security/key.py
def __init__(
    self,
    size: int | None = None,
    binary: bytes | None = None,
    base64: str | None = None,
    url_safe: bool = False,
) -> None:
    """Initialize a cryptographic key.

    Args:
        size: Generate a random key of specified byte size.
        binary: Create key from binary data.
        base64: Create key from Base64-encoded string.
        url_safe: Use URL-safe Base64 decoding when base64 is provided.

    Raises:
        ValueError: If no valid initialization method is provided.
    """
    if size is not None:
        self.__binary = secrets.token_bytes(size)
        return
    if binary is not None:
        self.__binary = binary
        return
    if base64 is not None:
        self.__binary = Base64Encoder.get_bytes(base64, url_safe=url_safe)
        return
    raise ValueError("Invalid call of constructor Key().")

binary property

Get the key as binary data.

length property

Get the key length in bytes.

b64 property

Get the key as Base64-encoded string.

b64_urlsafe property

Get the key as URL-safe Base64-encoded string.

hex property

Get the key as uppercase hexadecimal string.

options: show_root_heading: false

Encoding

spakky.plugins.security.encoding

Base64 encoding and decoding utilities.

Provides utilities for encoding and decoding data in Base64 format with support for URL-safe encoding and direct bytes conversion.

Base64Encoder

Utility class for Base64 encoding and decoding operations.

encode(utf8, url_safe=False) staticmethod

Encode a UTF-8 string to Base64.

Parameters:

Name Type Description Default
utf8 str

The string to encode.

required
url_safe bool

Use URL-safe Base64 encoding without padding.

False

Returns:

Type Description
str

The Base64-encoded string.

Source code in plugins/spakky-security/src/spakky/plugins/security/encoding.py
@staticmethod
def encode(utf8: str, url_safe: bool = False) -> str:
    """Encode a UTF-8 string to Base64.

    Args:
        utf8: The string to encode.
        url_safe: Use URL-safe Base64 encoding without padding.

    Returns:
        The Base64-encoded string.
    """
    if url_safe:
        return (
            base64.urlsafe_b64encode(utf8.encode("UTF-8"))
            .decode("UTF-8")
            .rstrip("=")
        )
    return base64.b64encode(utf8.encode("UTF-8")).decode("UTF-8")

decode(b64, url_safe=False) staticmethod

Decode a Base64 string to UTF-8.

Parameters:

Name Type Description Default
b64 str

The Base64-encoded string to decode.

required
url_safe bool

Use URL-safe Base64 decoding with padding restoration.

False

Returns:

Type Description
str

The decoded UTF-8 string.

Source code in plugins/spakky-security/src/spakky/plugins/security/encoding.py
@staticmethod
def decode(b64: str, url_safe: bool = False) -> str:
    """Decode a Base64 string to UTF-8.

    Args:
        b64: The Base64-encoded string to decode.
        url_safe: Use URL-safe Base64 decoding with padding restoration.

    Returns:
        The decoded UTF-8 string.
    """
    if url_safe:
        return base64.urlsafe_b64decode(
            (b64 + ("=" * (4 - (len(b64) % 4)))).encode("UTF-8")
        ).decode("UTF-8")
    return base64.b64decode(b64.encode("UTF-8")).decode("UTF-8")

from_bytes(binary, url_safe=False) staticmethod

Encode binary data to Base64 string.

Parameters:

Name Type Description Default
binary bytes

The binary data to encode.

required
url_safe bool

Use URL-safe Base64 encoding without padding.

False

Returns:

Type Description
str

The Base64-encoded string.

Source code in plugins/spakky-security/src/spakky/plugins/security/encoding.py
@staticmethod
def from_bytes(binary: bytes, url_safe: bool = False) -> str:
    """Encode binary data to Base64 string.

    Args:
        binary: The binary data to encode.
        url_safe: Use URL-safe Base64 encoding without padding.

    Returns:
        The Base64-encoded string.
    """
    if url_safe:
        return base64.urlsafe_b64encode(binary).decode("UTF-8").rstrip("=")
    return base64.b64encode(binary).decode("UTF-8")

get_bytes(b64, url_safe=False) staticmethod

Decode a Base64 string to binary data.

Parameters:

Name Type Description Default
b64 str

The Base64-encoded string to decode.

required
url_safe bool

Use URL-safe Base64 decoding with padding restoration.

False

Returns:

Type Description
bytes

The decoded binary data.

Source code in plugins/spakky-security/src/spakky/plugins/security/encoding.py
@staticmethod
def get_bytes(b64: str, url_safe: bool = False) -> bytes:
    """Decode a Base64 string to binary data.

    Args:
        b64: The Base64-encoded string to decode.
        url_safe: Use URL-safe Base64 decoding with padding restoration.

    Returns:
        The decoded binary data.
    """
    if url_safe:
        return base64.urlsafe_b64decode(
            (b64 + ("=" * (4 - (len(b64) % 4)))).encode("UTF-8")
        )
    return base64.b64decode(b64.encode("UTF-8"))

options: show_root_heading: false

Hash

spakky.plugins.security.hash

Cryptographic hash utilities.

Provides utilities for computing cryptographic hashes using various algorithms including MD5, SHA1, SHA224, SHA256, SHA384, and SHA512.

HashType

Bases: str, Enum

Supported cryptographic hash algorithms.

Hash(data, hash_type=HashType.SHA256)

Cryptographic hash computation utility.

Computes cryptographic hashes of strings or file streams using various hash algorithms. Supports multiple output formats including hex, Base64, and binary.

Initialize a hash computation.

Parameters:

Name Type Description Default
data str | BufferedReader

The data to hash (string or file stream).

required
hash_type HashType

The hash algorithm to use.

SHA256
Source code in plugins/spakky-security/src/spakky/plugins/security/hash.py
def __init__(
    self, data: str | BufferedReader, hash_type: HashType = HashType.SHA256
) -> None:
    """Initialize a hash computation.

    Args:
        data: The data to hash (string or file stream).
        hash_type: The hash algorithm to use.
    """
    self.__hash_type = hash_type
    match self.__hash_type:
        case HashType.MD5:
            self.__hash = MD5.new()
        case HashType.SHA1:
            self.__hash = SHA1.new()  # type: ignore
        case HashType.SHA224:
            self.__hash = SHA224.new()  # type: ignore
        case HashType.SHA256:
            self.__hash = SHA256.new()  # type: ignore
        case HashType.SHA384:
            self.__hash = SHA384.new()  # type: ignore
        case HashType.SHA512:  # pragma: no cover
            self.__hash = SHA512.new()  # type: ignore
    if isinstance(data, str):
        self.__hash.update(data.encode("UTF-8"))
    if isinstance(data, BufferedReader):
        while True:
            buffer: bytes = data.read(65536)
            if not any(buffer):
                break
            self.__hash.update(buffer)

hex property

Get hash as uppercase hexadecimal string.

b64 property

Get hash as Base64-encoded string.

b64_urlsafe property

Get hash as URL-safe Base64-encoded string.

binary property

Get hash as binary data.

oid property

Get the OID (Object Identifier) of the hash algorithm.

digest()

Compute and return the hash digest as binary data.

Returns:

Type Description
bytes

The hash digest as bytes.

Source code in plugins/spakky-security/src/spakky/plugins/security/hash.py
def digest(self) -> bytes:
    """Compute and return the hash digest as binary data.

    Returns:
        The hash digest as bytes.
    """
    return self.__hash.digest()

options: show_root_heading: false

HMAC Signer

spakky.plugins.security.hmac_signer

HMAC signing and verification utilities.

Provides utilities for creating and verifying HMAC signatures using various hash algorithms (SHA-224, SHA-256, SHA-384, SHA-512).

HMACType

Bases: str, Enum

Supported HMAC hash algorithms.

HMAC

HMAC signing and verification utility.

Provides static methods for creating and verifying HMAC signatures using various hash algorithms.

sign_text(key, hmac_type, content, url_safe=False) staticmethod

Sign text content with HMAC.

Parameters:

Name Type Description Default
key Key

The cryptographic key to use for signing.

required
hmac_type HMACType

The HMAC hash algorithm to use.

required
content str

The text content to sign.

required
url_safe bool

Use URL-safe Base64 encoding for the signature.

False

Returns:

Type Description
str

The HMAC signature as a Base64-encoded string.

Source code in plugins/spakky-security/src/spakky/plugins/security/hmac_signer.py
@staticmethod
def sign_text(
    key: Key,
    hmac_type: HMACType,
    content: str,
    url_safe: bool = False,
) -> str:
    """Sign text content with HMAC.

    Args:
        key: The cryptographic key to use for signing.
        hmac_type: The HMAC hash algorithm to use.
        content: The text content to sign.
        url_safe: Use URL-safe Base64 encoding for the signature.

    Returns:
        The HMAC signature as a Base64-encoded string.
    """
    key_bytes: bytes = key.binary
    hash_function: Callable[..., Any]
    match hmac_type:
        case HMACType.HS224:
            hash_function = hashlib.sha224
        case HMACType.HS256:
            hash_function = hashlib.sha256
        case HMACType.HS384:
            hash_function = hashlib.sha384
        case HMACType.HS512:
            hash_function = hashlib.sha512  # pragma: no cover
    return Base64Encoder.from_bytes(
        hmac.new(
            key_bytes,
            content.encode("UTF-8"),
            hash_function,  # type: ignore
        ).digest(),
        url_safe,
    )

verify(key, hmac_type, content, signature, url_safe=False) staticmethod

Verify HMAC signature of text content.

Parameters:

Name Type Description Default
key Key

The cryptographic key used for verification.

required
hmac_type HMACType

The HMAC hash algorithm to use.

required
content str

The text content to verify.

required
signature str

The expected HMAC signature as a Base64 string.

required
url_safe bool

Whether the signature uses URL-safe Base64 encoding.

False

Returns:

Type Description
bool

True if the signature is valid, False otherwise.

Source code in plugins/spakky-security/src/spakky/plugins/security/hmac_signer.py
@staticmethod
def verify(
    key: Key,
    hmac_type: HMACType,
    content: str,
    signature: str,
    url_safe: bool = False,
) -> bool:
    """Verify HMAC signature of text content.

    Args:
        key: The cryptographic key used for verification.
        hmac_type: The HMAC hash algorithm to use.
        content: The text content to verify.
        signature: The expected HMAC signature as a Base64 string.
        url_safe: Whether the signature uses URL-safe Base64 encoding.

    Returns:
        True if the signature is valid, False otherwise.
    """
    key_bytes: bytes = key.binary
    hash_function: Callable[..., Any]
    match hmac_type:
        case HMACType.HS224:
            hash_function = hashlib.sha224
        case HMACType.HS256:
            hash_function = hashlib.sha256
        case HMACType.HS384:
            hash_function = hashlib.sha384
        case HMACType.HS512:
            hash_function = hashlib.sha512  # pragma: no cover
    return (
        Base64Encoder.from_bytes(
            hmac.new(
                key_bytes,
                content.encode("UTF-8"),
                hash_function,  # type: ignore
            ).digest(),
            url_safe,
        )
        == signature
    )

options: show_root_heading: false

Cryptography

spakky.plugins.security.cryptography.interface

Cryptography protocol interfaces.

Defines protocol interfaces for encryption/decryption and signing/verification operations used by cryptographic implementations.

ICryptor

Bases: ABC

Protocol for encryption and decryption operations.

ISigner

Bases: ABC

Protocol for digital signature operations.

options: show_root_heading: false

spakky.plugins.security.cryptography.aes

AES encryption and decryption utilities.

Provides AES-CBC mode encryption/decryption with automatic padding and IV generation using 256-bit keys.

Aes(key, url_safe=False)

Bases: ICryptor

AES-CBC encryption/decryption implementation.

Uses 256-bit keys (32 bytes) with automatic PKCS7 padding and random IV generation for each encryption operation.

Initialize AES encryptor.

Parameters:

Name Type Description Default
key Key

256-bit (32-byte) encryption key.

required
url_safe bool

Use URL-safe Base64 encoding for cipher text.

False

Raises:

Type Description
KeySizeError

If key is not 32 bytes.

Source code in plugins/spakky-security/src/spakky/plugins/security/cryptography/aes.py
def __init__(self, key: Key, url_safe: bool = False) -> None:
    """Initialize AES encryptor.

    Args:
        key: 256-bit (32-byte) encryption key.
        url_safe: Use URL-safe Base64 encoding for cipher text.

    Raises:
        KeySizeError: If key is not 32 bytes.
    """
    if key.length != self.KEY_SIZE:
        raise KeySizeError
    self.url_safe = url_safe
    self.__key = key

encrypt(message)

Encrypt a message using AES-CBC.

Parameters:

Name Type Description Default
message str

Plain text message to encrypt.

required

Returns:

Type Description
str

Encrypted cipher text in format "iv:cipher" (Base64 encoded).

Source code in plugins/spakky-security/src/spakky/plugins/security/cryptography/aes.py
def encrypt(self, message: str) -> str:
    """Encrypt a message using AES-CBC.

    Args:
        message: Plain text message to encrypt.

    Returns:
        Encrypted cipher text in format "iv:cipher" (Base64 encoded).
    """
    plain_bytes: bytes = pad(message.encode(), AES.block_size)
    iv: Key = Key(size=16)
    cryptor = AES.new(  # type: ignore
        key=self.__key.binary,
        mode=AES.MODE_CBC,
        iv=iv.binary,
    )
    cipher_bytes: bytes = cryptor.encrypt(plain_bytes)
    return "{iv}:{cipher}".format(
        iv=iv.b64_urlsafe if self.url_safe else iv.b64,
        cipher=Base64Encoder.from_bytes(cipher_bytes, self.url_safe),
    )

decrypt(cipher)

Decrypt a cipher text using AES-CBC.

Parameters:

Name Type Description Default
cipher str

Cipher text in format "iv:cipher" (Base64 encoded).

required

Returns:

Type Description
str

Decrypted plain text message.

Raises:

Type Description
DecryptionFailedError

If decryption fails.

Source code in plugins/spakky-security/src/spakky/plugins/security/cryptography/aes.py
def decrypt(self, cipher: str) -> str:
    """Decrypt a cipher text using AES-CBC.

    Args:
        cipher: Cipher text in format "iv:cipher" (Base64 encoded).

    Returns:
        Decrypted plain text message.

    Raises:
        DecryptionFailedError: If decryption fails.
    """
    try:
        [iv, cipher] = cipher.split(":")
        iv_bytes: bytes = Base64Encoder.get_bytes(iv, self.url_safe)
        cipher_bytes: bytes = Base64Encoder.get_bytes(cipher, self.url_safe)
        cryptor = AES.new(  # type: ignore
            key=self.__key.binary,
            mode=AES.MODE_CBC,
            iv=iv_bytes,
        )
        plain_bytes: bytes = cryptor.decrypt(cipher_bytes)
        return unpad(plain_bytes, AES.block_size).decode()
    except Exception as e:
        raise DecryptionFailedError from e

options: show_root_heading: false

spakky.plugins.security.cryptography.gcm

AES-GCM encryption and decryption utilities.

Provides AES-GCM mode authenticated encryption/decryption with automatic padding, IV, and AAD generation using 256-bit keys.

Gcm(key, url_safe=False)

Bases: ICryptor

AES-GCM authenticated encryption/decryption implementation.

Uses 256-bit keys (32 bytes) with automatic PKCS7 padding, random IV, and AAD generation for authenticated encryption operations.

Initialize AES-GCM encryptor.

Parameters:

Name Type Description Default
key Key

256-bit (32-byte) encryption key.

required
url_safe bool

Use URL-safe Base64 encoding for cipher text.

False

Raises:

Type Description
KeySizeError

If key is not 32 bytes.

Source code in plugins/spakky-security/src/spakky/plugins/security/cryptography/gcm.py
def __init__(self, key: Key, url_safe: bool = False) -> None:
    """Initialize AES-GCM encryptor.

    Args:
        key: 256-bit (32-byte) encryption key.
        url_safe: Use URL-safe Base64 encoding for cipher text.

    Raises:
        KeySizeError: If key is not 32 bytes.
    """
    if key.length != self.KEY_SIZE:
        raise KeySizeError
    self.url_safe = url_safe
    self.__key = key

encrypt(message)

Encrypt a message using AES-GCM.

Parameters:

Name Type Description Default
message str

Plain text message to encrypt.

required

Returns:

Type Description
str

Encrypted cipher text in format "aad:tag:iv:cipher" (Base64 encoded).

Source code in plugins/spakky-security/src/spakky/plugins/security/cryptography/gcm.py
def encrypt(self, message: str) -> str:
    """Encrypt a message using AES-GCM.

    Args:
        message: Plain text message to encrypt.

    Returns:
        Encrypted cipher text in format "aad:tag:iv:cipher" (Base64 encoded).
    """
    plain_bytes: bytes = pad(message.encode(), AES.block_size)
    aad: Key = Key(size=16)
    iv: Key = Key(size=12)
    cryptor = AES.new(  # type: ignore
        key=self.__key.binary,
        mode=AES.MODE_GCM,
        nonce=iv.binary,
    )
    cryptor.update(aad.binary)
    cipher_bytes, tag_bytes = cryptor.encrypt_and_digest(plain_bytes)
    return "{aad}:{tag}:{iv}:{cipher}".format(
        aad=aad.b64_urlsafe if self.url_safe else aad.b64,
        tag=Base64Encoder.from_bytes(tag_bytes, self.url_safe),
        iv=iv.b64_urlsafe if self.url_safe else iv.b64,
        cipher=Base64Encoder.from_bytes(cipher_bytes, self.url_safe),
    )

decrypt(cipher)

Decrypt a cipher text using AES-GCM.

Parameters:

Name Type Description Default
cipher str

Cipher text in format "aad:tag:iv:cipher" (Base64 encoded).

required

Returns:

Type Description
str

Decrypted plain text message.

Raises:

Type Description
DecryptionFailedError

If decryption or authentication fails.

Source code in plugins/spakky-security/src/spakky/plugins/security/cryptography/gcm.py
def decrypt(self, cipher: str) -> str:
    """Decrypt a cipher text using AES-GCM.

    Args:
        cipher: Cipher text in format "aad:tag:iv:cipher" (Base64 encoded).

    Returns:
        Decrypted plain text message.

    Raises:
        DecryptionFailedError: If decryption or authentication fails.
    """
    try:
        [aad, tag, iv, cipher] = cipher.split(":")
        aad_bytes: bytes = Base64Encoder.get_bytes(aad, self.url_safe)
        tag_bytes: bytes = Base64Encoder.get_bytes(tag, self.url_safe)
        iv_bytes: bytes = Base64Encoder.get_bytes(iv, self.url_safe)
        cipher_bytes: bytes = Base64Encoder.get_bytes(cipher, self.url_safe)
        cryptor = AES.new(  # type: ignore
            key=self.__key.binary,
            mode=AES.MODE_GCM,
            nonce=iv_bytes,
        )
        cryptor.update(aad_bytes)
        plain_bytes: bytes = cryptor.decrypt_and_verify(cipher_bytes, tag_bytes)
        return unpad(plain_bytes, AES.block_size).decode()
    except Exception as e:
        raise DecryptionFailedError from e

options: show_root_heading: false

spakky.plugins.security.cryptography.rsa

RSA encryption, decryption, and signing utilities.

Provides RSA asymmetric cryptography operations including key generation, encryption/decryption with PKCS1_OAEP, and signing/verification with PKCS1_v1_5.

AsymmetricKey(key=None, size=None, passphrase=None)

AsymmetricKey(*, key: str, passphrase: str | None = None)
AsymmetricKey(*, key: bytes, passphrase: str | None = None)
AsymmetricKey(*, size: int, passphrase: str | None = None)

RSA asymmetric key pair.

Manages RSA public/private key pairs with support for key generation, import/export, and passphrase protection. Supports 1024, 2048, 4096, and 8192-bit keys.

Source code in plugins/spakky-security/src/spakky/plugins/security/cryptography/rsa.py
def __init__(
    self,
    key: str | bytes | None = None,
    size: int | None = None,
    passphrase: str | None = None,
) -> None:
    if key is None and size is None:  # pragma: no cover
        raise ValueError("'key' or 'size' must be specified")
    if key is not None:
        try:
            imported_key = RSA.import_key(key, passphrase)
            if (key_size := imported_key.size_in_bits()) not in self.KEY_SIZES:
                raise KeySizeError(key_size * 8)
            self.__key = imported_key
        except (ValueError, IndexError, TypeError) as e:
            raise CannotImportAsymmetricKeyError from e
    if size is not None:
        if size not in self.KEY_SIZES:
            raise KeySizeError(size)
        self.__key = RSA.generate(size)
    if self.__key.has_private():
        self.__private_key = Key(
            binary=self.__key.export_key(passphrase=passphrase)
        )
    self.__public_key = Key(binary=self.__key.public_key().export_key())

is_private property

Check if this key pair includes a private key.

private_key property

Get the private key, or None if this is a public key only.

public_key property

Get the public key.

Rsa(key, url_safe=False)

Bases: ICryptor, ISigner

RSA encryption/decryption and signing/verification.

Provides PKCS1_OAEP encryption/decryption and PKCS1_v1_5 signing/verification using RSA asymmetric keys. Encryption uses the public key, decryption and signing require the private key.

Initialize RSA cryptor/signer.

Parameters:

Name Type Description Default
key AsymmetricKey

RSA asymmetric key pair.

required
url_safe bool

Use URL-safe Base64 encoding for cipher/signature.

False
Source code in plugins/spakky-security/src/spakky/plugins/security/cryptography/rsa.py
def __init__(self, key: AsymmetricKey, url_safe: bool = False) -> None:
    """Initialize RSA cryptor/signer.

    Args:
        key: RSA asymmetric key pair.
        url_safe: Use URL-safe Base64 encoding for cipher/signature.
    """
    self.url_safe = url_safe
    self.__key = key

encrypt(message)

Encrypt a message using RSA public key.

Parameters:

Name Type Description Default
message str

Plain text message to encrypt.

required

Returns:

Type Description
str

Encrypted cipher text (Base64 encoded).

Source code in plugins/spakky-security/src/spakky/plugins/security/cryptography/rsa.py
def encrypt(self, message: str) -> str:
    """Encrypt a message using RSA public key.

    Args:
        message: Plain text message to encrypt.

    Returns:
        Encrypted cipher text (Base64 encoded).
    """
    cryptor = PKCS1_OAEP.new(RSA.import_key(self.__key.public_key.binary))
    cipher_bytes: bytes = cryptor.encrypt(message.encode())
    return Base64Encoder.from_bytes(cipher_bytes, self.url_safe)

decrypt(cipher)

Decrypt a cipher text using RSA private key.

Parameters:

Name Type Description Default
cipher str

Cipher text to decrypt (Base64 encoded).

required

Returns:

Type Description
str

Decrypted plain text message.

Raises:

Type Description
PrivateKeyRequiredError

If key pair has no private key.

DecryptionFailedError

If decryption fails.

Source code in plugins/spakky-security/src/spakky/plugins/security/cryptography/rsa.py
def decrypt(self, cipher: str) -> str:
    """Decrypt a cipher text using RSA private key.

    Args:
        cipher: Cipher text to decrypt (Base64 encoded).

    Returns:
        Decrypted plain text message.

    Raises:
        PrivateKeyRequiredError: If key pair has no private key.
        DecryptionFailedError: If decryption fails.
    """
    if self.__key.private_key is None:
        raise PrivateKeyRequiredError
    try:
        cipher_bytes: bytes = Base64Encoder.get_bytes(cipher, self.url_safe)
        cryptor = PKCS1_OAEP.new(RSA.import_key(self.__key.private_key.binary))
        return cryptor.decrypt(cipher_bytes).decode()
    except Exception as e:
        raise DecryptionFailedError from e

sign(message, hash_type=HashType.SHA256)

Sign a message using RSA private key.

Parameters:

Name Type Description Default
message str

Message to sign.

required
hash_type HashType

Hash algorithm to use for signing.

SHA256

Returns:

Type Description
str

Digital signature (Base64 encoded).

Raises:

Type Description
PrivateKeyRequiredError

If key pair has no private key.

Source code in plugins/spakky-security/src/spakky/plugins/security/cryptography/rsa.py
def sign(self, message: str, hash_type: HashType = HashType.SHA256) -> str:
    """Sign a message using RSA private key.

    Args:
        message: Message to sign.
        hash_type: Hash algorithm to use for signing.

    Returns:
        Digital signature (Base64 encoded).

    Raises:
        PrivateKeyRequiredError: If key pair has no private key.
    """
    if self.__key.private_key is None:
        raise PrivateKeyRequiredError
    signer = PKCS1_v1_5.new(RSA.import_key(self.__key.private_key.binary))
    signature_bytes: bytes = signer.sign(Hash(message, hash_type))
    return Base64Encoder.from_bytes(signature_bytes, self.url_safe)

verify(message, signature, hash_type=HashType.SHA256)

Verify a signature using RSA public key.

Parameters:

Name Type Description Default
message str

Original message that was signed.

required
signature str

Digital signature to verify (Base64 encoded).

required
hash_type HashType

Hash algorithm used for signing.

SHA256

Returns:

Type Description
bool

True if signature is valid, False otherwise.

Source code in plugins/spakky-security/src/spakky/plugins/security/cryptography/rsa.py
def verify(
    self, message: str, signature: str, hash_type: HashType = HashType.SHA256
) -> bool:
    """Verify a signature using RSA public key.

    Args:
        message: Original message that was signed.
        signature: Digital signature to verify (Base64 encoded).
        hash_type: Hash algorithm used for signing.

    Returns:
        True if signature is valid, False otherwise.
    """
    signature_bytes: bytes = Base64Encoder.get_bytes(signature, self.url_safe)
    signer = PKCS1_v1_5.new(RSA.import_key(self.__key.public_key.binary))
    return signer.verify(Hash(message, hash_type), signature_bytes)

options: show_root_heading: false

Password Hashing

spakky.plugins.security.password.interface

Password encoding protocol interface.

Defines the protocol interface for password hashing implementations used by various password encoding algorithms.

IPasswordEncoder

Bases: IEquatable, IRepresentable, ABC

Protocol for password hashing and verification operations.

options: show_root_heading: false

spakky.plugins.security.password.argon2

Argon2 password hashing implementation.

Provides password hashing using the Argon2 algorithm with configurable parameters for time cost, memory cost, parallelism, and hash length.

Argon2PasswordEncoder(*, password_hash=None, password=None, salt=None, time_cost=3, memory_cost=65536, parallelism=4, hash_len=32, url_safe=False)

Argon2PasswordEncoder(
    *, password_hash: str, url_safe: bool = False
)
Argon2PasswordEncoder(
    *,
    password: str,
    salt: Key | None = None,
    time_cost: int = 3,
    memory_cost: int = 65536,
    parallelism: int = 4,
    hash_len: int = 32,
    url_safe: bool = False,
)

Bases: IPasswordEncoder

Argon2 password encoder.

Uses the Argon2 key derivation function for secure password hashing with configurable computational complexity parameters.

Source code in plugins/spakky-security/src/spakky/plugins/security/password/argon2.py
def __init__(
    self,
    *,
    password_hash: str | None = None,
    password: str | None = None,
    salt: Key | None = None,
    time_cost: int = 3,
    memory_cost: int = 65536,
    parallelism: int = 4,
    hash_len: int = 32,
    url_safe: bool = False,
) -> None:
    self.__url_safe = url_safe
    if password_hash is not None:
        parts: list[str] = password_hash.split(":")
        parts.pop(0)
        self.__salt = Key(
            binary=Base64Encoder.get_bytes(parts[0], url_safe=self.__url_safe)
        )
        self.__time_cost = int(parts[1])
        self.__memory_cost = int(parts[2])
        self.__parallelism = int(parts[3])
        self.__hash_len = int(parts[4])
        self.__salt_len = self.__salt.length
        self.__hash = parts[5]
    else:
        if password is None:
            raise ValueError("parameter 'password' cannot be None")
        if salt is None:
            salt = Key(size=self.SALT_SIZE)
        self.__salt = salt
        self.__time_cost = time_cost
        self.__memory_cost = memory_cost
        self.__parallelism = parallelism
        self.__hash_len = hash_len
        self.__salt_len = salt.length
        self.__hash = Base64Encoder.from_bytes(
            binary=PasswordHasher(
                time_cost=self.__time_cost,
                memory_cost=self.__memory_cost,
                parallelism=self.__parallelism,
                hash_len=self.__hash_len,
                salt_len=self.__salt_len,
            )
            .hash(password.encode("UTF-8"), salt=self.__salt.binary)
            .encode("UTF-8"),
            url_safe=self.__url_safe,
        )

encode()

Encode password hash as a string.

Returns:

Type Description
str

Encoded password hash string with algorithm and parameters.

Source code in plugins/spakky-security/src/spakky/plugins/security/password/argon2.py
def encode(self) -> str:
    """Encode password hash as a string.

    Returns:
        Encoded password hash string with algorithm and parameters.
    """
    return "{algorithm}:{salt}:{time_cost}:{memory_cost}:{parallelism}:{hash_len}:{hash}".format(
        algorithm=self.ALGORITHM_TYPE,
        salt=self.__salt.b64_urlsafe if self.__url_safe else self.__salt.b64,
        time_cost=self.__time_cost,
        memory_cost=self.__memory_cost,
        parallelism=self.__parallelism,
        hash_len=self.__hash_len,
        hash=self.__hash,
    )

challenge(password)

Verify a password against the stored hash.

Parameters:

Name Type Description Default
password str

Password to verify.

required

Returns:

Type Description
bool

True if password matches, False otherwise.

Source code in plugins/spakky-security/src/spakky/plugins/security/password/argon2.py
def challenge(self, password: str) -> bool:
    """Verify a password against the stored hash.

    Args:
        password: Password to verify.

    Returns:
        True if password matches, False otherwise.
    """
    return PasswordHasher(
        time_cost=self.__time_cost,
        memory_cost=self.__memory_cost,
        parallelism=self.__parallelism,
        hash_len=self.__hash_len,
        salt_len=self.__salt_len,
    ).verify(
        Base64Encoder.get_bytes(self.__hash, self.__url_safe),
        password.encode("UTF-8"),
    )

options: show_root_heading: false

spakky.plugins.security.password.bcrypt

Bcrypt password hashing implementation.

Provides password hashing using the Bcrypt algorithm with automatic salt generation and configurable work factor.

BcryptPasswordEncoder(password_hash=None, password=None, url_safe=False, rounds=None)

BcryptPasswordEncoder(
    *, password_hash: str, url_safe: bool = False
)
BcryptPasswordEncoder(
    *,
    password: str,
    url_safe: bool = False,
    rounds: int | None = None,
)

Bases: IPasswordEncoder

Bcrypt password encoder.

Uses the Bcrypt adaptive hash function for secure password hashing with automatic salt generation.

Source code in plugins/spakky-security/src/spakky/plugins/security/password/bcrypt.py
def __init__(
    self,
    password_hash: str | None = None,
    password: str | None = None,
    url_safe: bool = False,
    rounds: int | None = None,
) -> None:
    self.__url_safe = url_safe
    if password_hash is not None:
        parts: list[str] = password_hash.split(":")
        parts.pop(0)
        self.__salt = Key(
            binary=Base64Encoder.get_bytes(parts[0], url_safe=self.__url_safe)
        )
        self.__hash = parts[1]
    else:
        if password is None:
            raise ValueError("parameter 'password' cannot be None")
        effective_rounds = rounds if rounds is not None else self.DEFAULT_ROUNDS
        self.__salt = Key(binary=bcrypt.gensalt(rounds=effective_rounds))
        self.__hash = Base64Encoder.from_bytes(
            bcrypt.hashpw(
                password.encode("UTF-8"),
                self.__salt.binary,
            ),
            url_safe=self.__url_safe,
        )

encode()

Encode password hash as a string.

Returns:

Type Description
str

Encoded password hash string with algorithm and salt.

Source code in plugins/spakky-security/src/spakky/plugins/security/password/bcrypt.py
def encode(self) -> str:
    """Encode password hash as a string.

    Returns:
        Encoded password hash string with algorithm and salt.
    """
    return "{algorithm}:{salt}:{hash}".format(
        algorithm=self.ALGORITHM_TYPE,
        salt=self.__salt.b64_urlsafe if self.__url_safe else self.__salt.b64,
        hash=self.__hash,
    )

challenge(password)

Verify a password against the stored hash.

Parameters:

Name Type Description Default
password str

Password to verify.

required

Returns:

Type Description
bool

True if password matches, False otherwise.

Source code in plugins/spakky-security/src/spakky/plugins/security/password/bcrypt.py
def challenge(self, password: str) -> bool:
    """Verify a password against the stored hash.

    Args:
        password: Password to verify.

    Returns:
        True if password matches, False otherwise.
    """
    return bcrypt.checkpw(
        password.encode("UTF-8"),
        Base64Encoder.get_bytes(self.__hash, url_safe=self.__url_safe),
    )

options: show_root_heading: false

spakky.plugins.security.password.pbkdf2

PBKDF2 password hashing implementation.

Provides password hashing using the PBKDF2 key derivation function with configurable hash algorithm, iteration count, and salt.

Pbkdf2PasswordEncoder(*, password_hash=None, password=None, salt=None, hash_type=HashType.SHA256, iteration=100000, url_safe=False)

Pbkdf2PasswordEncoder(
    *, password_hash: str, url_safe: bool = False
)
Pbkdf2PasswordEncoder(
    *,
    password: str,
    salt: Key | None = None,
    hash_type: HashType = HashType.SHA256,
    iteration: int = 100000,
    url_safe: bool = False,
)

Bases: IPasswordEncoder

PBKDF2 password encoder.

Uses the PBKDF2 key derivation function for secure password hashing with configurable iteration count and hash algorithm.

Source code in plugins/spakky-security/src/spakky/plugins/security/password/pbkdf2.py
def __init__(
    self,
    *,
    password_hash: str | None = None,
    password: str | None = None,
    salt: Key | None = None,
    hash_type: HashType = HashType.SHA256,
    iteration: int = 100000,
    url_safe: bool = False,
) -> None:
    self.__url_safe = url_safe
    if password_hash is not None:
        parts: list[str] = password_hash.split(":")
        parts.pop(0)
        self.__hash_type = HashType(parts[0].upper())
        self.__iteration = int(parts[1])
        self.__salt = Key(
            binary=Base64Encoder.get_bytes(parts[2], url_safe=self.__url_safe)
        )
        self.__hash = parts[3]
    else:
        if password is None:
            raise ValueError("parameter 'password' cannot be None")
        if salt is None:
            salt = Key(size=self.SALT_SIZE)
        self.__salt = salt
        self.__hash_type = hash_type
        self.__iteration = iteration
        self.__hash: str = Base64Encoder.from_bytes(
            hashlib.pbkdf2_hmac(
                self.__hash_type,
                password.encode("UTF-8"),
                self.__salt.binary,
                self.__iteration,
            ),
            url_safe=self.__url_safe,
        )

encode()

Encode password hash as a string.

Returns:

Type Description
str

Encoded password hash string with algorithm, hash type, and parameters.

Source code in plugins/spakky-security/src/spakky/plugins/security/password/pbkdf2.py
def encode(self) -> str:
    """Encode password hash as a string.

    Returns:
        Encoded password hash string with algorithm, hash type, and parameters.
    """
    return "{algorithm}:{hash_type}:{iteration}:{salt}:{hash}".format(
        algorithm=self.ALGORITHM_TYPE,
        hash_type=self.__hash_type.lower(),
        iteration=self.__iteration,
        salt=self.__salt.b64_urlsafe if self.__url_safe else self.__salt.b64,
        hash=self.__hash,
    )

challenge(password)

Verify a password against the stored hash.

Parameters:

Name Type Description Default
password str

Password to verify.

required

Returns:

Type Description
bool

True if password matches, False otherwise.

Source code in plugins/spakky-security/src/spakky/plugins/security/password/pbkdf2.py
def challenge(self, password: str) -> bool:
    """Verify a password against the stored hash.

    Args:
        password: Password to verify.

    Returns:
        True if password matches, False otherwise.
    """
    new_password: Pbkdf2PasswordEncoder = Pbkdf2PasswordEncoder(
        password=password,
        salt=self.__salt,
        hash_type=self.__hash_type,
        iteration=self.__iteration,
    )
    return self == new_password

options: show_root_heading: false

spakky.plugins.security.password.scrypt

Scrypt password hashing implementation.

Provides password hashing using the Scrypt key derivation function with configurable CPU and memory cost parameters for resistance against hardware brute-force attacks.

ScryptPasswordEncoder(*, password_hash=None, password=None, salt=None, n=2 ** 14, r=8, p=1, maxmem=0, dklen=32, url_safe=False)

ScryptPasswordEncoder(
    *, password_hash: str, url_safe: bool = False
)
ScryptPasswordEncoder(
    *,
    password: str,
    salt: Key | None = None,
    n: int = 2**14,
    r: int = 8,
    p: int = 1,
    maxmem: int = 0,
    dklen: int = 32,
    url_safe: bool = False,
)

Bases: IPasswordEncoder

Scrypt password encoder.

Uses the Scrypt key derivation function for secure password hashing with configurable CPU/memory cost parameters for enhanced security.

Source code in plugins/spakky-security/src/spakky/plugins/security/password/scrypt.py
def __init__(
    self,
    *,
    password_hash: str | None = None,
    password: str | None = None,
    salt: Key | None = None,
    n: int = 2**14,
    r: int = 8,
    p: int = 1,
    maxmem: int = 0,
    dklen: int = 32,
    url_safe: bool = False,
) -> None:
    self.__url_safe = url_safe
    if password_hash is not None:
        parts: list[str] = password_hash.split(":")
        parts.pop(0)
        self.__salt = Key(
            binary=Base64Encoder.get_bytes(parts[0], url_safe=self.__url_safe)
        )
        self.__n = int(parts[1])
        self.__r = int(parts[2])
        self.__p = int(parts[3])
        self.__maxmem = int(parts[4])
        self.__dklen = int(parts[5])
        self.__hash = parts[6]
    else:
        if password is None:
            raise ValueError("parameter 'password' cannot be None")
        if salt is None:
            salt = Key(size=self.SALT_SIZE)
        self.__salt = salt
        self.__n = n
        self.__r = r
        self.__p = p
        self.__maxmem = maxmem
        self.__dklen = dklen

        self.__hash = Base64Encoder.from_bytes(
            scrypt(
                password.encode("UTF-8"),
                salt=self.__salt.binary,
                n=self.__n,
                r=self.__r,
                p=self.__p,
                maxmem=self.__maxmem,
                dklen=self.__dklen,
            ),
            url_safe=self.__url_safe,
        )

encode()

Encode password hash as a string.

Returns:

Type Description
str

Encoded password hash string with algorithm and parameters.

Source code in plugins/spakky-security/src/spakky/plugins/security/password/scrypt.py
def encode(self) -> str:
    """Encode password hash as a string.

    Returns:
        Encoded password hash string with algorithm and parameters.
    """
    return "{algorithm}:{salt}:{n}:{r}:{p}:{maxmem}:{dklen}:{hash}".format(
        algorithm=self.ALGORITHM_TYPE,
        salt=self.__salt.b64_urlsafe if self.__url_safe else self.__salt.b64,
        n=self.__n,
        r=self.__r,
        p=self.__p,
        maxmem=self.__maxmem,
        dklen=self.__dklen,
        hash=self.__hash,
    )

challenge(password)

Verify a password against the stored hash.

Parameters:

Name Type Description Default
password str

Password to verify.

required

Returns:

Type Description
bool

True if password matches, False otherwise.

Source code in plugins/spakky-security/src/spakky/plugins/security/password/scrypt.py
def challenge(self, password: str) -> bool:
    """Verify a password against the stored hash.

    Args:
        password: Password to verify.

    Returns:
        True if password matches, False otherwise.
    """
    return self.__hash == Base64Encoder.from_bytes(
        scrypt(
            password.encode("UTF-8"),
            salt=self.__salt.binary,
            n=self.__n,
            r=self.__r,
            p=self.__p,
            maxmem=self.__maxmem,
            dklen=self.__dklen,
        ),
        url_safe=self.__url_safe,
    )

options: show_root_heading: false

Errors

spakky.plugins.security.error

Security-related error classes.

Provides specialized exception classes for cryptography, key management, and JWT processing errors.

DecryptionFailedError

Bases: AbstractSpakkyFrameworkError

Raised when decryption fails due to invalid key or corrupted data.

KeySizeError

Bases: AbstractSpakkyFrameworkError

Raised when a cryptographic key has an invalid size.

PrivateKeyRequiredError

Bases: AbstractSpakkyFrameworkError

Raised when a private key is required but not provided.

CannotImportAsymmetricKeyError

Bases: AbstractSpakkyFrameworkError

Raised when an asymmetric key cannot be imported.

InvalidJWTFormatError

Bases: AbstractSpakkyFrameworkError

Raised when a JWT token has an invalid format.

JWTDecodingError

Bases: AbstractSpakkyFrameworkError

Raised when JWT token decoding fails.

JWTProcessingError

Bases: AbstractSpakkyFrameworkError

Raised when JWT token processing encounters an error.

options: show_root_heading: false

Main

spakky.plugins.security.main

Plugin initialization for Security utilities.

This plugin provides cryptographic utilities, password hashing, JWT handling, and other security-related functions. Currently, it does not require any post-processors or Pod registrations as it provides standalone utility functions.

initialize(app)

Initialize the Security plugin.

This plugin provides utility functions and does not require any Pod registration or post-processor setup at this time.

Parameters:

Name Type Description Default
app SpakkyApplication

The Spakky application instance.

required
Source code in plugins/spakky-security/src/spakky/plugins/security/main.py
def initialize(app: SpakkyApplication) -> None:
    """Initialize the Security plugin.

    This plugin provides utility functions and does not require any
    Pod registration or post-processor setup at this time.

    Args:
        app: The Spakky application instance.
    """
    # Security plugin provides utility functions only
    # No pods or post-processors to register
    pass

options: show_root_heading: false