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

如何将C++生成的RSA密钥转换为PEM格式在PHP中使用?

解决RSA密钥格式互转问题:C++ HEX ↔ OpenSSL PEM

一、将C++生成的HEX格式RSA私钥转为PEM格式

你的核心问题是ASN.1整数编码规则不匹配:OpenSSL遵循PKCS#1标准,要求所有整数参数(N、p、q等)以无符号形式编码,若参数最高位字节≥0x80,必须前置0x00字节避免被解析为负数。这就是你看到OpenSSL生成的N是257字节(带00前缀),而自己的是256字节的原因。

具体步骤

  1. 处理单个参数的ASN.1编码
    对每个HEX格式的参数(N、E、D、p、q、dP、dQ、qInv)执行以下操作:

    • 将HEX字符串转为字节数组
    • 检查字节数组的首字节:如果首字节≥0x80,在数组开头添加0x00
    • 用ASN.1的INTEGER标签(0x02)和长度字段包装这个字节数组
  2. 组装PKCS#1私钥的DER结构
    PKCS#1的RSA私钥是一个ASN.1 SEQUENCE,结构如下:

    RSAPrivateKey ::= SEQUENCE {
        version           INTEGER,  -- 固定为0
        modulus           INTEGER,  -- N
        publicExponent    INTEGER,  -- E
        privateExponent   INTEGER,  -- D
        prime1            INTEGER,  -- p
        prime2            INTEGER,  -- q
        exponent1         INTEGER,  -- dP
        exponent2         INTEGER,  -- dQ
        coefficient       INTEGER   -- qInv
    }
    

    按顺序将所有编码后的参数放入SEQUENCE(标签0x30)中,生成完整的DER编码字节流。

  3. 转换为PEM格式

    • 将DER字节流做Base64编码
    • 在编码前后添加PEM头部/尾部,每64个字符换行:
      -----BEGIN RSA PRIVATE KEY-----
      [Base64编码内容,每64字符换行]
      -----END RSA PRIVATE KEY-----
      

PHP代码示例

function hexToAsn1Integer(string $hex): string {
    $bytes = hex2bin($hex);
    // 检查最高位是否需要补0x00
    if (ord($bytes[0]) >= 0x80) {
        $bytes = "\x00" . $bytes;
    }
    // 生成ASN.1 INTEGER:标签(0x02) + 长度 + 内容
    $len = strlen($bytes);
    $lenBytes = $len < 0x80 ? chr($len) : chr(0x81) . chr($len);
    return "\x02" . $lenBytes . $bytes;
}

function rsaHexToPem(string $nHex, string $eHex, string $dHex, string $pHex, string $qHex, string $dPHex, string $dQHex, string $qInvHex): string {
    // 组装各个ASN.1整数
    $version = hexToAsn1Integer("00"); // PKCS#1版本为0
    $n = hexToAsn1Integer($nHex);
    $e = hexToAsn1Integer($eHex);
    $d = hexToAsn1Integer($dHex);
    $p = hexToAsn1Integer($pHex);
    $q = hexToAsn1Integer($qHex);
    $dP = hexToAsn1Integer($dPHex);
    $dQ = hexToAsn1Integer($dQHex);
    $qInv = hexToAsn1Integer($qInvHex);

    // 组装SEQUENCE
    $sequenceContent = $version . $n . $e . $d . $p . $q . $dP . $dQ . $qInv;
    $seqLen = strlen($sequenceContent);
    $seqLenBytes = $seqLen < 0x80 ? chr($seqLen) : chr(0x81) . chr($seqLen);
    $der = "\x30" . $seqLenBytes . $sequenceContent;

    // 转PEM
    $base64 = base64_encode($der);
    $pemLines = str_split($base64, 64);
    $pem = "-----BEGIN RSA PRIVATE KEY-----\n" . implode("\n", $pemLines) . "\n-----END RSA PRIVATE KEY-----";
    return $pem;
}

// 使用示例:传入你的HEX参数
$pem = rsaHexToPem($yourNHex, $yourEHex, $yourDHex, $yourPHex, $yourQHex, $yourDPHex, $yourDQHex, $yourQInvHex);
file_put_contents("private_key.pem", $pem);

二、从OpenSSL PEM密钥提取HEX格式参数

如果你需要把OpenSSL生成的PEM密钥转成C++可用的HEX参数,只需去掉ASN.1编码的0x00前缀即可。

方法1:命令行提取

使用OpenSSL命令直接解析PEM并输出参数的HEX值:

openssl rsa -in private.pem -text -noout

输出中会显示每个参数的HEX内容,比如:

modulus:
00:ab:cd:...(省略后续字节)
publicExponent: 65537 (0x10001)
privateExponent:
00:ef:gh:...

直接去掉每个参数开头的00:前缀,拼接成完整的HEX字符串即可。

方法2:PHP代码提取

$pem = file_get_contents("private_key.pem");
$key = openssl_pkey_get_private($pem);
$details = openssl_pkey_get_details($key);

// 提取各个参数并转HEX,去掉可能的前置0x00
function derIntegerToHex(string $derInt): string {
    $content = substr($derInt, 2); // 跳过ASN.1标签和长度
    if (ord($content[0]) === 0x00) {
        $content = substr($content, 1);
    }
    return bin2hex($content);
}

$nHex = derIntegerToHex($details['rsa']['n']);
$eHex = derIntegerToHex($details['rsa']['e']);
$dHex = derIntegerToHex($details['rsa']['d']);
$pHex = derIntegerToHex($details['rsa']['p']);
$qHex = derIntegerToHex($details['rsa']['q']);
$dPHex = derIntegerToHex($details['rsa']['dmp1']); // dP对应dmp1
$dQHex = derIntegerToHex($details['rsa']['dmq1']); // dQ对应dmq1
$qInvHex = derIntegerToHex($details['rsa']['iqmp']); // qInv对应iqmp

// 输出或保存这些HEX字符串供C++使用
echo "N: " . $nHex . PHP_EOL;
echo "E: " . $eHex . PHP_EOL;

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 14:20:48