openmls 0.9.0-rc.1

A Rust implementation of the Messaging Layer Security (MLS) protocol, as defined in RFC 9420.
Documentation
//! Unit tests for the ciphersuites.

use openmls_traits::types::HpkeCiphertext;

use crate::ciphersuite::*;

// Spot test to make sure hpke seal/open work.
#[openmls_test::openmls_test]
fn test_hpke_seal_open() {
    let provider = &Provider::default();

    let plaintext = &[1, 2, 3];
    let kp = provider
        .crypto()
        .derive_hpke_keypair(
            ciphersuite.hpke_config(),
            Secret::random(ciphersuite, provider.rand())
                .expect("Not enough randomness.")
                .as_slice(),
        )
        .expect("error deriving hpke key pair");
    let ciphertext = hpke::encrypt_with_label(
        &kp.public,
        "label",
        &[1, 2, 3],
        plaintext,
        ciphersuite,
        provider.crypto(),
    )
    .unwrap();
    let decrypted_payload = hpke::decrypt_with_label(
        &kp.private,
        "label",
        &[1, 2, 3],
        &ciphertext,
        ciphersuite,
        provider.crypto(),
    )
    .expect("Unexpected error while decrypting a valid ciphertext.");
    assert_eq!(decrypted_payload, plaintext);

    let mut broken_kem_output = ciphertext.kem_output.clone();
    broken_kem_output.pop();
    let mut broken_ciphertext = ciphertext.ciphertext.clone();
    broken_ciphertext.pop();
    let broken_ciphertext1 = HpkeCiphertext {
        kem_output: broken_kem_output,
        ciphertext: ciphertext.ciphertext.clone(),
    };
    let broken_ciphertext2 = HpkeCiphertext {
        kem_output: ciphertext.kem_output,
        ciphertext: broken_ciphertext,
    };
    assert_eq!(
        hpke::decrypt_with_label(
            &kp.private,
            "label",
            &[1, 2, 3],
            &broken_ciphertext1,
            ciphersuite,
            provider.crypto(),
        )
        .map_err(|_| CryptoError::HpkeDecryptionError)
        .expect_err("Erroneously correct ciphertext decryption of broken ciphertext."),
        CryptoError::HpkeDecryptionError
    );
    assert_eq!(
        hpke::decrypt_with_label(
            &kp.private,
            "label",
            &[1, 2, 3],
            &broken_ciphertext2,
            ciphersuite,
            provider.crypto(),
        )
        .map_err(|_| CryptoError::HpkeDecryptionError)
        .expect_err("Erroneously correct ciphertext decryption of broken ciphertext."),
        CryptoError::HpkeDecryptionError
    );
}

// Spot test for safe hpke seal/open.
#[cfg(feature = "extensions-draft")]
#[openmls_test::openmls_test]
fn test_safe_hpke_seal_open() {
    use crate::component::ComponentId;

    let provider = &Provider::default();

    const CONTEXT: &[u8] = &[1, 2, 3];
    const LABEL: &str = "label";

    let plaintext = &[1, 2, 3];
    let kp = provider
        .crypto()
        .derive_hpke_keypair(
            ciphersuite.hpke_config(),
            Secret::random(ciphersuite, provider.rand())
                .expect("Not enough randomness.")
                .as_slice(),
        )
        .expect("error deriving hpke key pair");

    const COMPONENT_ID: ComponentId = 1;

    let ciphertext = hpke::safe_encrypt_with_label(
        &kp.public,
        plaintext,
        ciphersuite,
        SafeEncryptionContext {
            component_id: COMPONENT_ID,
            label: LABEL,
            context: CONTEXT,
        },
        provider.crypto(),
    )
    .unwrap();
    let decrypted_payload = hpke::safe_decrypt_with_label(
        &kp.private,
        &ciphertext,
        ciphersuite,
        SafeEncryptionContext {
            component_id: COMPONENT_ID,
            label: LABEL,
            context: CONTEXT,
        },
        provider.crypto(),
    )
    .expect("Unexpected error while decrypting a valid ciphertext.");
    assert_eq!(decrypted_payload, plaintext);

    let mut broken_kem_output: Vec<u8> = ciphertext.kem_output.clone().into();
    broken_kem_output[0] ^= 0xff;
    let mut broken_ciphertext: Vec<u8> = ciphertext.ciphertext.clone().into();
    broken_ciphertext[1] ^= 0xff;

    let broken_ciphertext1 = HpkeCiphertext {
        kem_output: broken_kem_output.into(),
        ciphertext: ciphertext.ciphertext.clone(),
    };
    let broken_ciphertext2 = HpkeCiphertext {
        kem_output: ciphertext.kem_output,
        ciphertext: broken_ciphertext.into(),
    };
    assert_eq!(
        hpke::safe_decrypt_with_label(
            &kp.private,
            &broken_ciphertext1,
            ciphersuite,
            SafeEncryptionContext {
                component_id: COMPONENT_ID,
                label: LABEL,
                context: CONTEXT,
            },
            provider.crypto(),
        )
        .map_err(|_| CryptoError::HpkeDecryptionError)
        .expect_err("Erroneously correct ciphertext decryption of broken ciphertext."),
        CryptoError::HpkeDecryptionError
    );
    assert_eq!(
        hpke::safe_decrypt_with_label(
            &kp.private,
            &broken_ciphertext2,
            ciphersuite,
            SafeEncryptionContext {
                component_id: COMPONENT_ID,
                label: LABEL,
                context: CONTEXT,
            },
            provider.crypto(),
        )
        .map_err(|_| CryptoError::HpkeDecryptionError)
        .expect_err("Erroneously correct ciphertext decryption of broken ciphertext."),
        CryptoError::HpkeDecryptionError
    );
}