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

时间:2010-08-25 16:16:32

标签: php xml rsa public-key pem

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

6 个答案:

答案 0 :(得分:10)

我假设按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公钥结构。

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

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

subjectPublicKey中描述了RSAPublicKey ::= SEQUENCE { modulus INTEGER, publicExponent INTEGER } PKCS#1 spec描述的

algorithm

PKCS#1规范中也描述了AlgorithmIdentifierrsaEncryption OBJECT IDENTIFIER ::= { pkcs-1 1 } )(参见A.1节):

toString()

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

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

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

答案 1 :(得分:5)

我们知道

  

.pem - (隐私增强邮件)Base64   封闭的编码DER证书   在“-----开始证书-----”之间   和“-----结束证书-----”

X.509

  

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

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-----";

答案 2 :(得分:1)

在XML中存储RSA公钥没有标准。所以转换的方式取决于你拥有的XML。

答案 3 :(得分:1)

以下是如何在PHP中读取XML RSA密钥的example

答案 4 :(得分: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')

其中E_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

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

答案 5 :(得分:-1)

也许你应该看看here

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

Check this too