use std::{
io::{Read, Write},
sync::RwLock,
};
use evercrypt::prelude::*;
use hpke::Hpke;
use hpke_rs_crypto::types as hpke_types;
use hpke_rs_evercrypt::HpkeEvercrypt;
use log::error;
use openmls_traits::{
crypto::OpenMlsCrypto,
random::OpenMlsRand,
types::{
AeadType, Ciphersuite, CryptoError, ExporterSecret, HashType, HpkeAeadType, HpkeCiphertext,
HpkeConfig, HpkeKdfType, HpkeKemType, HpkeKeyPair, KemOutput, SignatureScheme,
},
};
use rand::{RngCore, SeedableRng};
#[derive(Debug)]
pub struct EvercryptProvider {
rng: RwLock<rand_chacha::ChaCha20Rng>,
}
impl Default for EvercryptProvider {
fn default() -> Self {
Self {
rng: RwLock::new(rand_chacha::ChaCha20Rng::from_entropy()),
}
}
}
#[inline(always)]
fn signature_mode(signature_scheme: SignatureScheme) -> Result<SignatureMode, &'static str> {
match signature_scheme {
SignatureScheme::ED25519 => Ok(SignatureMode::Ed25519),
SignatureScheme::ECDSA_SECP256R1_SHA256 => Ok(SignatureMode::P256),
SignatureScheme::ED448 => Err("SignatureScheme ed448 is not supported."),
SignatureScheme::ECDSA_SECP521R1_SHA512 => {
Err("SignatureScheme ecdsa_secp521r1 is not supported.")
}
SignatureScheme::ECDSA_SECP384R1_SHA384 => {
Err("SignatureScheme ecdsa_secp384r1 is not supported.")
}
}
}
#[inline(always)]
fn hash_from_signature(signature_scheme: SignatureScheme) -> Result<DigestMode, &'static str> {
match signature_scheme {
SignatureScheme::ED25519 => Ok(DigestMode::Sha256),
SignatureScheme::ECDSA_SECP256R1_SHA256 => Ok(DigestMode::Sha256),
SignatureScheme::ED448 => Err("SignatureScheme ed448 is not supported."),
SignatureScheme::ECDSA_SECP521R1_SHA512 => {
Err("SignatureScheme ecdsa_secp521r1 is not supported.")
}
SignatureScheme::ECDSA_SECP384R1_SHA384 => {
Err("SignatureScheme ecdsa_secp384r1 is not supported.")
}
}
}
#[inline(always)]
fn hash_from_algorithm(hash_type: HashType) -> DigestMode {
match hash_type {
HashType::Sha2_256 => DigestMode::Sha256,
HashType::Sha2_384 => DigestMode::Sha384,
HashType::Sha2_512 => DigestMode::Sha512,
}
}
#[inline(always)]
fn aead_from_algorithm(alg: AeadType) -> AeadMode {
match alg {
AeadType::Aes128Gcm => AeadMode::Aes128Gcm,
AeadType::Aes256Gcm => AeadMode::Aes256Gcm,
AeadType::ChaCha20Poly1305 => AeadMode::Chacha20Poly1305,
}
}
#[inline(always)]
fn hmac_from_hash(hash_type: HashType) -> HmacMode {
match hash_type {
HashType::Sha2_256 => HmacMode::Sha256,
HashType::Sha2_384 => HmacMode::Sha384,
HashType::Sha2_512 => HmacMode::Sha512,
}
}
impl OpenMlsCrypto for EvercryptProvider {
fn supports(&self, ciphersuite: Ciphersuite) -> Result<(), CryptoError> {
match ciphersuite {
Ciphersuite::MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519
| Ciphersuite::MLS_128_DHKEMX25519_CHACHA20POLY1305_SHA256_Ed25519
| Ciphersuite::MLS_128_DHKEMP256_AES128GCM_SHA256_P256 => Ok(()),
_ => Err(CryptoError::UnsupportedCiphersuite),
}
}
fn supported_ciphersuites(&self) -> Vec<Ciphersuite> {
vec![
Ciphersuite::MLS_128_DHKEMX25519_AES128GCM_SHA256_Ed25519,
Ciphersuite::MLS_128_DHKEMX25519_CHACHA20POLY1305_SHA256_Ed25519,
Ciphersuite::MLS_128_DHKEMP256_AES128GCM_SHA256_P256,
]
}
fn hkdf_extract(
&self,
hash_type: HashType,
salt: &[u8],
ikm: &[u8],
) -> Result<Vec<u8>, CryptoError> {
let hmac = hmac_from_hash(hash_type);
Ok(hkdf::extract(hmac, salt, ikm))
}
fn hkdf_expand(
&self,
hash_type: HashType,
prk: &[u8],
info: &[u8],
okm_len: usize,
) -> Result<Vec<u8>, CryptoError> {
let hmac = hmac_from_hash(hash_type);
Ok(hkdf::expand(hmac, prk, info, okm_len))
}
fn hash(&self, hash_type: HashType, data: &[u8]) -> Result<Vec<u8>, CryptoError> {
let alg = hash_from_algorithm(hash_type);
Ok(evercrypt::digest::hash(alg, data))
}
fn aead_encrypt(
&self,
alg: AeadType,
key: &[u8],
data: &[u8],
nonce: &[u8],
aad: &[u8],
) -> Result<Vec<u8>, CryptoError> {
let alg = aead_from_algorithm(alg);
aead::encrypt_combined(alg, key, data, nonce, aad)
.map_err(|_| CryptoError::CryptoLibraryError)
}
fn aead_decrypt(
&self,
alg: AeadType,
key: &[u8],
ct_tag: &[u8],
nonce: &[u8],
aad: &[u8],
) -> Result<Vec<u8>, CryptoError> {
let alg = aead_from_algorithm(alg);
aead_decrypt_combined(alg, key, ct_tag, nonce, aad)
.map_err(|_| CryptoError::CryptoLibraryError)
}
fn signature_key_gen(&self, alg: SignatureScheme) -> Result<(Vec<u8>, Vec<u8>), CryptoError> {
let signature_mode = match signature_mode(alg) {
Ok(signature_mode) => signature_mode,
Err(_) => return Err(CryptoError::UnsupportedSignatureScheme),
};
match signature::key_gen(signature_mode) {
Ok((sk, pk)) => Ok((sk, pk)),
Err(e) => {
error!("Key generation really shouldn't fail. {:?}", e);
Err(CryptoError::CryptoLibraryError)
}
}
}
fn verify_signature(
&self,
alg: SignatureScheme,
data: &[u8],
pk: &[u8],
signature: &[u8],
) -> Result<(), CryptoError> {
let signature_mode = match signature_mode(alg) {
Ok(signature_mode) => signature_mode,
Err(_) => return Err(CryptoError::UnsupportedSignatureScheme),
};
let digest_mode = match hash_from_signature(alg) {
Ok(dm) => dm,
Err(_) => return Err(CryptoError::UnsupportedSignatureScheme),
};
let valid = if signature_mode == SignatureMode::P256 {
verify(
signature_mode,
digest_mode,
pk,
&der_decode(signature)?,
data,
)
} else {
verify(signature_mode, digest_mode, pk, signature, data)
}
.map_err(|_| CryptoError::InvalidSignature)?;
if valid {
Ok(())
} else {
Err(CryptoError::InvalidSignature)
}
}
fn sign(&self, alg: SignatureScheme, data: &[u8], key: &[u8]) -> Result<Vec<u8>, CryptoError> {
let signature_mode = match signature_mode(alg) {
Ok(signature_mode) => signature_mode,
Err(_) => return Err(CryptoError::UnsupportedSignatureScheme),
};
let (hash, nonce) = match signature_mode {
SignatureMode::Ed25519 => (None, None),
SignatureMode::P256 => {
let digest =
hash_from_signature(alg).map_err(|_| CryptoError::UnsupportedHashAlgorithm)?;
let nonce =
p256_ecdsa_random_nonce().map_err(|_| CryptoError::CryptoLibraryError)?;
(Some(digest), Some(nonce))
}
};
let signature = evercrypt::signature::sign(signature_mode, hash, key, data, nonce.as_ref())
.map_err(|_| CryptoError::CryptoLibraryError)?;
if signature_mode == SignatureMode::P256 {
der_encode(&signature)
} else {
Ok(signature)
}
}
fn hpke_seal(
&self,
config: HpkeConfig,
pk_r: &[u8],
info: &[u8],
aad: &[u8],
ptxt: &[u8],
) -> openmls_traits::types::HpkeCiphertext {
let (kem_output, ciphertext) = hpke_from_config(config)
.seal(&pk_r.into(), info, aad, ptxt, None, None, None)
.unwrap();
HpkeCiphertext {
kem_output: kem_output.into(),
ciphertext: ciphertext.into(),
}
}
fn hpke_open(
&self,
config: HpkeConfig,
input: &openmls_traits::types::HpkeCiphertext,
sk_r: &[u8],
info: &[u8],
aad: &[u8],
) -> Result<Vec<u8>, CryptoError> {
hpke_from_config(config)
.open(
input.kem_output.as_slice(),
&sk_r.into(),
info,
aad,
input.ciphertext.as_slice(),
None,
None,
None,
)
.map_err(|_| CryptoError::HpkeDecryptionError)
}
fn hpke_setup_sender_and_export(
&self,
config: HpkeConfig,
pk_r: &[u8],
info: &[u8],
exporter_context: &[u8],
exporter_length: usize,
) -> Result<(KemOutput, ExporterSecret), CryptoError> {
let (kem_output, context) = hpke_from_config(config)
.setup_sender(&pk_r.into(), info, None, None, None)
.map_err(|_| CryptoError::SenderSetupError)?;
let exported_secret = context
.export(exporter_context, exporter_length)
.map_err(|_| CryptoError::ExporterError)?;
Ok((kem_output, exported_secret))
}
fn hpke_setup_receiver_and_export(
&self,
config: HpkeConfig,
enc: &[u8],
sk_r: &[u8],
info: &[u8],
exporter_context: &[u8],
exporter_length: usize,
) -> Result<ExporterSecret, CryptoError> {
let context = hpke_from_config(config)
.setup_receiver(enc, &sk_r.into(), info, None, None, None)
.map_err(|_| CryptoError::ReceiverSetupError)?;
let exported_secret = context
.export(exporter_context, exporter_length)
.map_err(|_| CryptoError::ExporterError)?;
Ok(exported_secret)
}
fn derive_hpke_keypair(
&self,
config: HpkeConfig,
ikm: &[u8],
) -> openmls_traits::types::HpkeKeyPair {
let kp = hpke_from_config(config)
.derive_key_pair(ikm)
.unwrap()
.into_keys();
HpkeKeyPair {
private: kp.0.as_slice().into(),
public: kp.1.as_slice().into(),
}
}
}
fn hpke_from_config(config: HpkeConfig) -> Hpke<HpkeEvercrypt> {
Hpke::<HpkeEvercrypt>::new(
hpke::Mode::Base,
kem_mode(config.0),
kdf_mode(config.1),
aead_mode(config.2),
)
}
#[inline(always)]
fn kem_mode(kem: HpkeKemType) -> hpke_types::KemAlgorithm {
match kem {
HpkeKemType::DhKemP256 => hpke_types::KemAlgorithm::DhKemP256,
HpkeKemType::DhKemP384 => hpke_types::KemAlgorithm::DhKemP384,
HpkeKemType::DhKemP521 => hpke_types::KemAlgorithm::DhKemP521,
HpkeKemType::DhKem25519 => hpke_types::KemAlgorithm::DhKem25519,
HpkeKemType::DhKem448 => hpke_types::KemAlgorithm::DhKem448,
}
}
#[inline(always)]
fn kdf_mode(kdf: HpkeKdfType) -> hpke_types::KdfAlgorithm {
match kdf {
HpkeKdfType::HkdfSha256 => hpke_types::KdfAlgorithm::HkdfSha256,
HpkeKdfType::HkdfSha384 => hpke_types::KdfAlgorithm::HkdfSha384,
HpkeKdfType::HkdfSha512 => hpke_types::KdfAlgorithm::HkdfSha512,
}
}
#[inline(always)]
fn aead_mode(aead: HpkeAeadType) -> hpke_types::AeadAlgorithm {
match aead {
HpkeAeadType::AesGcm128 => hpke_types::AeadAlgorithm::Aes128Gcm,
HpkeAeadType::AesGcm256 => hpke_types::AeadAlgorithm::Aes256Gcm,
HpkeAeadType::ChaCha20Poly1305 => hpke_types::AeadAlgorithm::ChaCha20Poly1305,
HpkeAeadType::Export => hpke_types::AeadAlgorithm::HpkeExport,
}
}
const P256_SCALAR_LENGTH: usize = 32;
const INTEGER_TAG: u8 = 0x02;
const SEQUENCE_TAG: u8 = 0x30;
impl<R: Read + ?Sized> ReadU8 for R {}
pub trait ReadU8: Read {
#[inline]
fn read_u8(&mut self) -> std::io::Result<u8> {
let mut buf = [0; 1];
self.read_exact(&mut buf)?;
Ok(buf[0])
}
}
impl<W: Write + ?Sized> WriteU8 for W {}
pub trait WriteU8: Write {
#[inline]
fn write_u8(&mut self, n: u8) -> std::io::Result<()> {
self.write_all(&[n])
}
}
fn der_encode(raw_signature: &[u8]) -> Result<Vec<u8>, CryptoError> {
fn scalar_length(mut scalar: &[u8]) -> Result<usize, CryptoError> {
let mut msb = scalar
.read_u8()
.map_err(|_| CryptoError::SignatureEncodingError)?;
while msb == 0x00 {
msb = scalar
.read_u8()
.map_err(|_| CryptoError::SignatureEncodingError)?;
}
let mut scalar_length = scalar.len() + 1;
if msb > 0x7F {
scalar_length += 1;
};
Ok(scalar_length)
}
fn encode_scalar<W: Write>(mut scalar: &[u8], mut buffer: W) -> Result<(), CryptoError> {
if scalar.len() != P256_SCALAR_LENGTH {
log::error!("Error while encoding scalar: Scalar too large.");
return Err(CryptoError::SignatureEncodingError);
}
buffer
.write_u8(INTEGER_TAG)
.map_err(|_| CryptoError::SignatureEncodingError)?;
let scalar_length = scalar_length(scalar)?;
buffer
.write_u8(scalar_length as u8)
.map_err(|_| CryptoError::SignatureEncodingError)?;
let mut msb = scalar
.read_u8()
.map_err(|_| CryptoError::SignatureEncodingError)?;
while msb == 0x00 {
msb = scalar
.read_u8()
.map_err(|_| CryptoError::SignatureEncodingError)?;
}
if msb > 0x7F {
buffer
.write_u8(0x00)
.map_err(|_| CryptoError::SignatureEncodingError)?;
};
buffer
.write_u8(msb)
.map_err(|_| CryptoError::SignatureEncodingError)?;
buffer
.write_all(scalar)
.map_err(|_| CryptoError::SignatureEncodingError)?;
Ok(())
}
if raw_signature.len() != 2 * P256_SCALAR_LENGTH {
return Err(CryptoError::SignatureEncodingError);
}
let r = raw_signature
.get(..P256_SCALAR_LENGTH)
.ok_or(CryptoError::SignatureEncodingError)?;
let s = raw_signature
.get(P256_SCALAR_LENGTH..2 * P256_SCALAR_LENGTH)
.ok_or(CryptoError::SignatureEncodingError)?;
let length_r = scalar_length(r)?;
let length_s = scalar_length(s)?;
let mut encoded_signature: Vec<u8> = Vec::with_capacity(6 + length_r + length_s);
encoded_signature
.write_u8(SEQUENCE_TAG)
.map_err(|_| CryptoError::SignatureEncodingError)?;
encoded_signature
.write_u8((4 + length_r + length_s) as u8)
.map_err(|_| CryptoError::SignatureEncodingError)?;
encode_scalar(r, &mut encoded_signature)?;
encode_scalar(s, &mut encoded_signature)?;
Ok(encoded_signature)
}
fn der_decode(mut signature_bytes: &[u8]) -> Result<Vec<u8>, CryptoError> {
fn decode_scalar<R: Read>(mut buffer: R) -> Result<Vec<u8>, CryptoError> {
let integer_tag = buffer
.read_u8()
.map_err(|_| CryptoError::SignatureDecodingError)?;
if integer_tag != INTEGER_TAG {
log::error!("Error while decoding scalar: Couldn't find INTEGER tag.");
return Err(CryptoError::SignatureDecodingError);
};
let mut scalar_length = buffer
.read_u8()
.map_err(|_| CryptoError::SignatureDecodingError)?
as usize;
if scalar_length > P256_SCALAR_LENGTH + 1 {
log::error!("Error while decoding scalar: Scalar too long.");
return Err(CryptoError::SignatureDecodingError);
};
if scalar_length == P256_SCALAR_LENGTH + 1 {
if buffer
.read_u8()
.map_err(|_| CryptoError::SignatureDecodingError)?
!= 0x00
{
log::error!("Error while decoding scalar: Scalar too large or invalid encoding.");
return Err(CryptoError::SignatureDecodingError);
};
scalar_length -= 1;
};
let mut scalar = vec![0; scalar_length];
buffer
.read_exact(&mut scalar)
.map_err(|_| CryptoError::SignatureDecodingError)?;
let mut padded_scalar = vec![0u8; P256_SCALAR_LENGTH - scalar_length];
padded_scalar.append(&mut scalar);
Ok(padded_scalar)
}
let sequence_tag = signature_bytes
.read_u8()
.map_err(|_| CryptoError::SignatureDecodingError)?;
if sequence_tag != SEQUENCE_TAG {
log::error!("Error while decoding DER encoded signature: Couldn't find SEQUENCE tag.");
return Err(CryptoError::SignatureDecodingError);
};
let length = signature_bytes
.read_u8()
.map_err(|_| CryptoError::SignatureDecodingError)? as usize;
if length > 2 * (P256_SCALAR_LENGTH + 3) {
log::error!("Error while decoding DER encoded signature: Signature too long.");
return Err(CryptoError::SignatureDecodingError);
}
if signature_bytes.len() != length {
log::error!("Error while decoding DER encoded signature: Encoded length inaccurate.");
return Err(CryptoError::SignatureDecodingError);
}
let mut r = decode_scalar(&mut signature_bytes)?;
let mut s = decode_scalar(&mut signature_bytes)?;
if !signature_bytes.is_empty() {
log::error!("Error while decoding DER encoded signature: Encoded overall length does not match the sum of scalar lengths.");
return Err(CryptoError::SignatureDecodingError);
}
let mut out = Vec::with_capacity(2 * P256_SCALAR_LENGTH);
out.append(&mut r);
out.append(&mut s);
Ok(out)
}
#[test]
fn test_der_codec() {
let evercrypt = EvercryptProvider::default();
let payload = vec![0u8];
let signature_scheme = SignatureScheme::ECDSA_SECP256R1_SHA256;
let (sk, pk) = signature_key_gen(signature_mode(signature_scheme).unwrap())
.expect("error generating sig keypair");
let signature = evercrypt
.sign(signature_scheme, &payload, &sk)
.expect("error creating signature");
let decoded_signature = der_decode(&signature).expect("Error decoding valid signature.");
verify(
SignatureMode::P256,
Some(hash_from_signature(signature_scheme).expect("Couldn't get digest mode of P256")),
&pk,
&decoded_signature,
&payload,
)
.expect("error while verifying der decoded signature");
let re_encoded_signature =
der_encode(&decoded_signature).expect("error encoding valid signature");
assert_eq!(re_encoded_signature, signature);
evercrypt
.verify_signature(signature_scheme, &payload, &pk, &signature)
.expect("error verifying signature");
}
#[test]
fn test_der_decoding() {
let evercrypt = EvercryptProvider::default();
let payload = vec![0u8];
let signature_scheme = SignatureScheme::ECDSA_SECP256R1_SHA256;
let (sk, _) = signature_key_gen(signature_mode(signature_scheme).unwrap())
.expect("error generating sig keypair");
let signature = evercrypt
.sign(signature_scheme, &payload, &sk)
.expect("error creating signature");
let original_bytes = signature;
let mut wrong_sequence_tag = original_bytes.clone();
wrong_sequence_tag[0] ^= 0xFF;
assert_eq!(
der_decode(&wrong_sequence_tag).expect_err("invalid signature successfully decoded"),
CryptoError::SignatureDecodingError
);
let mut too_long = original_bytes.clone();
too_long.extend_from_slice(&original_bytes);
assert_eq!(
der_decode(&too_long).expect_err("invalid signature successfully decoded"),
CryptoError::SignatureDecodingError
);
let mut inaccurate_length = original_bytes.clone();
inaccurate_length[1] = 0x9F;
assert_eq!(
der_decode(&inaccurate_length).expect_err("invalid signature successfully decoded"),
CryptoError::SignatureDecodingError
);
let mut wrong_integer_tag = original_bytes.clone();
wrong_integer_tag[2] ^= 0xFF;
assert_eq!(
der_decode(&wrong_sequence_tag).expect_err("invalid signature successfully decoded"),
CryptoError::SignatureDecodingError
);
let mut scalar_too_long = original_bytes.clone();
scalar_too_long[3] = 0x9F;
assert_eq!(
der_decode(&scalar_too_long).expect_err("invalid signature successfully decoded"),
CryptoError::SignatureDecodingError
);
let mut scalar_length_encoding = original_bytes.clone();
scalar_length_encoding[3] = 0x21;
scalar_length_encoding[4] = 0xFF;
assert_eq!(
der_decode(&scalar_length_encoding).expect_err("invalid signature successfully decoded"),
CryptoError::SignatureDecodingError
);
let empty_signature = Vec::new();
assert_eq!(
der_decode(&empty_signature).expect_err("invalid signature successfully decoded"),
CryptoError::SignatureDecodingError
);
let one_byte_sig = vec![0x30];
assert_eq!(
der_decode(&one_byte_sig).expect_err("invalid signature successfully decoded"),
CryptoError::SignatureDecodingError
);
let mut signature_too_long_2 = original_bytes.clone();
signature_too_long_2[1] += 0x01;
signature_too_long_2.extend_from_slice(&[0]);
assert_eq!(
der_decode(&signature_too_long_2).expect_err("invalid signature successfully decoded"),
CryptoError::SignatureDecodingError
);
}
#[test]
fn test_der_encoding() {
let evercrypt = EvercryptProvider::default();
let payload = vec![0u8];
let signature_scheme = SignatureScheme::ECDSA_SECP256R1_SHA256;
let (sk, _) = signature_key_gen(signature_mode(signature_scheme).unwrap())
.expect("error generating sig keypair");
let signature = evercrypt
.sign(signature_scheme, &payload, &sk)
.expect("error creating signature");
let raw_signature = der_decode(&signature).expect("error decoding a valid siganture");
let empty_signature = Vec::new();
assert_eq!(
der_encode(&empty_signature).expect_err("successfully encoded invalid raw signature"),
CryptoError::SignatureEncodingError
);
let mut signature_too_long = raw_signature.clone();
signature_too_long.extend_from_slice(&raw_signature);
assert_eq!(
der_encode(&signature_too_long).expect_err("successfully encoded invalid raw signature"),
CryptoError::SignatureEncodingError
);
let zero_scalar = vec![0x00; 2 * P256_SCALAR_LENGTH];
assert_eq!(
der_encode(&zero_scalar).expect_err("successfully encoded invalid raw signature"),
CryptoError::SignatureEncodingError
);
}
impl OpenMlsRand for EvercryptProvider {
type Error = &'static str;
fn random_array<const N: usize>(&self) -> Result<[u8; N], Self::Error> {
let mut rng = self.rng.write().map_err(|_| "Rng lock is poisoned.")?;
let mut out = [0u8; N];
rng.try_fill_bytes(&mut out)
.map_err(|_| "Unable to collect enough randomness.")?;
Ok(out)
}
fn random_vec(&self, len: usize) -> Result<Vec<u8>, Self::Error> {
let mut rng = self.rng.write().map_err(|_| "Rng lock is poisoned.")?;
let mut out = vec![0u8; len];
rng.try_fill_bytes(&mut out)
.map_err(|_| "Unable to collect enough randomness.")?;
Ok(out)
}
}