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§
- Agreement
Key - A device’s long-term key-agreement secret.
- Agreement
Public Key - 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.
- Session
Error - 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.