use openmls_traits::{
crypto::OpenMlsCrypto,
types::{Ciphersuite, CryptoError, HpkeCiphertext},
};
use thiserror::Error;
use tls_codec::{Serialize, TlsDeserialize, TlsSerialize, TlsSize, VLBytes};
use super::LABEL_PREFIX;
#[derive(Error, Debug, PartialEq, Clone)]
pub(crate) enum Error {
#[error(
"Error while serializing content. This should only happen if a bounds check was missing."
)]
MissingBoundCheck,
#[error("Decryption failed.")]
DecryptionFailed,
}
impl From<tls_codec::Error> for Error {
fn from(_: tls_codec::Error) -> Self {
Self::MissingBoundCheck
}
}
impl From<CryptoError> for Error {
fn from(_: CryptoError) -> Self {
Self::DecryptionFailed
}
}
#[derive(Debug, Clone, TlsSerialize, TlsDeserialize, TlsSize)]
pub struct EncryptContext {
label: VLBytes,
context: VLBytes,
}
impl EncryptContext {
pub fn new(label: &str, context: VLBytes) -> Self {
let label_string = LABEL_PREFIX.to_owned() + label;
let label = label_string.as_bytes().into();
Self { label, context }
}
}
impl From<(&str, &[u8])> for EncryptContext {
fn from((label, context): (&str, &[u8])) -> Self {
Self::new(label, context.into())
}
}
pub(crate) fn encrypt_with_label(
public_key: &[u8],
label: &str,
context: &[u8],
plaintext: &[u8],
ciphersuite: Ciphersuite,
crypto: &impl OpenMlsCrypto,
) -> Result<HpkeCiphertext, Error> {
let context: EncryptContext = (label, context).into();
let context = context.tls_serialize_detached()?;
log_crypto!(
debug,
"HPKE Encrypt with label `{label}` and ciphersuite `{ciphersuite:?}`:"
);
log_crypto!(debug, "* context: {context:x?}");
log_crypto!(debug, "* public key: {public_key:x?}");
log_crypto!(debug, "* plaintext: {plaintext:x?}");
let cipher = crypto.hpke_seal(
ciphersuite.hpke_config(),
public_key,
&context,
&[],
plaintext,
);
log_crypto!(debug, "* ciphertext: {:x?}", cipher);
Ok(cipher)
}
pub(crate) fn decrypt_with_label(
private_key: &[u8],
label: &str,
context: &[u8],
ciphertext: &HpkeCiphertext,
ciphersuite: Ciphersuite,
crypto: &impl OpenMlsCrypto,
) -> Result<Vec<u8>, Error> {
let context: EncryptContext = (label, context).into();
let context = context.tls_serialize_detached()?;
log_crypto!(
debug,
"HPKE Decrypt with label `{label}` and `ciphersuite` {ciphersuite:?}:"
);
log_crypto!(debug, "* context: {context:x?}");
log_crypto!(debug, "* private key: {private_key:x?}");
log_crypto!(debug, "* ciphertext: {ciphertext:x?}");
let plaintext = crypto
.hpke_open(
ciphersuite.hpke_config(),
ciphertext,
private_key,
&context,
&[],
)
.map_err(|e| e.into());
log_crypto!(debug, "* plaintext: {plaintext:x?}");
plaintext
}