【问题标题】:Convert RSA public key, from XML to PEM (PHP)将 RSA 公钥从 XML 转换为 PEM (PHP)
【发布时间】:2011-04-03 20:07:49
【问题描述】:

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

【问题讨论】:

标签: php xml rsa public-key pem


【解决方案1】:

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

【讨论】:

【解决方案2】:

也许你应该看看here

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

Check this too

【讨论】:

    【解决方案3】:

    我们知道

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

    X.509

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

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

    【讨论】:

    • 也许是变量名具有误导性,但签名值和证书(您放在 BEGIN/END CERTIFICATE 之间)是两个不同的东西。此外,最初的问题是关于公钥,而不是证书。在 XML 签名规范中,公钥分为模数和指数。
    • 因为我们没有关于神秘 xml 的任何信息……以它为例。将修改代码以更清楚地反映这一点
    • 当然可以,但是如果是 RSAKeyValue XML DSig 格式,您仍然需要重构 ASN.1 结构并重新编码为 base-64,然后再将其置于 BEGIN/END PUBLIC KEY 之间。这不仅仅是从 XML 中提取文本的问题。 @mario 的指点会有所帮助。
    • 如果没有明确的定义,我总是尝试“简单地思考”。但当然是你的权利。
    【解决方案4】:

    我假设 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 structure

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

    subjectPublicKeyPKCS#1 spec中描述的序列组成:

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

    algorithmAlgorithmIdentifier)也在 PKCS#1 规范中进行了描述(参见 A.1 节):

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

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

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

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

    【讨论】:

      【解决方案5】:

      这里有一个example 如何在 PHP 中读取 XML RSA 密钥:

      【讨论】:

        【解决方案6】:

        为了完整起见,这里是一个在 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
        

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-11-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-03-06
          • 2012-02-23
          • 2015-10-19
          • 2011-03-10
          相关资源
          最近更新 更多