use crate::{
dh::{DhError, AEAD, NONCE_SIZE},
encoding::{BinaryMarshaler, BinaryUnmarshaler, Marshaling, MarshallingError},
util::random::RandStream,
Group, Point, Scalar,
};
use thiserror::Error;
pub fn encrypt<GROUP: Group>(
group: GROUP,
public: GROUP::POINT,
message: &[u8],
) -> Result<Vec<u8>, EciesError> {
let r = group.scalar().pick(&mut RandStream::default());
let r_p = group.point().mul(&r, None);
let dh = group.point().mul(&r, Some(&public));
let len = 32 + NONCE_SIZE;
let buf = derive_key::<GROUP>(&dh, len)?;
let mut nonce = [0u8; NONCE_SIZE];
nonce.copy_from_slice(&buf[32..len]);
let gcm = AEAD::<GROUP>::new(r_p.clone(), &buf)?;
let c = gcm.seal(None, &nonce, message, None)?;
let mut ctx = Vec::new();
r_p.marshal_to(&mut ctx)?;
for v in c {
ctx.push(v);
}
Ok(ctx)
}
pub fn decrypt<GROUP: Group>(
group: GROUP,
private: <GROUP::POINT as Point>::SCALAR,
ctx: &[u8],
) -> Result<Vec<u8>, EciesError> {
let mut r_p = group.point();
let l = group.point_len();
r_p.unmarshal_binary(&ctx[..l])?;
let dh = group.point().mul(&private, Some(&r_p));
let len = 32 + NONCE_SIZE;
let buf = derive_key::<GROUP>(&dh, len)?;
let mut nonce = [0u8; NONCE_SIZE];
nonce.copy_from_slice(&buf[32..len]);
let gcm = AEAD::<GROUP>::new(r_p.clone(), &buf)?;
Ok(gcm.open(None, &nonce, &ctx[l..], None)?)
}
fn derive_key<GROUP: Group>(dh: &GROUP::POINT, len: usize) -> Result<Vec<u8>, EciesError> {
let dhb = dh.marshal_binary()?;
let key = GROUP::hkdf(&dhb, &Vec::new(), Some(len))?;
if key.len() < len {
return Err(EciesError::KeyTooShort);
}
Ok(key)
}
#[derive(Debug, Error)]
pub enum EciesError {
#[error("marshalling error")]
MarshalingError(#[from] MarshallingError),
#[error("dh error")]
DhError(#[from] DhError),
#[error("hkdf-derived key too short")]
KeyTooShort,
}