Source code for stegx.header

from __future__ import annotations

import struct
from dataclasses import dataclass, field
from typing import Optional

from .constants import (
    ARGON2_MAX_MEMORY_KIB,
    ARGON2_MAX_PARALLELISM,
    ARGON2_MAX_TIME_COST,
    ARGON2_MIN_MEMORY_KIB,
    ARGON2_MIN_PARALLELISM,
    ARGON2_MIN_TIME_COST,
    FORMAT_VERSION_V2,
    FORMAT_VERSION_V3,
    HEADER_SALT_LEN,
    HEADER_SIZE_V2,
    HEADER_SIZE_V3_BASE,
    KMS_WRAP_MAX,
    PBKDF2_MAX_ITERATIONS,
    PBKDF2_MIN_ITERATIONS,
    YK_CHALLENGE_NONCE_LEN,
)
from .exceptions import HeaderParameterOutOfRange
from .kdf import KDF_ARGON2ID, KDF_PBKDF2, KdfParams

MAGIC = 0x58


VERSION = FORMAT_VERSION_V2
VERSION_V2 = FORMAT_VERSION_V2
VERSION_V3 = FORMAT_VERSION_V3

FLAG_COMPRESSED = 1 << 0
FLAG_DUAL_CIPHER = 1 << 1
FLAG_KEYFILE = 1 << 2
FLAG_ADAPTIVE = 1 << 3
FLAG_MATRIX = 1 << 4
FLAG_YUBIKEY = 1 << 5


HEADER_SIZE = HEADER_SIZE_V2
SALT_LEN = 16
NONCE_LEN = 12
KDF_PARAMS_LEN = 8

_STRUCT_V2 = struct.Struct(">BBBB8s16s12s12sI")
assert _STRUCT_V2.size == HEADER_SIZE_V2


_STRUCT_V3 = struct.Struct(">BBBB8s16s12s12sI16s16sH")
assert _STRUCT_V3.size == HEADER_SIZE_V3_BASE

def _check_argon2_params(time_cost: int, memory_cost: int, parallelism: int) -> None:
    if not (ARGON2_MIN_TIME_COST <= time_cost <= ARGON2_MAX_TIME_COST):
        raise HeaderParameterOutOfRange("Header rejected: KDF parameters out of range")
    if not (ARGON2_MIN_MEMORY_KIB <= memory_cost <= ARGON2_MAX_MEMORY_KIB):
        raise HeaderParameterOutOfRange("Header rejected: KDF parameters out of range")
    if not (ARGON2_MIN_PARALLELISM <= parallelism <= ARGON2_MAX_PARALLELISM):
        raise HeaderParameterOutOfRange("Header rejected: KDF parameters out of range")