Skip to main content

Cryptographic message containers with signing and encryption

Project description

pybottle

Tests Python 3.10+ License: MIT

A Python library for cryptographic message containers with signing and encryption. This is a port of the Go cryptutil library.

Features

  • Bottle: Signed, encrypted message containers with CBOR/JSON serialization
  • IDCard: Identity cards linking signing keys to encryption keys
  • Opener: For opening (decrypting/verifying) bottles
  • Keychain: Private key storage and management
  • Membership: Group membership support

Supported Key Types

  • RSA (signing and encryption)
  • ECDSA P-256 (signing, ECDH encryption)
  • Ed25519 (signing, converts to X25519 for encryption)
  • X25519 (ECDH encryption)

Installation

pip install pybottle

Or install from source:

git clone https://github.com/KarpelesLab/pybottle.git
cd pybottle
pip install -e .

Quick Start

Basic Message Signing

from cryptography.hazmat.primitives.asymmetric import ec
from pybottle import new_bottle, EMPTY_OPENER

# Generate a key
private_key = ec.generate_private_key(ec.SECP256R1())

# Create and sign a bottle
bottle = new_bottle(b"Hello, World!")
bottle.sign(private_key)

# Verify the signature
data, result = EMPTY_OPENER.open(bottle)
assert result.signed_by(private_key.public_key())

Encrypted Messages

from cryptography.hazmat.primitives.asymmetric import ec
from pybottle import new_bottle, new_opener

# Generate keys for sender and recipient
alice = ec.generate_private_key(ec.SECP256R1())
bob = ec.generate_private_key(ec.SECP256R1())

# Alice creates an encrypted, signed message for Bob
bottle = new_bottle(b"Secret message for Bob")
bottle.encrypt(bob.public_key())
bottle.bottle_up()  # Wrap so signature covers encryption
bottle.sign(alice)

# Serialize to bytes
cbor_data = bottle.to_cbor()

# Bob opens the bottle
opener = new_opener(bob)
data, result = opener.open_cbor(cbor_data)

print(data)  # b"Secret message for Bob"
print(result.signed_by(alice.public_key()))  # True
print(result.decryption_count)  # 1

Multiple Recipients

# Encrypt for multiple recipients - any of them can decrypt
bottle = new_bottle(b"Message for the group")
bottle.encrypt(bob.public_key(), charlie.public_key(), dave.public_key())

Using IDCards

IDCards allow a signing key to specify additional keys for encryption:

from pybottle import new_idcard, new_opener
from cryptography.hazmat.primitives.asymmetric import ec, x25519

# Create signing and encryption keys
sign_key = ec.generate_private_key(ec.SECP256R1())
encrypt_key = x25519.X25519PrivateKey.generate()

# Create an IDCard
idcard = new_idcard(sign_key.public_key())
idcard.add_key_purpose(encrypt_key.public_key(), "decrypt")

# Now you can encrypt to the IDCard (uses decrypt-capable keys)
bottle = new_bottle(b"Message")
bottle.encrypt(idcard)

# Open with either key
opener = new_opener(encrypt_key)
data, result = opener.open(bottle)

Wrapping Data

from pybottle import wrap, EMPTY_OPENER

# Wrap a Python object in a bottle
data = {"user": "alice", "action": "login", "timestamp": 1234567890}
bottle = wrap(data)

# The content-type is automatically set
print(bottle.header["ct"])  # "cbor"

# Parse it back
result_data, _ = EMPTY_OPENER.parse(bottle)
print(result_data)  # {"user": "alice", ...}

Interoperability with Go

This library is designed to be wire-compatible with the Go cryptutil library. Bottles created in Python can be opened in Go and vice versa.

Static test keys matching the Go tests are available:

from pybottle.testkeys import get_alice, get_bob, get_chloe, get_daniel

# alice, bob: ECDSA P-256 keys
# chloe, daniel: Ed25519 keys
alice = get_alice()
bob = get_bob()

API Reference

Bottle Functions

  • new_bottle(data: bytes) -> Bottle - Create a new bottle with raw data
  • wrap(data: Any) -> Bottle - Create a bottle with CBOR-encoded data
  • wrap_json(data: Any) -> Bottle - Create a bottle with JSON-encoded data

Bottle Methods

  • bottle.sign(private_key) - Sign the bottle
  • bottle.encrypt(*recipients) - Encrypt for recipients
  • bottle.bottle_up() - Wrap bottle in another bottle (for layering)
  • bottle.to_cbor() -> bytes - Serialize to CBOR
  • bottle.to_json() -> bytes - Serialize to JSON

Opener Functions

  • new_opener(*keys) -> Opener - Create an opener with private keys
  • EMPTY_OPENER - An opener without keys (for signature verification only)

Opener Methods

  • opener.open(bottle) -> (bytes, OpenResult) - Open a bottle
  • opener.open_cbor(data) -> (bytes, OpenResult) - Open CBOR-encoded bottle
  • opener.parse(bottle) -> (Any, OpenResult) - Open and parse contents

OpenResult

  • result.signed_by(key) -> bool - Check if signed by a key
  • result.decryption_count - Number of decryption layers
  • result.signatures - List of verified signatures

Development

# Install with dev dependencies
pip install -e ".[dev]"

# Run tests
pytest

# Run tests with coverage
pytest --cov=pybottle

License

MIT License - see LICENSE for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pybottle-0.1.3.tar.gz (29.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pybottle-0.1.3-py3-none-any.whl (25.4 kB view details)

Uploaded Python 3

File details

Details for the file pybottle-0.1.3.tar.gz.

File metadata

  • Download URL: pybottle-0.1.3.tar.gz
  • Upload date:
  • Size: 29.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.11

File hashes

Hashes for pybottle-0.1.3.tar.gz
Algorithm Hash digest
SHA256 a195354e37a107acee3ad1b3947d8003206570ba7449bc8d5e2ebf64e6623c54
MD5 7b33aab13a48ebe3ab71a4f4b269c425
BLAKE2b-256 641022bdacc6e18fb7b9f84b5bb6918ff310c5fe86802613af9885cfd0bc011d

See more details on using hashes here.

File details

Details for the file pybottle-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: pybottle-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 25.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.11

File hashes

Hashes for pybottle-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 d2b472faa43814f9415417057a67ee705748e9b0bda27f36146d385d1df59142
MD5 f39b93fb011eb014cd2e98a856737692
BLAKE2b-256 af6274cb20264dc676b18124862f5df30c18c145c193cfd40aa9f52722b2368b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page