2021-07-09 12:26:42 +00:00
|
|
|
use std::fmt::{self, Display};
|
|
|
|
|
|
|
|
use anyhow::Error;
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
|
2021-10-08 09:19:37 +00:00
|
|
|
use proxmox_schema::api;
|
2021-07-09 12:26:42 +00:00
|
|
|
|
|
|
|
#[api(default: "encrypt")]
|
|
|
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
|
|
|
|
#[serde(rename_all = "kebab-case")]
|
|
|
|
/// Defines whether data is encrypted (using an AEAD cipher), only signed, or neither.
|
|
|
|
pub enum CryptMode {
|
|
|
|
/// Don't encrypt.
|
|
|
|
None,
|
|
|
|
/// Encrypt.
|
|
|
|
Encrypt,
|
|
|
|
/// Only sign.
|
|
|
|
SignOnly,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Eq, PartialEq, Hash, Clone, Deserialize, Serialize)]
|
|
|
|
#[serde(transparent)]
|
|
|
|
/// 32-byte fingerprint, usually calculated with SHA256.
|
|
|
|
pub struct Fingerprint {
|
|
|
|
#[serde(with = "bytes_as_fingerprint")]
|
|
|
|
bytes: [u8; 32],
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Fingerprint {
|
|
|
|
pub fn new(bytes: [u8; 32]) -> Self {
|
|
|
|
Self { bytes }
|
|
|
|
}
|
|
|
|
pub fn bytes(&self) -> &[u8; 32] {
|
|
|
|
&self.bytes
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Display as short key ID
|
|
|
|
impl Display for Fingerprint {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
write!(f, "{}", as_fingerprint(&self.bytes[0..8]))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl std::str::FromStr for Fingerprint {
|
|
|
|
type Err = Error;
|
|
|
|
|
|
|
|
fn from_str(s: &str) -> Result<Self, Error> {
|
|
|
|
let mut tmp = s.to_string();
|
|
|
|
tmp.retain(|c| c != ':');
|
|
|
|
let bytes = proxmox::tools::hex_to_digest(&tmp)?;
|
|
|
|
Ok(Fingerprint::new(bytes))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-17 06:07:40 +00:00
|
|
|
fn as_fingerprint(bytes: &[u8]) -> String {
|
|
|
|
hex::encode(bytes)
|
|
|
|
.as_bytes()
|
|
|
|
.chunks(2)
|
|
|
|
.map(|v| unsafe { std::str::from_utf8_unchecked(v) }) // it's a hex string
|
|
|
|
.collect::<Vec<&str>>().join(":")
|
|
|
|
}
|
|
|
|
|
|
|
|
pub mod bytes_as_fingerprint {
|
|
|
|
use std::mem::MaybeUninit;
|
|
|
|
|
|
|
|
use serde::{Deserialize, Serializer, Deserializer};
|
|
|
|
|
|
|
|
pub fn serialize<S>(
|
|
|
|
bytes: &[u8; 32],
|
|
|
|
serializer: S,
|
|
|
|
) -> Result<S::Ok, S::Error>
|
|
|
|
where
|
|
|
|
S: Serializer,
|
|
|
|
{
|
|
|
|
let s = super::as_fingerprint(bytes);
|
|
|
|
serializer.serialize_str(&s)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn deserialize<'de, D>(
|
|
|
|
deserializer: D,
|
|
|
|
) -> Result<[u8; 32], D::Error>
|
|
|
|
where
|
|
|
|
D: Deserializer<'de>,
|
|
|
|
{
|
|
|
|
// TODO: more efficiently implement with a Visitor implementing visit_str using split() and
|
|
|
|
// hex::decode by-byte
|
|
|
|
let mut s = String::deserialize(deserializer)?;
|
|
|
|
s.retain(|c| c != ':');
|
|
|
|
let mut out = MaybeUninit::<[u8; 32]>::uninit();
|
|
|
|
hex::decode_to_slice(s.as_bytes(), unsafe { &mut (*out.as_mut_ptr())[..] })
|
|
|
|
.map_err(serde::de::Error::custom)?;
|
|
|
|
Ok(unsafe { out.assume_init() })
|
|
|
|
}
|
|
|
|
}
|