use crate::{MResult, ServerError};
#[derive(Clone)]
pub struct SignKeypair {
inner: InnerSignKeypair,
}
#[non_exhaustive]
#[derive(Clone)]
enum InnerSignKeypair {
#[cfg(feature = "ed25519-utils")]
Ed25519(Box<ed25519_dalek::SigningKey>),
#[cfg(feature = "pqc-utils")]
Dilithium5(Box<authnz_pqc_dilithium::Keypair>),
}
impl InnerSignKeypair {
fn pack(&self) -> String {
use base64::{Engine as _, engine::general_purpose::STANDARD};
#[allow(unreachable_patterns)]
match self {
#[cfg(feature = "ed25519-utils")]
Self::Ed25519(keypair) => STANDARD.encode(keypair.to_keypair_bytes()),
#[cfg(feature = "pqc-utils")]
Self::Dilithium5(keypair) => format!(
"{}::||::{}",
STANDARD.encode(keypair.public),
STANDARD.encode(keypair.expose_secret())
),
_ => unreachable!(),
}
}
#[allow(clippy::unwrap_used)]
fn unpack(cert: impl AsRef<str>) -> MResult<Self> {
use base64::{Engine as _, engine::general_purpose::STANDARD};
#[cfg(feature = "pqc-utils")]
if cert.as_ref().contains("::||::") {
let parts = cert.as_ref().split("::||::").collect::<Vec<_>>();
if parts.len() != 2 {
return Err(
ServerError::from_private_str("Certificate have no part divider, this is not the certificate!")
.with_private_str("Invalid certificate!")
.with_500(),
);
}
let public = parts.first().unwrap();
let public = STANDARD.decode(public).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't decode public certificate part!")
.with_500()
})?;
let private = parts.last().unwrap();
let private = STANDARD.decode(private).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't decode private certificate part!")
.with_500()
})?;
return Ok(Self::Dilithium5(Box::new(
authnz_pqc_dilithium::Keypair::restore(&public, &private).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't restore Dilithium5 keypair!")
.with_500()
})?,
)));
}
#[cfg(feature = "ed25519-utils")]
{
let keypair = STANDARD.decode(cert.as_ref()).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't decode Ed25519 certificate!")
.with_500()
})?;
return Ok(Self::Ed25519(Box::new(
ed25519_dalek::SigningKey::from_keypair_bytes(keypair.as_slice().try_into().map_err(|e| {
ServerError::from_private(e)
.with_private_str("Incorrect keypair length!")
.with_500()
})?)
.map_err(|e| {
ServerError::from_private(e)
.with_private_str("Incorrect Ed25519 certificate!")
.with_500()
})?,
)));
}
#[allow(unreachable_code)]
Err(ServerError::from_private_str("Enable at least one of `ed25519-utils`, `pqc-utils` to use SignKeypair!").with_500())
}
fn public(&self) -> Vec<u8> {
#[cfg(feature = "pqc-utils")]
#[allow(irrefutable_let_patterns)]
if let Self::Dilithium5(keypair) = &self {
return keypair.public.to_vec();
}
#[cfg(feature = "ed25519-utils")]
#[allow(irrefutable_let_patterns)]
if let Self::Ed25519(keypair) = &self {
return keypair.verifying_key().as_bytes().to_vec();
}
unreachable!()
}
fn private(&self) -> Vec<u8> {
#[cfg(feature = "pqc-utils")]
#[allow(irrefutable_let_patterns)]
if let Self::Dilithium5(keypair) = &self {
return keypair.expose_secret().to_vec();
}
#[cfg(feature = "ed25519-utils")]
#[allow(irrefutable_let_patterns)]
if let Self::Ed25519(keypair) = &self {
return keypair.as_bytes().to_vec();
}
unreachable!()
}
}
impl SignKeypair {
#[cfg(feature = "ed25519-utils")]
pub fn new_ed25519() -> MResult<Self> {
use rand::TryRngCore;
let mut csprng = rand::rngs::OsRng;
let mut secret = ed25519_dalek::SecretKey::default();
csprng.try_fill_bytes(&mut secret).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't generate Ed25519 certificate!")
.with_500()
})?;
Ok(Self {
inner: InnerSignKeypair::Ed25519(Box::new(ed25519_dalek::SigningKey::from_bytes(&secret))),
})
}
#[cfg(feature = "pqc-utils")]
pub fn new_dilithium5() -> Self {
Self {
inner: InnerSignKeypair::Dilithium5(Box::new(authnz_pqc_dilithium::Keypair::generate())),
}
}
pub fn pack_keypair(&self) -> String {
self.inner.pack()
}
pub fn unpack_keypair(keypair: impl AsRef<str>) -> MResult<Self> {
Ok(Self {
inner: InnerSignKeypair::unpack(keypair)?,
})
}
pub fn sign_raw(&self, data: &[u8]) -> Vec<u8> {
#[allow(unreachable_patterns)]
match &self.inner {
#[cfg(feature = "ed25519-utils")]
InnerSignKeypair::Ed25519(keypair) => ed25519_dalek::Signer::sign(keypair.as_ref(), data).to_vec(),
#[cfg(feature = "pqc-utils")]
InnerSignKeypair::Dilithium5(keypair) => keypair.sign(data).to_vec(),
_ => unreachable!(),
}
}
pub fn verify_raw(data: &[u8], sign: &[u8], public_key: &[u8]) -> MResult<()> {
#[cfg(feature = "pqc-utils")]
if authnz_pqc_dilithium::verify(sign, data, public_key).is_ok() {
return Ok(());
}
#[cfg(feature = "ed25519-utils")]
if let Ok(pkey) = public_key.try_into()
&& let Ok(vkey) = ed25519_dalek::VerifyingKey::from_bytes(pkey)
&& let Ok(sign) = ed25519_dalek::Signature::from_slice(sign)
&& ed25519_dalek::Verifier::verify(&vkey, data, &sign).is_ok()
{
return Ok(());
}
Err(ServerError::from_public("Invalid signature!").with_401())
}
pub fn sign<T: serde::Serialize>(&self, data: &T) -> MResult<Vec<u8>> {
rmp_serde::to_vec(data)
.map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't serialize data to sign!")
.with_500()
})
.map(|v| self.sign_raw(&v))
}
pub fn verify<T: serde::Serialize>(data: &T, sign: &[u8], public_key: &[u8]) -> MResult<()> {
let data = rmp_serde::to_vec(data).map_err(|e| {
ServerError::from_private(e)
.with_private_str("Can't serialize data to validate signature!")
.with_500()
})?;
Self::verify_raw(&data, sign, public_key)
}
pub fn verify_token(header: &[u8], payload: &[u8], sign: &[u8], public_key: &[u8]) -> MResult<()> {
let mut data = header.to_vec();
data.extend_from_slice(payload);
Self::verify_raw(&data, sign, public_key)
}
pub fn public(&self) -> Vec<u8> {
self.inner.public()
}
pub unsafe fn private(&self) -> Vec<u8> {
self.inner.private()
}
}