Как преобразовать ключ XML RSA в файл PEM?
У меня есть два 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>
Я использую xmlseclibs
Библиотека Роберта Ричардса, для которой требуется шифрование.PEM для шифрования и дешифрования.
Как новичок в шифровании, я не уверен, с чего начать, и беглый поиск в Google не выявил ничего особенно очевидного...
Спасибо!
7 ответов
Для тех, кто хочет, чтобы полученный PEM был читаемым BouncyCastle:
- используйте инструмент XMLSec2PEM для получения файла pem
- конвертировать pem в pkcs8 и обратно (!)
Окончательное решение, которым я доволен:
java XMLSec2PEM my.xml > my.pem
- редактировать
my.pem
немного вручную org.bouncycastle.openssl.PEMReader.readObject()
возвращаетсяnull
:-(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
- сейчас
my.pkcs8.pem
читается сPEMReader
мое решение в python работает так:
- извлечь модуль и показатель степени из xml
xml = etree.fromstring(key_bin) modulus = xml.find('Modulus').text exponent = xml.find('Exponent').text
- декодируйте их в base64 и повторите результат, чтобы сохранить его как строку символов длины 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])
- Преобразуйте шестнадцатеричную строку в целое число и сгенерируйте открытый ключ rsa с помощью библиотеки rsa:
exp_num = int(exp, 16) mod_num = int(mod, 16) rsa_key = rsa.PublicKey(mod_num, exp_num)
- Наконец, любой текст можно зашифровать:
msg_cryp = rsa.encrypt(msg.encode('ascii'), rsa_key) msg_cryp_str = b64encode(msg_cryp).decode('ascii')
Я сделал эту разработку, чтобы использовать веб-службу, которая требует отправки зашифрованного пароля из открытого ключа в формате XML. Таким образом мне удалось зашифровать пароль и без проблем использовать веб-сервис.
Вот скрипт версии ruby для преобразования RSA в pem и наоборот.
Убедитесь, что Ruby установлен.
запустите irb в своем терминале
> irb
Вставьте следующий код в консоль 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
пэм -> xml
Вот пример преобразования PEM в 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 -> пэм
Вот пример преобразования xml в 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
Ссылка
Поскольку 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, если параметры не предоставлены. Больше информации:
Я часами искал точно такую же проблему. Этот инструмент Java сделал свою работу:)
Но ссылка изменилась, теперь она доступна здесь
Нашел этот полезный онлайн-инструмент RSA Key Converter, который поддерживает
- XML -> PEM
- PEM -> XML