2

如何将 RSA 公钥从 XML 转换为 PEM (PHP)?

4

6 回答 6

11

我假设 XML 格式是指XML DSig RSAKeyValue,而 PEM 格式是指 OpenSSL 在-----BEGIN PUBLIC KEY-----和之间导出的内容-----END PUBLIC KEY-----

您首先需要从 XML 中提取模数和公共指数。

   <RSAKeyValue>
     <Modulus>xA7SEU+e0yQH5rm9kbCDN9o3aPIo7HbP7tX6WOocLZAtNfyxSZDU16ksL6W
      jubafOqNEpcwR3RdFsT7bCqnXPBe5ELh5u4VEy19MzxkXRgrMvavzyBpVRgBUwUlV
      5foK5hhmbktQhyNdy/6LpQRhDUDsTvK+g9Ucj47es9AQJ3U=
     </Modulus>
     <Exponent>AQAB</Exponent>
   </RSAKeyValue>

您可以使用base64_decode.

完成此操作后,您需要以某种方式构建ASN.1公钥结构。

OpenSSL 在 BEGIN/END PUBLIC KEY 之间导出的是X.509 SubjectPublicKeyInfo 结构

SubjectPublicKeyInfo ::= SEQUENCE {
   algorithm AlgorithmIdentifier,
   subjectPublicKey BIT STRING }

PKCS#1 规范subjectPublicKey中描述的序列组成:

RSAPublicKey ::= SEQUENCE {
   modulus INTEGER,
   publicExponent INTEGER
}

( algorithman AlgorithmIdentifier) 在 PKCS#1 规范中也有描述(参见 A.1 节):

rsaEncryption
OBJECT IDENTIFIER ::= { pkcs-1 1 }

此结构需要以 DER 形式序列化,然后进行 base64 编码,然后放置在 BEGIN/END 分隔符之间。

不幸的是,我不知道有任何 PHP 库可以进行 ASN.1/DER 编码(其余的相对容易,但处理 ASN.1 往往很乏味)。

PHP/PEAR Crypt_RSA 模块可以从模数和指数构造 RSA 公钥,但是它的toString()方法使用自定义格式(只是 PHP 的结果serialize在数组结构上的 base64 编码,与 ASN.1/ 无关DER 编码)。

于 2010-08-26T14:12:48.830 回答
5

我们知道

.pem -(隐私增强邮件)Base64 编码的 DER 证书,包含在“-----BEGIN CERTIFICATE-----”和“-----END CERTIFICATE-----”之间

X.509

SignatureValue 元素包含应用CanonicalizationMethod 指定的算法后SignedInfo 元素的Base64 编码签名结果——使用SignatureMethod 元素中指定的参数生成的签名。

XML_Signature

所以我们最终得到

$xml = simplexml_load_file($xmlFile); // or simplexml_load_string

$pem = "-----BEGIN CERTIFICATE-----\n";
$pem .= $xml->SignatureValue;
$pem .= "\n-----END CERTIFICATE-----";

// save to file

如果您的 xml 文件不是 XML_Signature

$xml = simplexml_load_file($xmlFile); // or simplexml_load_string
$pem = "-----BEGIN CERTIFICATE-----\n";
$pem .= $xml->nodeWithWantedValue; // use base64_encode if needed
$pem .= "\n-----END CERTIFICATE-----";
于 2010-08-25T16:34:30.667 回答
1

下面是一个如何在 PHP 中读取 XML RSA 密钥的示例:

于 2010-10-02T17:24:26.080 回答
0

为了完整起见,这里是一个从 python 中的模数创建 PEM 的工作示例。如有必要,您可以在 PHP 的子进程中调用它。

解决方案的要点是:

def big_endian(n):
    s = '%x' % n
    if len(s) & 1:
        s = '0' + s
    return s.decode('hex')

from M2Crypto import RSA

e = E_PREFIX + big_endian(public_exponent)
n = N_PREFIX + big_endian(modulus)

new = RSA.new_pub_key((e,n))
new.save_key('foo.pub')

WhereE_PREFIXN_PREFIX是常量(据我所知)取决于指数和密钥长度。这是我构建的一个快速表:

E_PREFIX = '\x00\x00\x00\x01' # 0x3 (3)
E_PREFIX = '\x00\x00\x00\x03' # 0x10001 (65537)

N_PREFIX = '\x00\x00\x00!\x00' # 256-bit
N_PREFIX = '\x00\x00\x00A\x00' # 512-bit (default)
N_PREFIX = '\x00\x00\x00\x81\x00' # 1024-bit
N_PREFIX = '\x00\x00\x01\x01\x00' # 2048-bit
N_PREFIX = '\x00\x00\x02\x01\x00' # 4096-bit

如果有人知道计算前缀的更通用方法,请告诉。

于 2010-11-20T10:33:13.160 回答
0

没有在 XML 中存储 RSA 公钥的标准。因此转换方式将取决于您拥有的 XML。

于 2010-08-25T16:18:55.943 回答
-1

也许你应该看看这里

提取两个base64编码的字符串,转换并传递给PEAR::Crypt_RSA,然后导出为文本文件,然后openssl转换?

也检查一下

于 2010-08-25T16:30:53.893 回答