Skip to main content

pamoja-session

X25519 key agreement, HKDF, and ChaCha20-Poly1305 with an anti-replay window, with no TLS stack. One capability of pamoja, one memory-safe Rust core with bindings for TypeScript, Python, and C#.

read the guide documentation API reference

Install

pip install pamoja-session
from pamoja import session

This pulls in pamoja-native, the compiled engine. pip install pamoja is the whole framework in one package.

Example

The script the test suite runs, spliced here as it ran.

From bindings/python/guides/session.py:

import os

from pamoja.core import PamojaError
from pamoja.session import AgreementKey, Role, Session

# Each device is provisioned with a 32-byte seed and publishes the key it derives. A real
# seed comes from the factory or a secure element; any 32 bytes stand in here.
node = AgreementKey(bytes([7]) * 32)
gateway = AgreementKey(bytes([9]) * 32)

# Neither side sends the session key. Both derive it from the shared secret, a salt that
# travels in the clear, and both public keys, with opposite roles.
#
# The salt must be fresh for every session: reusing one derives the same key from the same
# pair of devices twice. The initiator draws it and sends it in the clear, so the responder
# uses the salt it received rather than one of its own.
salt = os.urandom(16)
uplink = Session(node, gateway.public_key, salt, Role.INITIATOR)
downlink = Session(gateway, node.public_key, salt, Role.RESPONDER)
print("agreed    both sides derived a key without sending one")

# The pump id is authenticated but not encrypted, so a router still reads it while any
# change to it fails the tag.
sealed = uplink.seal(b"flow=41.2", b"pump-3")
hidden = "still" if sealed.ciphertext == b"flow=41.2" else "no longer"
print(f"sealed    counter {sealed.counter}, and what goes on the wire is {hidden} the reading")
print(f"opened    {downlink.open(sealed, b'pump-3').decode()}")

# The anti-replay window refuses a counter it has already accepted, so a frame captured
# off the air and sent again is not delivered a second time.
try:
    downlink.open(sealed, b"pump-3")
    print("a replayed frame was accepted, which should never happen")
except PamojaError as error:
    print(f"replay    refused: {error}")

# A router that rewrites the pump id breaks the tag, so the gateway refuses the frame rather
# than file the reading under the wrong pump. A frame that fails to open leaves its counter
# unused.
later = uplink.seal(b"flow=41.3", b"pump-3")
try:
    downlink.open(later, b"pump-4")
    print("a rewritten pump id was accepted, which should never happen")
except PamojaError as error:
    print(f"altered   refused: {error}")

# Radio frames can arrive out of order. The window accepts any counter it has not seen
# among the 64 below the newest, so the frame that was held up still opens.
newest = uplink.seal(b"flow=41.5", b"pump-3")
first = downlink.open(newest, b"pump-3").decode()
second = downlink.open(later, b"pump-3").decode()
print(f"late      counter {newest.counter} opened first, then counter {later.counter}: {first}, then {second}")

# The gateway answers on the same session. Its frames carry the other direction in their
# nonce, so a reply can never be taken for, or replayed as, one from the node.
order = downlink.seal(b"valve=close", b"pump-3")
print(f"reply     {uplink.open(order, b'pump-3').decode()}, sealed by the gateway and opened by the node")

The same capability in every language

Language Package Reference
Rust pamoja-session reference, docs.rs, install
TypeScript @pamoja/session reference, install
Python pamoja-session reference, install
C# Pamoja.Session reference, install

Documentation

License

MIT

Release files for pamoja-session 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pamoja-session 0.2.0
File Size Uploaded
pamoja_session-0.2.0.tar.gz 5.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for pamoja-session 0.2.0
File Interpreter ABI Platform
pamoja_session-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 10.9 kB

Release files / pamoja_session-0.2.0.tar.gz

Download URL pamoja_session-0.2.0.tar.gz
Size 5.1 kB
Tags Source
SHA-256 checksum
How to use checksums
3e945c272370a8a1104bbca5c4b630b24d8f906b9dfc591a573053a603dfd7f0
BLAKE2b-256 checksum
How to use checksums
fb4c87095f792d38c2c40c8c29968346600e192dc243b8aa3adf8ec1255e2a25
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.15

Release files / pamoja_session-0.2.0-py3-none-any.whl

Download URL pamoja_session-0.2.0-py3-none-any.whl
Size 5.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
613828f129717fea166cb8ef0e2323294c7fcf57ad06aa898dd7e474ecbc58f6
BLAKE2b-256 checksum
How to use checksums
f9898292474b5adc789f96e9fa22130efbbb19f273633a6f4330196bd4f855fb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.15

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.18

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page