winisland_plugin_api/packager/
signing.rs1use ed25519_dalek::pkcs8::DecodePrivateKey;
2use ed25519_dalek::{Signature, Signer, SigningKey, VerifyingKey};
3use sha2::{Digest, Sha256};
4use std::path::Path;
5
6#[derive(Debug)]
8pub enum SigningError {
9 Io(std::io::Error),
10 Key(String),
11 Signature(String),
12}
13
14impl std::fmt::Display for SigningError {
15 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16 match self {
17 Self::Io(e) => write!(f, "I/O error: {}", e),
18 Self::Key(msg) => write!(f, "Key error: {}", msg),
19 Self::Signature(msg) => write!(f, "Signature error: {}", msg),
20 }
21 }
22}
23
24impl std::error::Error for SigningError {}
25
26impl From<std::io::Error> for SigningError {
27 fn from(e: std::io::Error) -> Self {
28 Self::Io(e)
29 }
30}
31
32impl From<SigningError> for String {
33 fn from(e: SigningError) -> Self {
34 e.to_string()
35 }
36}
37
38pub fn hash_file(path: &Path) -> Result<String, SigningError> {
40 let data = std::fs::read(path)?;
41 let mut hasher = Sha256::new();
42 hasher.update(&data);
43 Ok(hex::encode(hasher.finalize()))
44}
45
46pub fn load_signing_key(path: &Path) -> Result<SigningKey, SigningError> {
48 let pem = std::fs::read_to_string(path).map_err(|e| {
49 SigningError::Key(format!("Cannot read key file '{}': {}", path.display(), e))
50 })?;
51 let key = SigningKey::from_pkcs8_pem(&pem).map_err(|e| {
52 SigningError::Key(format!("Invalid PEM key in '{}': {}", path.display(), e))
53 })?;
54 Ok(key)
55}
56
57pub fn load_signing_key_from_env(var: &str) -> Result<SigningKey, SigningError> {
59 let pem = std::env::var(var)
60 .map_err(|_| SigningError::Key(format!("Environment variable '{}' not set", var)))?;
61 let key = SigningKey::from_pkcs8_pem(&pem)
62 .map_err(|e| SigningError::Key(format!("Invalid PEM key in env '{}': {}", var, e)))?;
63 Ok(key)
64}
65
66pub fn sign_payload(key: &SigningKey, payload: &[u8]) -> String {
69 let sig: Signature = key.sign(payload);
70 hex::encode(sig.to_bytes())
71}
72
73pub fn verify_signature(
75 public_key: &VerifyingKey,
76 payload: &[u8],
77 signature_hex: &str,
78) -> Result<(), SigningError> {
79 let sig_bytes = hex::decode(signature_hex)
80 .map_err(|_| SigningError::Signature("Invalid hex signature".into()))?;
81 let sig = Signature::from_slice(&sig_bytes)
82 .map_err(|_| SigningError::Signature("Invalid signature bytes".into()))?;
83 public_key
84 .verify_strict(payload, &sig)
85 .map_err(|_| SigningError::Signature("Signature verification failed".into()))
86}