ssh_scp_manager/
rsa.rs

1use std::io;
2
3use base64::Engine;
4use openssl::rsa::Rsa;
5
6pub const DEFAULT_BITS: u32 = 4092;
7
8/// Returns a new RSA key, the private key in PEM encoding, the public key in base64 encoding.
9pub fn new_key(bits: Option<u32>) -> io::Result<(String, String)> {
10    let generated_key =
11        Rsa::generate(if let Some(b) = bits { b } else { DEFAULT_BITS }).map_err(|e| {
12            io::Error::new(
13                io::ErrorKind::Other,
14                format!("failed to rsa generate {}", e),
15            )
16        })?;
17
18    let pk = generated_key.private_key_to_pem().map_err(|e| {
19        io::Error::new(
20            io::ErrorKind::Other,
21            format!("failed to derive rsa private key to pem {}", e),
22        )
23    })?;
24    let pk_pem_encoded = String::from_utf8(pk).map_err(|e| {
25        io::Error::new(
26            io::ErrorKind::Other,
27            format!("failed to convert rsa private key to string {}", e),
28        )
29    })?;
30
31    // ref. <https://www.ietf.org/rfc/rfc4251.txt>
32    let pubkey = generated_key.public_key_to_der().map_err(|e| {
33        io::Error::new(
34            io::ErrorKind::Other,
35            format!("failed to derive rsa public key to der {}", e),
36        )
37    })?;
38    // do not prefix with "ssh-rsa "
39    // otherwise, import ec2 key pair will fail with
40    // "Key is not in valid OpenSSH public key format"
41    let pubkey_der_encoded = base64::engine::general_purpose::STANDARD.encode(pubkey);
42
43    Ok((pk_pem_encoded, pubkey_der_encoded))
44}
45
46/// RUST_LOG=debug cargo test --lib -- rsa::test_key --exact --show-output
47#[test]
48fn test_key() {
49    let (pk_encoded, pubkey_encoded) = new_key(Some(3072)).unwrap();
50    println!("{pk_encoded}");
51    println!("{pubkey_encoded}");
52}