# pamoja-session
Encrypted, authenticated sessions for pamoja: X25519 key agreement (RFC 7748) and HKDF-SHA256 (RFC 5869) derive a session key, then ChaCha20-Poly1305 (RFC 8439) protects each message with counter nonces and an anti-replay window, so two devices that know each other's keys share a confidential, tamper-evident link, no_std and allocation-free. The secured-channel half ahead of the rustls/DTLS driver.
<a href="https://pamoja.molex.cloud/docs/reference/rust/pamoja_session/index.html"><img height="28" alt="API reference" src="https://raw.githubusercontent.com/molexxxx/pamoja/main/.github/badges/btn-api.svg"></a>
<a href="https://pamoja.molex.cloud/docs/guides/session.html"><img height="28" alt="read the guide" src="https://raw.githubusercontent.com/molexxxx/pamoja/main/.github/badges/btn-guide.svg"></a>
<a href="https://crates.io/crates/pamoja-session"><img height="28" alt="crates.io" src="https://raw.githubusercontent.com/molexxxx/pamoja/main/.github/badges/btn-cratesio.svg"></a>
<a href="https://docs.rs/pamoja-session"><img height="28" alt="docs.rs" src="https://raw.githubusercontent.com/molexxxx/pamoja/main/.github/badges/btn-docsrs.svg"></a>
## The same capability in every language
| Rust | [`pamoja-session`](https://crates.io/crates/pamoja-session) | [reference](https://pamoja.molex.cloud/docs/reference/rust/pamoja_session/index.html), [docs.rs](https://docs.rs/pamoja-session), [install](https://pamoja.molex.cloud/docs/reference/rust.html#rust-session) |
| TypeScript | [`@pamoja/session`](https://www.npmjs.com/package/@pamoja/session) | [reference](https://pamoja.molex.cloud/docs/reference/node/modules/_pamoja_session.html), [install](https://pamoja.molex.cloud/docs/reference/node.html#node-session) |
| Python | [`pamoja-session`](https://pypi.org/project/pamoja-session/) | [reference](https://pamoja.molex.cloud/docs/reference/python/pamoja/session.html), [install](https://pamoja.molex.cloud/docs/reference/python.html#python-session) |
| C# | [`Pamoja.Session`](https://www.nuget.org/packages/Pamoja.Session) | [reference](https://pamoja.molex.cloud/docs/reference/dotnet/api/Pamoja.Session.html), [install](https://pamoja.molex.cloud/docs/reference/dotnet.html#dotnet-session) |
Encrypted, authenticated sessions for the pamoja SDK.
[`pamoja-security`](https://docs.rs/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**
```rust
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());
```
## License
MIT - part of the [pamoja](https://github.com/molexxxx/pamoja) workspace: one memory-safe Rust core with bindings for every language.