Skip to main content

Crate pamoja_session

Crate pamoja_session 

Source
Expand description

Encrypted, authenticated sessions for the pamoja SDK.

pamoja-security proves a payload came from a device and was not altered. This crate adds the other half a networked link needs: confidentiality and a fresh, ordered, replay-protected channel, so a reading is not just trustworthy but private, and a captured message cannot be replayed to reopen a valve or re-trigger an alarm.

Two devices that each hold the other’s authenticated public key agree a session key with Session::establish and then exchange messages with Session::seal and Session::open. The whole exchange is built from published standards and the tests are pinned to their reference vectors:

  • X25519 key agreement, RFC 7748, so neither side ever sends the key.
  • HKDF-SHA256, RFC 5869, to derive a per-session key bound to both public keys.
  • ChaCha20-Poly1305, RFC 8439, to encrypt and authenticate each message; chosen because the cheap hardware this SDK targets rarely has AES acceleration.

Establishing a session is deterministic given the keys and salt, and every operation works in place on caller-owned buffers, so the crate is no_std and allocation-free and runs unchanged on a microcontroller. It is the secured-channel groundwork the security pillar builds on, ahead of full transport TLS/DTLS.

§Authenticating the peer

Key agreement gives a private channel; it does not by itself say who is on the other end. The peer’s AgreementPublicKey must be authenticated out of band, by pinning it at provisioning time or by having it signed with the peer’s pamoja-security identity. Without that, the channel is confidential but open to a man in the middle.

§Examples

use pamoja_session::{AgreementKey, Role, Session};

// Each device holds its own seed and the other's authenticated public key.
let sensor = AgreementKey::from_seed(&[1u8; 32]);
let gateway = AgreementKey::from_seed(&[2u8; 32]);

// A fresh salt is exchanged in the clear to start the session.
let salt = [42u8; 16];
let mut a = Session::establish(&sensor, &gateway.public(), &salt, Role::Initiator);
let mut b = Session::establish(&gateway, &sensor.public(), &salt, Role::Responder);

// Seal a reading; the device id rides along as authenticated-but-readable data.
let mut reading = *b"tank: 18%";
let sealed = a.seal(&mut reading, b"well-3");

// The gateway opens it, recovering the reading and proving it is authentic.
b.open(&sealed, &mut reading, b"well-3").expect("authentic and fresh");
assert_eq!(&reading, b"tank: 18%");

// A replay of the same message is refused.
assert!(b.open(&sealed, &mut reading.clone(), b"well-3").is_err());

Structs§

AgreementKey
A device’s long-term key-agreement secret.
AgreementPublicKey
The public half of a device’s key-agreement key.
Sealed
The out-of-band header of a sealed message: the counter that orders it and the tag that authenticates it.
Session
A confidential, tamper-evident, replay-protected channel with one peer.

Enums§

Role
Which end of a session a device is.
SessionError
What can go wrong opening a sealed message on a session.

Functions§

hkdf_sha256
Derives output key material from input keying material with HKDF-SHA256.
hmac_sha256
Computes HMAC-SHA256 over a message with a key of any length.