1use ed25519_dalek::SigningKey;
2use russh_keys::key::KeyPair;
3use std::sync::Arc;
4use styrene_identity::derive::KeyDeriver;
5use styrene_identity::signer::{RootSecret, SignerError};
6use zeroize::Zeroize;
7
8pub fn derive_key_pair(root: &RootSecret, label: &str) -> Result<Arc<KeyPair>, AuthError> {
13 let deriver = KeyDeriver::new(root.as_bytes());
14 let mut seed = deriver
15 .derive_ssh_user_key(label)
16 .map_err(|e| AuthError::Derivation(e.to_string()))?;
17 let signing_key = SigningKey::from_bytes(&seed);
18 seed.zeroize();
19 Ok(Arc::new(KeyPair::Ed25519(signing_key)))
20}
21
22pub fn derive_public_key_bytes(root: &RootSecret, label: &str) -> Result<[u8; 32], AuthError> {
24 let deriver = KeyDeriver::new(root.as_bytes());
25 let mut seed = deriver
26 .derive_ssh_user_key(label)
27 .map_err(|e| AuthError::Derivation(e.to_string()))?;
28 let signing_key = SigningKey::from_bytes(&seed);
29 seed.zeroize();
30 let verifying_key = signing_key.verifying_key();
31 Ok(verifying_key.to_bytes())
32}
33
34pub fn public_key_fingerprint(root: &RootSecret, label: &str) -> Result<String, AuthError> {
36 let pubkey_bytes = derive_public_key_bytes(root, label)?;
37 Ok(hex::encode(pubkey_bytes))
38}
39
40#[derive(Debug, thiserror::Error)]
41pub enum AuthError {
42 #[error("key derivation failed: {0}")]
43 Derivation(String),
44 #[error("signer error: {0}")]
45 Signer(#[from] SignerError),
46 #[error("authentication rejected by server")]
47 Rejected,
48}