Skip to content

Pickachu19/keyprism

Repository files navigation

keyprism

Typed, fixed-size multi-secret containers for Python.

PyPI version Supported Python versions MIT license PEP 561 typed package

PyPI · TestPyPI · Source · Documentation · Security


Keyprism stores several plaintexts in one fixed-size container. Each passphrase opens one plaintext. The file format gives encrypted slots and random-filled slots the same size and byte-level structure.

Applications use the typed Container API. Keyprism selects salts, nonces, padding, and physical slot positions inside the library.

Security status: Keyprism 0.1.0 has automated cryptographic, statistical, and misuse tests. No external cryptographer has audited the design or implementation. Do not use this pre-1.0 release for high-risk production data.

Features

Capability Implementation
Multiple plaintexts Each passphrase protects one complete plaintext
Fixed-size storage Each physical slot uses the configured capacity
Random-filled slots Empty slots use secrets.token_bytes()
Length hiding Encryption covers the length field, plaintext, and random padding
Password hardening Argon2id derives a separate key for each real slot
Authenticated encryption ChaCha20-Poly1305 authenticates each real slot
Restricted API Callers cannot set nonces, salts, offsets, or slot indexes
Typed package Type annotations and py.typed support PEP 561 tooling

Installation

Keyprism requires Python 3.11 or newer.

python -m pip install keyprism

Release indexes:

Index URL Purpose
PyPI pypi.org/project/keyprism Stable releases
TestPyPI test.pypi.org/project/keyprism Release verification

Documentation

Topic Reference
First container Quick start
Classes, methods, and properties API reference
Serialized bytes Container format
Algorithms and parameters Cryptographic profile
Claims and exclusions Security model
Package exceptions Error handling
Python and format support Compatibility

Quick start

from pathlib import Path

from keyprism import Container

path = Path("private-notes.kpr")

container = Container.create(num_slots=4, slot_capacity=4096)
container.write_slot("ordinary-passphrase", b"Buy milk")
container.write_slot("private-passphrase", b"Recovery instructions")
container.save(path)

loaded = Container.load(path)

assert loaded.open("ordinary-passphrase") == b"Buy milk"
assert loaded.open("private-passphrase") == b"Recovery instructions"
assert loaded.open("unknown-passphrase") is None

save() fills unwritten slots with CSPRNG output before writing the file. open() attempts each physical slot and returns matching plaintext bytes. Wrong passphrases return None.

Keyprism accepts plaintext as bytes. Your application controls text encoding, object serialization, user authentication, and secret input.

API reference

Create or load

from keyprism import Container

container = Container.create(
    num_slots=4,
    slot_capacity=4096,
)

loaded = Container.load(path)
Operation Result
Container.create(num_slots, slot_capacity) New writable in-memory container
Container.load(path) Validated read-only container

The slot capacity includes salt, nonce, authentication tag, and encrypted length framing. A slot needs at least 48 bytes.

Properties

Property Type Meaning
num_slots int Observable physical slot count
slot_capacity int Serialized bytes per physical slot
max_plaintext_size int Maximum plaintext bytes per slot
serialized_size int Exact saved container size
finalized bool Whether each slot contains serialized bytes

Methods

Method Behavior
write_slot(passphrase, plaintext) Encrypts plaintext into a random unwritten slot
open(passphrase) Returns matching plaintext bytes or None
finalize() Fills unwritten slots and prevents later writes
save(path) Finalizes and writes the container

Loaded containers reject write_slot(). The format stores no unused-slot marker, so the library cannot select a safe overwrite target after loading. Create a new container when you need to change its plaintext set.

Container format

Keyprism format version 1 starts with an eight-byte header.

Header

Offset Size Field
0 4 bytes Magic and format version: KPR\x01
4 4 bytes Big-endian slot capacity
8 Remaining bytes One or more fixed-size slots

The file length determines the physical slot count:

physical_slot_count = (file_size - 8) / slot_capacity
serialized_file_size = 8 + (physical_slot_count * slot_capacity)

Physical slot

Offset Size Real slot Empty slot
0 16 bytes Argon2id salt CSPRNG bytes
16 12 bytes ChaCha20-Poly1305 nonce CSPRNG bytes
28 slot_capacity - 44 bytes Ciphertext CSPRNG bytes
slot_capacity - 16 16 bytes Poly1305 tag CSPRNG bytes

The authenticated plaintext contains a four-byte big-endian length, the plaintext, and random padding. The maximum plaintext size is:

max_plaintext_size = slot_capacity - 48

Cryptographic profile

Format version 1 fixes these parameters:

Component Selection
KDF Argon2id version 1.3
Time cost 3 iterations
Memory cost 131,072 KiB
Parallelism 1 lane
Derived key 32 bytes
Salt 16 random bytes per real slot
AEAD ChaCha20-Poly1305
Nonce 12 random bytes per real slot
Authentication tag 16 bytes
Random source Python secrets module

AEAD associated data binds each slot to the format version and slot capacity. Changing the KDF parameters for format version 1 would make existing containers unreadable.

Security model

Keyprism targets an adversary who obtains a finalized container and may know one passphrase. The design aims for computational indistinguishability between a real encrypted slot and a random-filled slot under the security of Argon2id, ChaCha20-Poly1305, and the operating system random source.

The format reveals:

Observable value Source
File type marker Four-byte header magic
Slot capacity Header
Physical slot count File length
Total file size Filesystem
Access and transport metadata Host application and operating system

The format does not store real-slot flags, plaintext lengths outside ciphertext, timestamps, or a real-plaintext count.

Keyprism does not protect against a compromised host, live process inspection, keylogging, weak passphrases, external evidence about plaintext count, file deletion, or rollback. Python cannot provide cycle-level constant-time execution. open() performs the same KDF and authentication work for each physical slot to avoid work that depends on the matching slot position.

Use strong unique passphrases. Keep plaintext out of logs, telemetry, shell history, swap, and crash reports. Treat finalized containers as opaque binary files.

Report security defects through a private security channel. Do not publish passphrases, plaintext, derived keys, production containers, or exploit details in a public issue.

Error handling

All package exceptions inherit from KeyPrismError.

Exception Condition
ConfigurationError Invalid container dimensions
ContainerFormatError Malformed or unsupported serialized framing
ContainerStateError Operation conflicts with container state
InvalidPassphraseError Empty or invalid passphrase input
NoAvailableSlotError Writable slots are exhausted
PaddingError Authenticated payload framing is invalid
PlaintextTooLargeError Plaintext exceeds max_plaintext_size

Exception messages omit passphrases, plaintext, keys, and raw slot bytes.

from keyprism import Container, PlaintextTooLargeError

container = Container.create(slot_capacity=128)

try:
    container.write_slot("passphrase", b"x" * 100)
except PlaintextTooLargeError:
    pass

Compatibility

  • Keyprism supports Python 3.11, 3.12, and 3.13.
  • Keyprism 0.1.0 uses container format version 1.
  • The earlier Tkinter prototype and unpublished package formats are incompatible with Keyprism format version 1.
  • Pre-1.0 releases may change the API or file format. The changelog records compatibility changes.

Support

Use GitHub Issues for bug reports and API questions. Include a minimal reproducible example without passphrases, plaintext, keys, or production containers.

Report security defects through the private process in SECURITY.md. Do not publish exploit details in a public issue.

License

Keyprism uses the MIT License. The source distribution and wheel include the license text.

About

A python library for creating secure, encrypted data containers.It supports multiple passwords that reveal different plaintexts for plausible deniability.Built with modern cryptographic primitives and a simple, developer-friendly API.

Topics

Resources

License

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages