如何将XML RSA密钥转换为PEM文件?

15

我有两个XML文件,结构如下:

我的键

<RSAKeyValue>
  <Modulus> ... </Modulus>
  <Exponent> ... </Exponent>
  <P> ... </P>
  <Q> ... </Q>
  <DP> ... </DP>
  <DQ> ... </DQ>
  <InverseQ> ... </InverseQ>
  <D> ... </D>
</RSAKeyValue>

公钥

<RSAKeyValue>
   <Modulus> ... </Modulus>
   <Exponent> ... </Exponent>
</RSAKeyValue>

我正在使用由Robert Richards编写的xmlseclibs库,该库需要密钥的.PEM表示才能加密和解密内容。

作为一个加密新手,我不知道从哪里开始,而简单的谷歌搜索也没有发现任何特别明显的东西……

谢谢!


看起来xmlseclibs有一个方法XMLSecurityKey::convertRSA,它接受模数和指数,并将创建一个与PEM兼容的公钥。然而,它似乎没有任何方法来创建必要的私钥。对此有什么帮助吗? - Philip
我相信关键的格式/展示来自RFC 3275,XML签名语法和处理 - jww
7个回答

10

2
对于那些希望生成 PEM 文件能被 BouncyCastle 读取的人:
  1. 使用 XMLSec2PEM 工具获取 pem 文件
  2. 将 pem 转换为 pkcs8 格式,再转换回来!
最终我满意的解决方案是:
  1. java XMLSec2PEM my.xml > my.pem
  2. 手动编辑一下 my.pem
  3. org.bouncycastle.openssl.PEMReader.readObject() 返回 null :-(
  4. openssl pkcs8 -topk8 -inform pem -in my.pem -outform pem -nocrypt -out my.pkcs8
  5. openssl pkcs8 -inform pem -nocrypt -in my.pkcs8 -out my.pkcs8.pem
  6. 现在 my.pkcs8.pem 可以被 PEMReader读取了

1

我的Python解决方案的工作原理如下:

  1. extract modulus and exponent from xml
    xml = etree.fromstring(key_bin)
    modulus = xml.find('Modulus').text
    exponent = xml.find('Exponent').text
    
  2. decode them in base64 and iterate the result to save it as a character string of length 2:
    mod_b64 = b64decode(modulus.encode())
    exp_b64 = b64decode(exponent.encode())
    exp = ''.join(['{:02x}'.format(x) for x in exp_b64])
    mod = ''.join(['{:02x}'.format(x) for x in mod_b64]) 
    
  3. Convert the hexadecimal string to integer and generate the rsa public key with the rsa library:
    exp_num = int(exp, 16)
    mod_num = int(mod, 16)
    rsa_key = rsa.PublicKey(mod_num, exp_num)
    
  4. Finally any text can be encrypted:
    msg_cryp = rsa.encrypt(msg.encode('ascii'), rsa_key)
    msg_cryp_str = b64encode(msg_cryp).decode('ascii') 
    
我开发了这个功能来调用一个需要使用XML格式的公钥发送加密密码的Web服务。通过这种方式,我成功地加密了密码并顺利地调用了Web服务。

0

这里是一个 Ruby 版本的脚本,用于将 RSA 转换为 pem,反之亦然。

  1. 确保已安装Ruby。

  2. 在终端中启动irb

    > irb
    
  3. 将以下代码粘贴到irb控制台中。

    require 'openssl'
    require 'base64'
    require 'rexml/document'
    
    class PKeyRSAConverter
      def initialize(from_pem:nil, from_xml:nil)
        @from_pem = from_pem
        @from_xml = from_xml
      end
    
      def to_xml
        xml  = '<RSAKeyValue>'
        xml += "<Modulus>#{xml_base64(xml_pkey.n)}</Modulus>"
        xml += "<Exponent>#{xml_base64(xml_pkey.e)}</Exponent>"
        xml += '</RSAKeyValue>'
        xml
      end
    
      def to_pem
        pem_key.to_pem
      end
    
      private
    
      def pem_key
        exponent = xml_find_exponent.to_s
        modulus = xml_find_modulus.to_s
        key = OpenSSL::PKey::RSA.new
        key.set_key(pem_base64(modulus), pem_base64(exponent), nil)
        key
      end
    
      def xml_find_modulus
        REXML::XPath.match(xml_document.root, "//RSAKeyValue/Modulus/text()")[0]
      end
    
      def xml_find_exponent
        REXML::XPath.match(xml_document.root, "//RSAKeyValue/Exponent/text()")[0]
      end
    
      def xml_document
        @xml_document ||= REXML::Document.new(@from_xml.to_s)
      end
    
      def pem_base64(string)
        Base64.urlsafe_decode64(string).bytes.inject(0){|a,e| (a << 8)| e }
      end
    
      def xml_pkey
        @xml_pkey ||= OpenSSL::PKey::RSA.new(@from_pem)
      end
    
      def xml_base64(int)
        Base64.encode64([int.to_s(16).downcase].pack('H*')).split("\n").join
      end
    end
    
  4. pem -> xml

    这里是将PEM转换为xml的示例

    rsa_pem="-----BEGIN PUBLIC KEY-----\nMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJYOlB8N/EdJL9nqEsRNF+No/9QkmPaX\n/xxpPleZTTNgakTkUlmyZPud8eEGsaX7nLgoVF39zTrXeg4hIeaWsAsCAwEAAQ==\n-----END     PUBLIC KEY-----\n"
    
    puts '将PEM转换为XML'
    to_xml = PKeyRSAConverter.new(from_pem: rsa_pem).to_xml
    puts to_xml == rsa_xml
    
  5. xml -> pem

    这里是将xml转换为PEM的示例

    rsa_xml="<RSAKeyValue><Modulus>lg6UHw38R0kv2eoSxE0X42j/1CSY9pf/HGk+V5lNM2BqRORSWbJk+53x4QaxpfucuChUXf3NOtd6DiEh5pawCw==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>"
    
    puts '将XML转换为PEM'
    to_pem = PKeyRSAConverter.new(from_xml: rsa_xml).to_pem
    puts rsa_pem == to_pem
    

参考资料

  1. Github Gist:anicet/pkey_rsa_converter.rb

0

由于xmlseclibs是PHP编写的,因此似乎需要另一个PHP解决方案。以下是方法:

<?php
include('Crypt/RSA.php');

$rsa = new Crypt_RSA();
$rsa->loadKey('<RSAKeyValue>
  <Modulus> ... </Modulus>
  <Exponent> ... </Exponent>
  <P> ... </P>
  <Q> ... </Q>
  <DP> ... </DP>
  <DQ> ... </DQ>
  <InverseQ> ... </InverseQ>
  <D> ... </D>
</RSAKeyValue>');

$privatekey = $rsa->getPrivateKey();
$publickey = $rsa->getPublicKey();
?>

phpseclib内置支持XML密钥、PuTTY密钥和PKCS1密钥。它会自动检测格式并加载,如果没有提供参数,则getPrivateKey / getPublicKey将默认输出PKCS1格式的密钥。更多信息:

http://phpseclib.sourceforge.net/rsa/examples.html#convert


0
我花了几个小时搜索完全相同的问题。这个Java工具解决了我的问题 :)
但是链接已经更改,现在可以从这里获取。

1
链接已损坏。 - Parag Bafna

-2

20
不要使用在线工具处理这类敏感信息。 - Torge
1
它只能用于公钥。 - Ofigenn
1
它可以用于公开已知的私钥,也可用于演示。 - Henry Story

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接