use super::{
COSEAlgorithm, COSEEC2Key, COSEKey, COSEKeyType,
ECDHSecret, ECDSACurve,
};
use ring::agreement::{
agree_ephemeral, Algorithm, EphemeralPrivateKey, UnparsedPublicKey, ECDH_P256, ECDH_P384,
};
use ring::digest;
use ring::hmac;
use ring::rand::SystemRandom;
use ring::signature::KeyPair;
use serde::Serialize;
use serde_bytes::ByteBuf;
pub type Result<T> = std::result::Result<T, BackendError>;
#[derive(Clone, Debug, PartialEq, Serialize)]
pub enum BackendError {
AgreementError,
UnspecifiedRingError,
KeyRejected,
UnsupportedKeyType,
UnsupportedCurve(ECDSACurve),
}
fn to_ring_curve(curve: ECDSACurve) -> Result<&'static Algorithm> {
match curve {
ECDSACurve::SECP256R1 => Ok(&ECDH_P256),
ECDSACurve::SECP384R1 => Ok(&ECDH_P384),
x => Err(BackendError::UnsupportedCurve(x)),
}
}
impl From<ring::error::Unspecified> for BackendError {
fn from(e: ring::error::Unspecified) -> Self {
BackendError::UnspecifiedRingError
}
}
impl From<ring::error::KeyRejected> for BackendError {
fn from(e: ring::error::KeyRejected) -> Self {
BackendError::KeyRejected
}
}
pub(crate) fn parse_key(curve: ECDSACurve, x: &[u8], y: &[u8]) -> Result<Vec<u8>> {
compile_error!(
"Ring-backend is not yet implemented. Compile with `--features crypto_openssl` for now."
)
}
pub(crate) fn serialize_key(curve: ECDSACurve, key: &[u8]) -> Result<(ByteBuf, ByteBuf)> {
compile_error!(
"Ring-backend is not yet implemented. Compile with `--features crypto_openssl` for now."
)
}
pub(crate) fn initialize() {
compile_error!(
"Ring-backend is not yet implemented. Compile with `--features crypto_openssl` for now."
)
}
pub(crate) fn encapsulate(key: &COSEKey) -> Result<ECDHSecret> {
if let COSEKeyType::EC2(ec2key) = &key.key {
let rng = SystemRandom::new();
let peer_public_key_alg = to_ring_curve(ec2key.curve)?;
let private_key = EphemeralPrivateKey::generate(peer_public_key_alg, &rng)?;
let my_public_key = private_key.compute_public_key()?;
let (x, y) = serialize_key(ec2key.curve, my_public_key.as_ref())?;
let my_public_key = COSEKey {
alg: key.alg,
key: COSEKeyType::EC2(COSEEC2Key {
curve: ec2key.curve,
x: x.to_vec(),
y: y.to_vec(),
}),
};
let key_bytes = parse_key(ec2key.curve, &ec2key.x, &ec2key.y)?;
let peer_public_key = UnparsedPublicKey::new(peer_public_key_alg, &key_bytes);
let shared_secret = agree_ephemeral(private_key, &peer_public_key, (), |key_material| {
let digest = digest::digest(&digest::SHA256, key_material);
Ok(Vec::from(digest.as_ref()))
})
.map_err(|_| BackendError::AgreementError)?;
Ok(ECDHSecret {
remote: COSEKey {
alg: key.alg,
key: COSEKeyType::EC2(ec2key.clone()),
},
my: my_public_key,
shared_secret,
})
} else {
Err(BackendError::UnsupportedKeyType)
}
}
#[cfg(test)]
pub(crate) fn test_encapsulate(
key: &COSEEC2Key,
alg: COSEAlgorithm,
my_pub_key: &[u8],
my_priv_key: &[u8],
) -> Result<ECDHSecret> {
compile_error!(
"Ring-backend is not yet implemented. Compile with `--features crypto_openssl` for now."
)
}
pub(crate) fn encrypt(
key: &[u8],
plain_text: &[u8],
) -> Result<Vec<u8> > {
compile_error!(
"Ring-backend is not yet implemented. Compile with `--features crypto_openssl` for now."
)
}
pub(crate) fn decrypt(
key: &[u8],
cypher_text: &[u8],
) -> Result<Vec<u8> > {
compile_error!(
"Ring-backend is not yet implemented. Compile with `--features crypto_openssl` for now."
)
}
pub(crate) fn authenticate(token: &[u8], input: &[u8]) -> Result<Vec<u8>> {
let s_key = hmac::Key::new(hmac::HMAC_SHA256, token);
let tag = hmac::sign(&s_key, input);
Ok(tag.as_ref().to_vec())
}