How do I convert an XML RSA key to a PEM file?
I have two XML files, structured as follows:
My Key
<RSAKeyValue>
<Modulus> ... </Modulus>
<Exponent> ... </Exponent>
<P> ... </P>
<Q> ... </Q>
<DP> ... </DP>
<DQ> ... </DQ>
<InverseQ> ... </InverseQ>
<D> ... </D>
</RSAKeyValue>
A Public Key
<RSAKeyValue>
<Modulus> ... </Modulus>
<Exponent> ... </Exponent>
</RSAKeyValue>
I am using the xmlseclibs
library by Robert Richards which requi开发者_如何学Cres a .PEM representation of the key in order to encrypt and decrypt things.
As an encryption novice, I'm not sure where to begin, and a cursory Google search did not reveal anything particularly obvious...
Thanks!
I have found a Java utility that can do it.
For those who want the resulting PEM to be readable by BouncyCastle:
- use XMLSec2PEM tool to get a pem file
- convert pem to pkcs8 and back (!)
The final solution I am happy with:
java XMLSec2PEM my.xml > my.pem
- edit
my.pem
manually a bit org.bouncycastle.openssl.PEMReader.readObject()
returnsnull
:-(openssl pkcs8 -topk8 -inform pem -in my.pem -outform pem -nocrypt -out my.pkcs8
openssl pkcs8 -inform pem -nocrypt -in my.pkcs8 -out my.pkcs8.pem
- now
my.pkcs8.pem
is readable with thePEMReader
my solution in python works like this:
- extract modulus and exponent from xml
xml = etree.fromstring(key_bin) modulus = xml.find('Modulus').text exponent = xml.find('Exponent').text
- 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])
- 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)
- Finally any text can be encrypted:
msg_cryp = rsa.encrypt(msg.encode('ascii'), rsa_key) msg_cryp_str = b64encode(msg_cryp).decode('ascii')
I did this development to consume a web service which requires that an encrypted password be sent from a public key in XML format. In this way I managed to encrypt the password and consume the web service without problems.
I was searching for hours for exactly the same problem. This Java tool did the job :)
But the link has changed, it is now available from here
Since xmlseclibs is PHP it seems like another PHP solution might be desirable. Here's how:
<?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 has built in support for XML keys, PuTTY keys and PKCS1 keys. It'll auto detect the format and load it and getPrivateKey / getPublicKey will output PKCS1 formatted keys by default if no parameters are provided. More info:
http://phpseclib.sourceforge.net/rsa/examples.html#convert
Here is a ruby version script to convert RSA to pem, vice versa.
Make sure Ruby has been installed.
start irb in your terminal
> irb
Paste the following code to the irb console.
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
pem -> xml
Here is an example to convert PEM to xml
rsa_pem="-----BEGIN PUBLIC KEY-----\nMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJYOlB8N/EdJL9nqEsRNF+No/9QkmPaX\n/xxpPleZTTNgakTkUlmyZPud8eEGsaX7nLgoVF39zTrXeg4hIeaWsAsCAwEAAQ==\n-----END PUBLIC KEY-----\n" puts 'Convert PEM to XML' to_xml = PKeyRSAConverter.new(from_pem: rsa_pem).to_xml puts to_xml == rsa_xml
xml -> pem
Here is an example to convert xml to PEM
rsa_xml="<RSAKeyValue><Modulus>lg6UHw38R0kv2eoSxE0X42j/1CSY9pf/HGk+V5lNM2BqRORSWbJk+53x4QaxpfucuChUXf3NOtd6DiEh5pawCw==</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>" puts 'Convert XML to PEM' to_pem = PKeyRSAConverter.new(from_xml: rsa_xml).to_pem puts rsa_pem == to_pem
Reference
- Github Gist: anicet/pkey_rsa_converter.rb
Found this useful online tool RSA Key Converter, which supports
- XML -> PEM
- PEM -> XML
精彩评论