1use crate::error::AuthError;
2use ed25519_dalek::{
3 Signature, Signer, SigningKey as EdSigningKey, Verifier, VerifyingKey as EdVerifyingKey,
4};
5use std::fs;
6use std::path::Path;
7
8#[derive(Debug, Clone)]
10pub struct SigningKey {
11 inner: EdSigningKey,
12}
13
14impl SigningKey {
15 pub fn generate() -> Self {
17 use rand::rngs::OsRng;
18 use rand::RngCore;
19 let mut bytes = [0u8; 32];
20 OsRng.fill_bytes(&mut bytes);
21 Self {
22 inner: EdSigningKey::from_bytes(&bytes),
23 }
24 }
25
26 pub fn from_bytes(bytes: &[u8; 32]) -> Self {
28 Self {
29 inner: EdSigningKey::from_bytes(bytes),
30 }
31 }
32
33 pub fn verifying_key(&self) -> VerifyingKey {
35 VerifyingKey {
36 inner: self.inner.verifying_key(),
37 }
38 }
39
40 pub fn key_id(&self) -> String {
42 self.verifying_key().key_id()
43 }
44
45 pub fn sign(&self, message: &[u8]) -> Signature {
47 self.inner.sign(message)
48 }
49
50 pub fn to_bytes(&self) -> [u8; 32] {
52 self.inner.to_bytes()
53 }
54
55 pub fn to_keypair_bytes(&self) -> [u8; 64] {
57 self.inner.to_keypair_bytes()
58 }
59
60 pub fn from_keypair_bytes(bytes: &[u8; 64]) -> Result<Self, AuthError> {
62 let key = EdSigningKey::from_keypair_bytes(bytes)
63 .map_err(|e| AuthError::InvalidKeyFormat(format!("Invalid keypair: {:?}", e)))?;
64 Ok(Self { inner: key })
65 }
66
67 pub fn to_pkcs8_der(&self) -> Result<Vec<u8>, AuthError> {
69 use ed25519_dalek::pkcs8::EncodePrivateKey;
70 self.inner
71 .to_pkcs8_der()
72 .map(|der| der.as_bytes().to_vec())
73 .map_err(|e| AuthError::InvalidKeyFormat(format!("PKCS#8 encoding failed: {:?}", e)))
74 }
75}
76
77#[derive(Debug, Clone)]
79pub struct VerifyingKey {
80 pub(crate) inner: EdVerifyingKey,
81}
82
83impl VerifyingKey {
84 pub fn from_bytes(bytes: &[u8; 32]) -> Result<Self, AuthError> {
86 let key = EdVerifyingKey::from_bytes(bytes)
87 .map_err(|e| AuthError::InvalidKeyFormat(format!("Invalid public key: {:?}", e)))?;
88 Ok(Self { inner: key })
89 }
90
91 pub fn verify(&self, message: &[u8], signature: &Signature) -> Result<(), AuthError> {
93 self.inner
94 .verify(message, signature)
95 .map_err(|e| AuthError::InvalidKeyFormat(format!("Verification failed: {:?}", e)))
96 }
97
98 pub fn to_bytes(&self) -> [u8; 32] {
100 self.inner.to_bytes()
101 }
102
103 pub fn key_id(&self) -> String {
105 let hex = self
106 .to_bytes()
107 .into_iter()
108 .map(|byte| format!("{byte:02x}"))
109 .collect::<String>();
110 hex[..16].to_string()
111 }
112
113 pub fn to_spki_der(&self) -> Result<Vec<u8>, AuthError> {
115 use ed25519_dalek::pkcs8::EncodePublicKey;
116 self.inner
117 .to_public_key_der()
118 .map(|der| der.as_bytes().to_vec())
119 .map_err(|e| AuthError::InvalidKeyFormat(format!("SPKI encoding failed: {:?}", e)))
120 }
121}
122
123pub struct KeyLoader;
125
126impl KeyLoader {
127 pub fn signing_key_from_env(var_name: &str) -> Result<SigningKey, AuthError> {
129 let b64 = std::env::var(var_name).map_err(|_| {
130 AuthError::KeyLoadingFailed(format!("Environment variable {} not set", var_name))
131 })?;
132 let bytes = base64::Engine::decode(&base64::engine::general_purpose::STANDARD, &b64)
133 .map_err(|e| AuthError::InvalidKeyFormat(format!("Invalid base64: {}", e)))?;
134 let key_bytes: [u8; 32] = bytes
135 .try_into()
136 .map_err(|_| AuthError::InvalidKeyFormat("Invalid key length".to_string()))?;
137 Ok(SigningKey::from_bytes(&key_bytes))
138 }
139
140 pub fn verifying_key_from_env(var_name: &str) -> Result<VerifyingKey, AuthError> {
142 let b64 = std::env::var(var_name).map_err(|_| {
143 AuthError::KeyLoadingFailed(format!("Environment variable {} not set", var_name))
144 })?;
145 let bytes = base64::Engine::decode(&base64::engine::general_purpose::STANDARD, &b64)
146 .map_err(|e| AuthError::InvalidKeyFormat(format!("Invalid base64: {}", e)))?;
147 let key_bytes: [u8; 32] = bytes
148 .try_into()
149 .map_err(|_| AuthError::InvalidKeyFormat("Invalid key length".to_string()))?;
150 VerifyingKey::from_bytes(&key_bytes)
151 }
152
153 pub fn generate_and_save_keys(
155 signing_key_path: impl AsRef<Path>,
156 verifying_key_path: impl AsRef<Path>,
157 ) -> Result<(SigningKey, VerifyingKey), AuthError> {
158 let signing_key = SigningKey::generate();
159 let verifying_key = signing_key.verifying_key();
160
161 let signing_b64 = base64::Engine::encode(
163 &base64::engine::general_purpose::STANDARD,
164 signing_key.to_bytes(),
165 );
166 fs::write(signing_key_path, signing_b64)?;
167
168 let verifying_b64 = base64::Engine::encode(
170 &base64::engine::general_purpose::STANDARD,
171 verifying_key.to_bytes(),
172 );
173 fs::write(verifying_key_path, verifying_b64)?;
174
175 Ok((signing_key, verifying_key))
176 }
177
178 pub fn signing_key_from_file(path: impl AsRef<Path>) -> Result<SigningKey, AuthError> {
180 let b64 = fs::read_to_string(path)?;
181 let bytes = base64::Engine::decode(&base64::engine::general_purpose::STANDARD, &b64)
182 .map_err(|e| AuthError::InvalidKeyFormat(format!("Invalid base64: {}", e)))?;
183 let key_bytes: [u8; 32] = bytes
184 .try_into()
185 .map_err(|_| AuthError::InvalidKeyFormat("Invalid key length".to_string()))?;
186 Ok(SigningKey::from_bytes(&key_bytes))
187 }
188
189 pub fn verifying_key_from_file(path: impl AsRef<Path>) -> Result<VerifyingKey, AuthError> {
191 let b64 = fs::read_to_string(path)?;
192 let bytes = base64::Engine::decode(&base64::engine::general_purpose::STANDARD, &b64)
193 .map_err(|e| AuthError::InvalidKeyFormat(format!("Invalid base64: {}", e)))?;
194 let key_bytes: [u8; 32] = bytes
195 .try_into()
196 .map_err(|_| AuthError::InvalidKeyFormat("Invalid key length".to_string()))?;
197 VerifyingKey::from_bytes(&key_bytes)
198 }
199}
200
201#[cfg(test)]
202mod tests {
203 use super::*;
204
205 #[test]
206 fn test_generate_and_sign() {
207 let signing_key = SigningKey::generate();
208 let message = b"test message";
209 let signature = signing_key.sign(message);
210
211 let verifying_key = signing_key.verifying_key();
212 assert!(verifying_key.verify(message, &signature).is_ok());
213 }
214
215 #[test]
216 fn test_bytes_roundtrip() {
217 let signing_key = SigningKey::generate();
218 let bytes = signing_key.to_bytes();
219
220 let loaded = SigningKey::from_bytes(&bytes);
221 assert_eq!(
222 signing_key.verifying_key().to_bytes(),
223 loaded.verifying_key().to_bytes()
224 );
225 }
226
227 #[test]
228 fn test_keypair_bytes_roundtrip() {
229 let signing_key = SigningKey::generate();
230 let keypair_bytes = signing_key.to_keypair_bytes();
231
232 let loaded = SigningKey::from_keypair_bytes(&keypair_bytes).unwrap();
233 assert_eq!(
234 signing_key.verifying_key().to_bytes(),
235 loaded.verifying_key().to_bytes()
236 );
237 }
238}