Как преобразовать ключ 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 ответов

Решение

Я нашел утилиту Java, которая может это сделать.

Для тех, кто хочет, чтобы полученный 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

мое решение в python работает так:

  1. извлечь модуль и показатель степени из xml
            xml = etree.fromstring(key_bin)
    modulus = xml.find('Modulus').text
    exponent = xml.find('Exponent').text
    
  2. декодируйте их в 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]) 
    
  3. Преобразуйте шестнадцатеричную строку в целое число и сгенерируйте открытый ключ rsa с помощью библиотеки rsa:
            exp_num = int(exp, 16)
    mod_num = int(mod, 16)
    rsa_key = rsa.PublicKey(mod_num, exp_num)
    
  4. Наконец, любой текст можно зашифровать:
            msg_cryp = rsa.encrypt(msg.encode('ascii'), rsa_key)
    msg_cryp_str = b64encode(msg_cryp).decode('ascii') 
    

Я сделал эту разработку, чтобы использовать веб-службу, которая требует отправки зашифрованного пароля из открытого ключа в формате XML. Таким образом мне удалось зашифровать пароль и без проблем использовать веб-сервис.

Вот скрипт версии 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. пэм -> 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
    
  5. 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
    

Ссылка

  1. Github Gist: anicet/pkey_rsa_converter.rb

Поскольку 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

Я часами искал точно такую ​​же проблему. Этот инструмент Java сделал свою работу:)

Но ссылка изменилась, теперь она доступна здесь

Нашел этот полезный онлайн-инструмент RSA Key Converter, который поддерживает

  • XML -> PEM
  • PEM -> XML
Другие вопросы по тегам