Clean & Better Encryption

This commit is contained in:
Alex Emmet 2026-06-25 19:41:51 +02:00
commit 2a00bb35e7
17 changed files with 640 additions and 367 deletions

View file

@ -31,9 +31,10 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
client_id: 0,
};
let server_bundle = host_public_key.clone();
let (conn, keyring) =
auth::connect_or_register(config, host_public_key, "client_keys.json").await?;
messages::send_and_receive(&conn, &keyring).await?;
messages::send_and_receive(&conn, &keyring, &server_bundle).await?;
println!("\nDone");
Ok(())

View file

@ -1,18 +1,14 @@
use mtp::client::MTPConnection;
use mtp::codec::{CommunicationType, CommunicationValue, DataType, DataTypeId, DataValue};
use mtp::crypto::{ChaCha20Poly1305, Ed25519Signer, Keyring, SigAlgorithm};
use mtp::crypto::{Ed25519Signer, EncryptionType, Keyring, PublicKeyBundle, SigAlgorithm};
fn derive_demo_key() -> [u8; 32] {
mtp::crypto::derive_encryption_key(
b"MTP-demo-shared-secret",
b"MTP-demo-salt",
b"encrypted-container-demo",
)
.expect("key derivation must succeed")
}
pub fn build_demo_message(client_id: u64, keyring: &Keyring) -> CommunicationValue {
let cipher = ChaCha20Poly1305::new(derive_demo_key());
pub fn build_demo_message(
client_id: u64,
keyring: &Keyring,
server_bundle: &PublicKeyBundle,
) -> CommunicationValue {
// Encrypt to the server's KEM public key; the server decrypts with its keyring.
let enc_type = EncryptionType::MlKemChaCha20Poly1305;
let signer = Ed25519Signer::new(&keyring.sig_cl_secret_key)
.expect("Ed25519 signer from keyring");
@ -21,7 +17,7 @@ pub fn build_demo_message(client_id: u64, keyring: &Keyring) -> CommunicationVal
(DataTypeId(2), DataValue::UnsignedNumber(42)),
]);
let mut dv_enc = inner_enc;
dv_enc.encrypt_container(&cipher, b"demo-aad");
dv_enc.encrypt_container(enc_type, server_bundle, b"demo-aad");
let inner_sig = DataValue::Container(vec![
(DataTypeId(1), DataValue::Str("signed by client".into())),
@ -35,7 +31,7 @@ pub fn build_demo_message(client_id: u64, keyring: &Keyring) -> CommunicationVal
(DataTypeId(2), DataValue::UnsignedNumber(7)),
]);
let mut dv_sec = inner_sec;
dv_sec.sign_and_encrypt_container(SigAlgorithm::ED25519, &signer, &cipher, b"demo-aad");
dv_sec.sign_and_encrypt_container(SigAlgorithm::ED25519, &signer, enc_type, server_bundle, b"demo-aad");
let timestamp = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
@ -66,8 +62,9 @@ pub fn build_demo_message(client_id: u64, keyring: &Keyring) -> CommunicationVal
pub async fn send_and_receive(
conn: &MTPConnection,
keyring: &Keyring,
server_bundle: &PublicKeyBundle,
) -> Result<(), Box<dyn std::error::Error>> {
let msg = build_demo_message(conn.client_id, keyring);
let msg = build_demo_message(conn.client_id, keyring, server_bundle);
println!("Sending: {msg}");
conn.sender.send(&msg).await?;

View file

@ -1,5 +1,7 @@
use mtp::codec::{CommunicationType, CommunicationValue, DataType, DataTypeId, DataValue, TypeMap};
use mtp::crypto::{ChaCha20Poly1305, CryptoError, SignatureScheme, SignaturePublicKey, verify_ed25519};
use mtp::crypto::{
CryptoError, Keyring, SignaturePublicKey, SignatureScheme, verify_ed25519,
};
struct Ed25519Verifier(SignaturePublicKey);
@ -12,19 +14,11 @@ impl SignatureScheme for Ed25519Verifier {
}
}
fn derive_demo_key() -> [u8; 32] {
mtp::crypto::derive_encryption_key(
b"MTP-demo-shared-secret",
b"MTP-demo-salt",
b"encrypted-container-demo",
)
.expect("key derivation must succeed")
}
pub fn process_and_respond(
msg: &CommunicationValue,
tm: &TypeMap,
client_pk: Option<&mtp::crypto::PublicKeyBundle>,
host_keyring: &Keyring,
) -> CommunicationValue {
let desc_id = DataTypeId(tm.data_id_enum(DataType::Description).unwrap());
let ts_id = DataTypeId(tm.data_id_enum(DataType::Timestamp).unwrap());
@ -56,8 +50,6 @@ pub fn process_and_respond(
println!(" Binary: {:?}", binary.as_bytes());
println!(" Items: {:?}", items.as_array());
let cipher = ChaCha20Poly1305::new(derive_demo_key());
let mut enc_status = String::from("EncryptedPayload: not present");
let mut sig_status = String::from("SignedPayload: not present");
let mut secure_status = String::from("SecurePayload: not present");
@ -65,7 +57,7 @@ pub fn process_and_respond(
let enc = msg.get_data(enc_id);
if matches!(enc, DataValue::EncryptedContainer(_)) {
let mut dv = enc.clone();
if dv.decrypt_into_container(&cipher, b"demo-aad").is_some() {
if dv.decrypt_into_container(host_keyring, b"demo-aad").is_some() {
if let Some(entries) = dv.as_container() {
println!(" Decrypted EncryptedPayload: {:?}", entries);
enc_status = format!("EncryptedPayload decrypted OK ({} entries)", entries.len());
@ -99,7 +91,7 @@ pub fn process_and_respond(
if let Some(pk_bundle) = client_pk {
let verifier = Ed25519Verifier(pk_bundle.sig_cl_public_key.clone());
let mut dv = secure.clone();
if dv.decrypt_signed_encrypted_container(&cipher, b"demo-aad").is_some()
if dv.decrypt_signed_encrypted_container(host_keyring, b"demo-aad").is_some()
&& dv.verify_into_container(&verifier).is_some()
{
if let Some(entries) = dv.as_container() {

View file

@ -12,6 +12,11 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
let (host_id, host_keyring) = keys::load_or_generate_host_keys("host_keys.json")?;
keys::export_host_public_keys(&host_keyring)?;
// The keyring is moved into the host config; keep a copy for decrypting the
// demo payloads clients encrypt to our KEM public key.
let decrypt_keyring = mtp::crypto::Keyring::from_bytes(&host_keyring.to_bytes())
.expect("re-load host keyring for decryption");
let (clients, next_id) = clients::load_client_db("clients.json")?;
let clients_for_get = clients.clone();
@ -62,8 +67,12 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
match conn.receiver.receive().await {
Ok(msg) => {
println!("Received: {msg}");
let response =
handlers::process_and_respond(&msg, tm, conn.client_public_key.as_ref());
let response = handlers::process_and_respond(
&msg,
tm,
conn.client_public_key.as_ref(),
&decrypt_keyring,
);
println!("Sending: {response}");
conn.sender.send(&response).await?;
}