pyaota.util.qrcrypto module¶
qrcrypto.py
QR code image generation and lightweight answer encryption for pyaota.
- Encryption uses an HMAC-SHA256-based stream cipher (no external dependencies):
Keystream derived from HMAC(key, block_counter) — CTR-mode equivalent
8-byte authentication tag appended to the ciphertext
Standard base64 encoding (LaTeX-safe: no underscores)
QR payload format: <version_label>:<base64(ciphertext + 8-byte-mac)>
- pyaota.util.qrcrypto.decrypt_answers(key_hex, payload)[source]¶
Decrypt a base64 payload produced by encrypt_answers.
Returns a list of single-character answer strings. Raises
ValueErrorif the payload is malformed or the MAC check fails.- Return type:
- pyaota.util.qrcrypto.encrypt_answers(key_hex, answers)[source]¶
Encrypt a list of single-character answer strings and return a URL-safe base64 payload suitable for embedding in a QR code.
Answers must already be normalised to single characters (True/False → a/b, MCQ choices lower-cased).
- Return type:
- pyaota.util.qrcrypto.generate_key()[source]¶
Return a new random 32-byte key as a lowercase hex string.
- Return type:
- pyaota.util.qrcrypto.generate_qr_png(content, output_path, error_correction='M', display_size_cm=None, scan_dpi=300)[source]¶
Generate a QR code PNG for content and write it to output_path.
- Return type:
- error_correction selects the Reed-Solomon level:
‘L’ = ~7 %, ‘M’ = ~15 % (default), ‘Q’ = ~25 %, ‘H’ = ~30 %
After writing the image is decoded with OpenCV at full resolution. If display_size_cm is given, a second verification is performed by downsampling to the expected scan resolution (
display_size_cm×scan_dpi/ 2.54 pixels square) so that readability at print size is confirmed before the exam PDF is built.Requires the
qrcode[pil]package (Pillow is already a dependency).