Rust SSH密钥解析与生成库openssh-keys的使用:支持OpenSSH格式密钥的读取、验证和转换

Rust SSH密钥解析与生成库openssh-keys的使用:支持OpenSSH格式密钥的读取、验证和转换

openssh-keys是一个纯Rust库,用于处理OpenSSH公钥。它可以解析、打印和生成OpenSSH公钥的指纹。支持以下算法:

  • RSA
  • DSA
  • ECDSA (nistp256, nistp384, nistp521)
  • ED25519

可以使用PublicKey::from_rsa()PublicKey::from_dsa()函数分别从RSA和DSA的组件构造密钥。

示例

以下是内容中提供的示例代码:

extern crate openssh_keys;

use std::{env, fs, io, path};
use std::io::BufRead;

fn main() {
    let home = env::home_dir().unwrap_or(path::PathBuf::from("/home/core/"));
    let pub_path = home.join(".ssh").join("id_rsa.pub");
    println!("Inspecting '{}':", pub_path.to_string_lossy());
    let file = fs::File::open(&pub_path).expect("unable to open RSA pubkey");
    let reader = io::BufReader::new(file);
    
    for (i, line) in reader.lines().enumerate() {
        let line = line.expect(&format!("unable to read key at line {}", i + 1));
        let pubkey = openssh_keys::PublicKey::parse(&line).expect("unable to parse RSA pubkey");
        println!(" * Pubkey #{} -> {}", i + 1, pubkey.to_fingerprint_string());
    }
}

完整示例

下面是一个更完整的示例,展示如何生成、读取、解析和验证SSH密钥:

use openssh_keys;
use openssl::rsa::Rsa;
use std::{fs, path::PathBuf};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 1. 生成新的RSA密钥对
    let rsa_key = Rsa::generate(2048)?;
    let n = rsa_key.n().to_vec();  // 模数
    let e = rsa_key.e().to_vec();  // 公开指数
    
    // 2. 从组件创建PublicKey
    let new_pubkey = openssh_keys::PublicKey::from_rsa(n, e)
        .expect("Failed to create RSA key");
    
    // 3. 保存公钥到文件
    let pubkey_path = PathBuf::from("test_key.pub");
    fs::write(&pubkey_path, new_pubkey.to_string())?;
    
    // 4. 读取并解析公钥文件
    let pubkey_content = fs::read_to_string(&pubkey_path)?;
    let parsed_pubkey = openssh_keys::PublicKey::parse(&pubkey_content)?;
    
    // 5. 打印密钥信息
    println!("Key type: {:?}", parsed_pubkey.key_type());
    println!("Fingerprint: {}", parsed_pubkey.to_fingerprint_string());
    println!("Comment: {}", parsed_pubkey.comment());
    
    // 6. 验证密钥是否匹配
    if parsed_pubkey.verify(&new_pubkey) {
        println!("Keys match!");
    } else {
        println!("Keys do not match!");
    }
    
    Ok(())
}

许可证

openssh-keys采用双重许可:

  • Apache License, Version 2.0
  • MIT license

您可以选择其中任意一种。

贡献

除非您明确声明,否则任何故意提交用于包含在此工作中的贡献,如Apache-2.0许可证中所定义,应按照上述双重许可,无需任何附加条款或条件。


1 回复

Rust SSH密钥解析与生成库openssh-keys使用指南

简介

openssh-keys是一个Rust库,用于处理OpenSSH格式的SSH密钥。它支持密钥的读取、验证、生成和转换操作,可以处理RSA、DSA、ECDSA和Ed25519等类型的密钥。

主要功能

  • 解析OpenSSH格式的私钥和公钥
  • 验证密钥的有效性
  • 生成新的SSH密钥对
  • 在不同格式间转换密钥
  • 支持加密的私钥

安装

在Cargo.toml中添加依赖:

[dependencies]
openssh-keys = "0.5"

基本使用方法

1. 解析SSH公钥

use openssh_keys::PublicKey;

// 示例公钥字符串
let pubkey_str = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQ... user@example.com";
// 解析公钥
let pubkey = PublicKey::parse(pubkey_str).unwrap();

// 打印密钥类型和注释
println!("Key type: {}", pubkey.keytype());
println!("Comment: {}", pubkey.comment());

2. 解析SSH私钥

use openssh_keys::PrivateKey;

// 示例私钥字符串
let privkey_str = r#"-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAlwAAAAdzc2gtcn
...
-----END OPENSSH PRIVATE KEY-----"#;

// 解析私钥
let privkey = PrivateKey::from_string(privkey_str).unwrap();
println!("Key type: {}", privkey.key_type());

3. 生成新的密钥对

use openssh_keys::{KeyPair, KeyType};

// 生成2048位RSA密钥对
let keypair = KeyPair::generate(KeyType::Rsa, 2048).unwrap();

// 获取并打印公钥
let pubkey_str = keypair.public_key().to_string();
println!("Public key:\n{}", pubkey_str);

// 获取并打印私钥 
let privkey_str = keypair.private_key().to_string();
println!("Private key:\n{}", privkey_str);

4. 加密私钥

use openssh_keys::{KeyPair, KeyType, Cipher};

// 生成Ed25519密钥对
let keypair = KeyPair::generate(KeyType::Ed25519, 0).unwrap();

// 使用AES-256-CBC和密码加密私钥
let encrypted_privkey = keypair.private_key().encrypt(
    Cipher::Aes256Cbc,
    "my-strong-password"
).unwrap();

println!("Encrypted private key:\n{}", encrypted_privkey);

5. 验证密钥对匹配

use openssh_keys::{PublicKey, PrivateKey};

// 示例公钥和私钥
let pubkey = PublicKey::parse("ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI...").unwrap();
let privkey = PrivateKey::from_string("-----BEGIN OPENSSH PRIVATE KEY-----\n...").unwrap();

// 验证密钥是否匹配
if privkey.matches(&pubkey) {
    println!("密钥匹配成功!");
} else {
    println!("密钥不匹配!");
}

高级用法

转换密钥格式

use openssh_keys::PrivateKey;
use openssh_keys::pkcs8::ToPkcs8;

// 解析OpenSSH格式私钥
let privkey = PrivateKey::from_string("-----BEGIN OPENSSH PRIVATE KEY-----\n...").unwrap();

// 转换为PKCS#8 DER格式
let pkcs8_der = privkey.to_pkcs8().unwrap();
println!("PKCS#8 DER length: {} bytes", pkcs8_der.len());

从现有密钥材料创建密钥

use openssh_keys::{PrivateKey, PublicKey};
use openssh_keys::ed25519::Ed25519Keypair;
use rand::rngs::OsRng;

// 生成Ed25519密钥材料
let mut csprng = OsRng;
let keypair = Ed25519Keypair::generate(&mut csprng);

// 创建OpenSSH格式的私钥和公钥
let privkey = PrivateKey::from_ed25519(keypair.clone()).unwrap();
let pubkey = PublicKey::from_ed25519(keypair.public).unwrap();

println!("Generated private key:\n{}", privkey.to_string());
println!("Generated public key: {}", pubkey.to_string());

完整示例

下面是一个完整的示例,展示如何生成密钥对、加密私钥并验证匹配:

use openssh_keys::{KeyPair, KeyType, Cipher, PublicKey, PrivateKey};

fn main() {
    // 1. 生成RSA密钥对
    let keypair = KeyPair::generate(KeyType::Rsa, 2048).unwrap();
    
    // 2. 获取公钥和私钥
    let pubkey_str = keypair.public_key().to_string();
    let privkey_str = keypair.private_key().to_string();
    
    println!("Generated RSA Key Pair:");
    println!("Public Key:\n{}", pubkey_str);
    println!("Private Key:\n{}", privkey_str);
    
    // 3. 加密私钥
    let encrypted_privkey = keypair.private_key()
        .encrypt(Cipher::Aes256Cbc, "secure-password-123")
        .unwrap();
    
    println!("\nEncrypted Private Key:");
    println!("{}", encrypted_privkey);
    
    // 4. 验证密钥匹配
    let parsed_pubkey = PublicKey::parse(&pubkey_str).unwrap();
    let parsed_privkey = PrivateKey::from_string(&privkey_str).unwrap();
    
    if parsed_privkey.matches(&parsed_pubkey) {
        println!("\n验证结果: 密钥对匹配成功");
    } else {
        println!("\n验证结果: 密钥对不匹配");
    }
    
    // 5. 尝试解析加密的私钥(应该失败,因为需要密码)
    match PrivateKey::from_string(&encrypted_privkey) {
        Ok(_) => println!("错误: 无需密码就解析了加密私钥"),
        Err(e) => println!("正确: 解析加密私钥需要密码:\n{}", e),
    }
}

注意事项

  1. 私钥是非常敏感的信息,务必妥善保管,避免泄露
  2. 加密私钥时,务必使用强密码
  3. RSA密钥长度至少应为2048位以确保安全
  4. 该库主要支持OpenSSH格式,对其他格式的密钥支持有限

错误处理

use openssh_keys::PublicKey;

let invalid_key = "invalid-key-string";
match PublicKey::parse(invalid_key) {
    Ok(key) => println!("成功解析: {}", key),
    Err(e) => eprintln!("解析失败: {}", e),
}
回到顶部