use age::x25519::Identity;
use argon2::password_hash::SaltString;
use secrecy::{ExposeSecret, SecretBox, SecretString};
use std::convert::AsRef;
use std::fmt;
use crate::{
crypto::{KeyDerivation, Seed},
Result,
};
#[derive(Clone)]
pub enum AccessKey {
Password(SecretString),
Identity(Identity),
}
impl From<SecretString> for AccessKey {
fn from(value: SecretString) -> Self {
Self::Password(value)
}
}
impl From<Identity> for AccessKey {
fn from(value: Identity) -> Self {
Self::Identity(value)
}
}
impl From<AccessKey> for SecretString {
fn from(value: AccessKey) -> Self {
match value {
AccessKey::Password(password) => password,
AccessKey::Identity(id) => id.to_string().into(),
}
}
}
impl AccessKey {
pub fn into_private(
self,
kdf: &KeyDerivation,
salt: &SaltString,
seed: Option<&Seed>,
) -> Result<PrivateKey> {
match self {
Self::Password(ref password) => {
let deriver = kdf.deriver();
Ok(PrivateKey::Symmetric(
deriver.derive(password, salt, seed)?,
))
}
Self::Identity(id) => Ok(PrivateKey::Asymmetric(id)),
}
}
}
impl fmt::Debug for AccessKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Password(_) => f.debug_struct("Password").finish(),
Self::Identity(_) => f.debug_struct("Identity").finish(),
}
}
}
impl PartialEq for AccessKey {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Password(a), Self::Password(b)) => {
a.expose_secret() == b.expose_secret()
}
(Self::Identity(a), Self::Identity(b)) => {
a.to_string().expose_secret() == b.to_string().expose_secret()
}
_ => false,
}
}
}
impl Eq for AccessKey {}
pub enum PrivateKey {
Symmetric(DerivedPrivateKey),
Asymmetric(Identity),
}
pub struct DerivedPrivateKey {
inner: SecretBox<Vec<u8>>,
}
impl DerivedPrivateKey {
pub fn generate() -> Self {
use crate::crypto::csprng;
use rand::Rng;
let bytes: [u8; 32] = csprng().gen();
Self {
inner: SecretBox::new(Box::new(bytes.to_vec())),
}
}
pub fn from_pem(key: &str) -> Result<Self> {
let pem = pem::parse(key)?;
let contents = pem.contents();
Ok(Self {
inner: SecretBox::new(Box::new(contents.to_vec())),
})
}
pub fn to_pem(&self) -> String {
pem::encode(&pem::Pem::new(
"PRIVATE KEY",
self.inner.expose_secret().as_slice(),
))
}
pub(crate) fn new(inner: SecretBox<Vec<u8>>) -> Self {
Self { inner }
}
}
impl AsRef<[u8]> for DerivedPrivateKey {
fn as_ref(&self) -> &[u8] {
self.inner.expose_secret()
}
}
impl From<Vec<u8>> for DerivedPrivateKey {
fn from(value: Vec<u8>) -> Self {
Self {
inner: SecretBox::new(value.into()),
}
}
}