You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用CryptoPP加载OpenSSH公私钥并转换为对应RSA密钥对象?

如何用CryptoPP加载OpenSSH格式的RSA密钥

你当前的代码无法直接加载OpenSSH密钥,因为CryptoPP的BERDecodePrivateKey仅支持标准PKCS#1/PKCS#8格式的密钥,而OpenSSH采用自定义封装格式,必须先解析提取出标准密钥数据才能加载。

私钥处理步骤

OpenSSH私钥(以-----BEGIN OPENSSH PRIVATE KEY-----开头)的结构是Base64编码的二进制数据,内部包含魔数、加密参数、公钥、私钥等字段。需按以下步骤提取PKCS#1格式的私钥数据:

  • 去掉首尾的标记行与换行符,保留纯Base64字符串
  • 对Base64字符串解码得到二进制数据
  • 解析二进制数据:跳过开头的"openssh-key-v1"魔数,依次读取加密算法、加密参数、公钥数据,最终提取出私钥字段(PKCS#1格式的DER编码)
  • 用BERDecodePrivateKey加载提取出的私钥数据

示例代码(针对无密码保护的私钥):

#include <cryptopp/files.h>
#include <cryptopp/rsa.h>
#include <cryptopp/base64.h>
#include <cryptopp/filters.h>
#include <cryptopp/endian.h>
#include <string>
#include <fstream>

using namespace CryptoPP;

// 从OpenSSH私钥文件提取PKCS#1私钥数据
std::string ExtractOpenSSHPrivateKeyData(const std::string& filePath) {
    std::ifstream file(filePath);
    std::string line, base64Data;
    bool inKey = false;

    // 过滤并读取Base64内容
    while (std::getline(file, line)) {
        if (line == "-----BEGIN OPENSSH PRIVATE KEY-----") {
            inKey = true;
            continue;
        }
        if (line == "-----END OPENSSH PRIVATE KEY-----") {
            inKey = false;
            break;
        }
        if (inKey) {
            base64Data += line;
        }
    }

    // Base64解码
    std::string binaryData;
    StringSource(base64Data, true, new Base64Decoder(new StringSink(binaryData)));

    // 解析OpenSSH私钥结构
    size_t pos = 0;
    // 跳过魔数 "openssh-key-v1"
    pos += 15;

    // 读取加密算法字段(先4字节大端长度,再内容)
    word32 algLen = BigEndianToNative32(*reinterpret_cast<const word32*>(binaryData.data() + pos));
    pos += 4 + algLen;

    // 跳过加密密钥长度、加密IV长度字段
    pos += 8;
    // 跳过公钥数据字段
    word32 pubKeyLen = BigEndianToNative32(*reinterpret_cast<const word32*>(binaryData.data() + pos));
    pos += 4 + pubKeyLen;

    // 读取私钥数据
    word32 privKeyLen = BigEndianToNative32(*reinterpret_cast<const word32*>(binaryData.data() + pos));
    pos += 4;
    std::string privKeyData(binaryData.data() + pos, privKeyLen);

    return privKeyData;
}

int main(int argc, char* argv[]) {
    try {
        // 提取PKCS#1私钥数据
        std::string privKeyData = ExtractOpenSSHPrivateKeyData("/root/.ssh/id_rsa");

        // 加载到CryptoPP私钥对象
        RSA::PrivateKey privateKey;
        StringSource(privKeyData, true, new BERDecoder(privateKey, &RSA::PrivateKey::BERDecodePrivateKey, false, privKeyData.size()));

        // 导出标准格式公钥(可选)
        RSA::PublicKey publicKey(privateKey);
        FileSink pubSink("/root/.ssh/id_rsa.cryptopp.pub", true);
        publicKey.DEREncode(pubSink);
    } catch (const std::exception& e) {
        std::cerr << e.what() << std::endl;
        return 1;
    }
    return 0;
}

公钥处理步骤

OpenSSH公钥(以ssh-rsa开头)的结构是:算法标识 + Base64编码的公钥数据。解码后的数据包含算法标识、指数(e)、模数(n),需提取这两个参数手动构建CryptoPP公钥:

示例代码:

#include <cryptopp/rsa.h>
#include <cryptopp/base64.h>
#include <cryptopp/filters.h>
#include <cryptopp/endian.h>
#include <string>
#include <fstream>
#include <sstream>

using namespace CryptoPP;

// 从OpenSSH公钥文件加载CryptoPP公钥
RSA::PublicKey LoadOpenSSHPublicKey(const std::string& filePath) {
    std::ifstream file(filePath);
    std::string line;
    std::getline(file, line);

    // 拆分算法标识与Base64数据
    std::istringstream iss(line);
    std::string alg, base64Data;
    iss >> alg >> base64Data;

    // Base64解码
    std::string binaryData;
    StringSource(base64Data, true, new Base64Decoder(new StringSink(binaryData)));

    size_t pos = 0;
    // 跳过算法标识字段
    word32 algLen = BigEndianToNative32(*reinterpret_cast<const word32*>(binaryData.data() + pos));
    pos += 4 + algLen;

    // 读取指数
    word32 eLen = BigEndianToNative32(*reinterpret_cast<const word32*>(binaryData.data() + pos));
    pos += 4;
    Integer e(reinterpret_cast<const byte*>(binaryData.data() + pos), eLen);
    pos += eLen;

    // 读取模数
    word32 nLen = BigEndianToNative32(*reinterpret_cast<const word32*>(binaryData.data() + pos));
    pos += 4;
    Integer n(reinterpret_cast<const byte*>(binaryData.data() + pos), nLen);

    // 构建公钥
    RSA::PublicKey publicKey;
    publicKey.Initialize(n, e);
    return publicKey;
}

int main(int argc, char* argv[]) {
    try {
        RSA::PublicKey publicKey = LoadOpenSSHPublicKey("/root/.ssh/id_rsa.pub");
        // 此处可添加加密/验证逻辑
    } catch (const std::exception& e) {
        std::cerr << e.what() << std::endl;
        return 1;
    }
    return 0;
}

注意事项

  • 若私钥带密码保护,需先根据加密算法(如AES)和参数用密码解密私钥字段
  • 上述代码仅适配RSA密钥,其他密钥类型(如ED25519)需调整解析逻辑

内容的提问来源于stack exchange,提问作者Richard

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 23:52:11