Files
pyGUI/backend/crypto_helper.py
Jack.Le e43bf258e3 Add initial backend structure with models, utilities, and settings management
- Introduced .gitignore to exclude common Python artifacts and IDE files.
- Added contour models for contour generation.
- Implemented cryptographic utilities for data encryption and decryption.
- Created CSV metadata model for handling wafer data.
- Developed time-indexed data segment model.
- Established local settings model for application configuration.
- Added Z-wafer data models and parser for CSV file handling.
- Implemented Marching Squares algorithm for contour generation.
2026-04-23 11:40:47 -07:00

91 lines
3.1 KiB
Python

import secrets
from pathlib import Path
from typing import Union
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
# ===== Crypto Utilities =====
class CryptoHelper:
"""Cryptographic utilities for wafer data encryption/decryption."""
# ===== Hex/Byte Conversion =====
@staticmethod
def hex_string_to_bytearray(hex_str: str) -> bytes:
"""Converts a hex string to bytes (e.g., '48656C6C6F' → b'Hello')."""
if len(hex_str) % 2 != 0:
raise ValueError("Hex string must have even length")
try:
return bytes.fromhex(hex_str)
except ValueError as e:
raise ValueError(f"Invalid hex string: {e}")
@staticmethod
def bytearray_to_hex_string(data: Union[bytes, bytearray]) -> str:
"""Converts bytes to lowercase hex string."""
return data.hex()
# ===== Random Data =====
@staticmethod
def generate_random_bytes(length: int) -> bytes:
"""Generates cryptographically secure random bytes."""
if length < 0:
raise ValueError("Length must be non-negative")
return secrets.token_bytes(length)
# ===== AES Decryption =====
@staticmethod
def decrypt_aes(data: bytes, key: bytes, iv: bytes) -> bytes:
"""
Decrypts AES-128-CBC data with PKCS7 padding.
Args:
data: Encrypted ciphertext (must be multiple of 16 bytes)
key: 16-byte AES key
iv: 16-byte IV
Returns:
Decrypted plaintext
Raises:
ValueError: If inputs are invalid
cryptography.exceptions.InvalidSignature: On decryption failure
"""
if len(key) != 16:
raise ValueError("Key must be 16 bytes (AES-128)")
if len(iv) != 16:
raise ValueError("IV must be 16 bytes")
if len(data) == 0:
return b""
if len(data) % 16 != 0:
raise ValueError("Ciphertext length must be multiple of 16 bytes")
cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend())
decrypt_ctx = cipher.decryptor()
plaintext_padded = decrypt_ctx.update(data) + decrypt_ctx.finalize()
# Remove PKCS7 padding
pad_len = plaintext_padded[-1]
if pad_len > 16 or pad_len == 0:
raise ValueError("Invalid padding")
return plaintext_padded[:-pad_len]
# ===== Binary File I/O =====
@staticmethod
def save_to_binary_file(file_path: Union[str, Path], data: bytes) -> None:
"""Writes bytes to a binary file."""
Path(file_path).write_bytes(data)
@staticmethod
def read_from_binary_file(file_path: Union[str, Path]) -> bytes:
"""Reads bytes from a binary file."""
return Path(file_path).read_bytes()
# ===== Convenience Helpers =====
@classmethod
def read_hex_string_from_binary_file(cls, file_path: Union[str, Path]) -> str:
"""Reads binary file and returns hex string."""
data = cls.read_from_binary_file(file_path)
return cls.bytearray_to_hex_string(data)