bitwarden_ssh/
generator.rsuse serde::{Deserialize, Serialize};
use ssh_key::{rand_core::CryptoRngCore, Algorithm};
#[cfg(feature = "wasm")]
use tsify_next::Tsify;
use crate::{error, error::KeyGenerationError, SshKey};
#[derive(Serialize, Deserialize)]
#[cfg_attr(feature = "wasm", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
pub enum KeyAlgorithm {
Ed25519,
Rsa3072,
Rsa4096,
}
pub fn generate_sshkey(key_algorithm: KeyAlgorithm) -> Result<SshKey, error::KeyGenerationError> {
let rng = rand::thread_rng();
generate_sshkey_internal(key_algorithm, rng)
}
fn generate_sshkey_internal(
key_algorithm: KeyAlgorithm,
mut rng: impl CryptoRngCore,
) -> Result<SshKey, error::KeyGenerationError> {
let private_key = match key_algorithm {
KeyAlgorithm::Ed25519 => ssh_key::PrivateKey::random(&mut rng, Algorithm::Ed25519)
.map_err(KeyGenerationError::KeyGenerationError),
KeyAlgorithm::Rsa3072 => create_rsa_key(&mut rng, 3072),
KeyAlgorithm::Rsa4096 => create_rsa_key(&mut rng, 4096),
}?;
private_key
.try_into()
.map_err(|_| KeyGenerationError::KeyConversionError)
}
fn create_rsa_key(
mut rng: impl CryptoRngCore,
bits: usize,
) -> Result<ssh_key::PrivateKey, error::KeyGenerationError> {
let rsa_keypair = ssh_key::private::RsaKeypair::random(&mut rng, bits)
.map_err(KeyGenerationError::KeyGenerationError)?;
let private_key =
ssh_key::PrivateKey::new(ssh_key::private::KeypairData::from(rsa_keypair), "")
.map_err(KeyGenerationError::KeyGenerationError)?;
Ok(private_key)
}
#[cfg(test)]
mod tests {
use rand::SeedableRng;
use super::KeyAlgorithm;
use crate::generator::generate_sshkey_internal;
#[test]
fn generate_ssh_key_ed25519() {
let rng = rand_chacha::ChaCha12Rng::from_seed([0u8; 32]);
let key_algorithm = KeyAlgorithm::Ed25519;
let result = generate_sshkey_internal(key_algorithm, rng);
let target = include_str!("../resources/generator/ed25519_key").replace("\r\n", "\n");
assert_eq!(result.unwrap().private_key, target);
}
#[test]
fn generate_ssh_key_rsa3072() {
let rng = rand_chacha::ChaCha12Rng::from_seed([0u8; 32]);
let key_algorithm = KeyAlgorithm::Rsa3072;
let result = generate_sshkey_internal(key_algorithm, rng);
let target = include_str!("../resources/generator/rsa3072_key").replace("\r\n", "\n");
assert_eq!(result.unwrap().private_key, target);
}
#[test]
fn generate_ssh_key_rsa4096() {
let rng = rand_chacha::ChaCha12Rng::from_seed([0u8; 32]);
let key_algorithm = KeyAlgorithm::Rsa4096;
let result = generate_sshkey_internal(key_algorithm, rng);
let target = include_str!("../resources/generator/rsa4096_key").replace("\r\n", "\n");
assert_eq!(result.unwrap().private_key, target);
}
}