Как мы конвертируем строку из формата PEM в формат DER

Отправьте строку в следующем формате:

-----BEGIN RSA PUBLIC KEY-----
MIGHAoGBANAahj75ZIz9nXqW2H83nGcUao4wNyYZ9Z1kiNTUYQl7ob/RBmDzs5rY
mUahXAg0qyS7+a55eU/csShf5ATGzAXv+DDPcz8HrSTcHMEFpuyYooX6PrIZ07Ma
XtsJ2J4mhlySI5uOZVRDoaFY53MPQx5gud2quDz759IN/0gnDEEVAgED
-----END RSA PUBLIC KEY-----

Как создать объект PublicKey из этой строки? Попробовали ниже удалить верхний и нижний колонтитулы и base64 декодировать буфер

public static PublicKey getFromString(String keystr) throws Exception
  {
  //String S1= asciiToHex(keystr);
   byte[] keyBytes = new sun.misc.BASE64Decoder().decodeBuffer(keystr);
   X509EncodedKeySpec spec =
       new X509EncodedKeySpec(keyBytes);
     KeyFactory kf = KeyFactory.getInstance("RSA");
     return kf.generatePublic(spec);

  }

Это не удается либо из-за недопустимого формата ключа, либо из-за ошибки ниже

java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException: algid parse error, not a sequence
 at sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:188)
 at java.security.KeyFactory.generatePublic(KeyFactory.java:304)
 at PublicKeyReader.getFromString(PublicKeyReader.java:30)
 at Tst.main(Tst.java:36)

Ключ генерируется через API openSSL PEM_write_bio_RSAPublicKey(bio, rsa);


person MSSV    schedule 27.10.2010    source источник
comment
Воспользовались ссылкой. Но не буду конвертировать в формат der.   -  person MSSV    schedule 27.10.2010
comment
Обратите внимание, что то, что вы пытаетесь сделать, на самом деле не является преобразованием в DER. Преобразование в DER — это просто декодирование того, что здесь base64, и вывод его в виде последовательности байтов. Вы пытаетесь расшифровать структуру ASN.1.   -  person Bruno    schedule 03.11.2010


Ответы (3)


при вызове PEM_write_bio_RSAPublicKey в выходные данные PEM кодируются только ключевой модуль и общедоступная экспонента. Однако ожидается, что X509EncodedKeySpec Формат ключа ASN.1:

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

Вы должны использовать функцию PEM_write_bio_PUBKEY, которая кодирует открытый ключ, используя структуру SubjectPublicKeyInfo, которая, как ожидается, X509EncodedKeySpec

Другое возможное решение для декодирования ключа. К сожалению, я не думаю, что это возможно сделать только с помощью стандартного API JDK, но это можно сделать с помощью Bouncycastle библиотека

import org.bouncycastle.asn1.*;
import org.bouncycastle.asn1.x509.RSAPublicKeyStructure;

public static PublicKey getFromString(String keystr) throws Exception
{
  //String S1= asciiToHex(keystr);
   byte[] keyBytes = new sun.misc.BASE64Decoder().decodeBuffer(keystr);
   ASN1InputStream in = new ASN1InputStream(keyBytes);
   DERObject obj = in.readObject();
   RSAPublicKeyStructure pStruct = RSAPublicKeyStructure.getInstance(obj);
   RSAPublicKeySpec spec = new RSAPublicKeySpec(pStrcut.getModulus(), pStruct.getPublicExponent());
   KeyFactory kf = KeyFactory.getInstance("RSA");
   return kf.generatePublic(spec);
}
person Jcs    schedule 27.10.2010
comment
как или где должна быть указана структура SubjectPublicKeyInfo? - person MSSV; 27.10.2010
comment
Ключ клиента получен, поэтому изменить формат невозможно. Можете ли вы предложить какой-либо другой способ загрузки этого ключа и получения подробностей через пример JCE. - person MSSV; 29.10.2010
comment
Не могли бы вы предложить, можно ли использовать открытый ключ, сгенерированный с помощью keypair.getPublic.getEncoded(), с вызовом API openSSL BIO_write и PEM_read_bio_RSAPublicKey - person MSSV; 03.11.2010
comment
Я так не думаю. getEncoded() для PublicKey возвращает закодированный SubjectPublicKeyInfo, а PEM_read_bio_RSAPublicKey ожидает структуру RSAPublicKey PKCS#1 (т. е. только модуль и общедоступную экспоненту: та же структура, что и у ключа, который вы пытались преобразовать). Согласно документации OpenSSL, PEM_read_bio_RSA_PUBKEY может работать. - person Jcs; 03.11.2010
comment
Можете ли вы предложить изменение, которое необходимо внести в генерацию ключа Java, чтобы PEM_read_bio_RSAPublicKey работал? - person MSSV; 03.11.2010
comment
не сможет ничего изменить на стороне клиента, пожалуйста, предложите изменение, которое будет работать с изменением формата ключа в java, пробовали даже с bouncycastle - person MSSV; 03.11.2010
comment
Код не компилируется. ANASSN1InputStream не существует. - person Alain O'Dea; 23.05.2017

PEMReader от BouncyCastle сделает это за вас:

String pemKey = "-----BEGIN RSA PUBLIC KEY-----\n"
            + "MIGHAoGBANAahj75ZIz9nXqW2H83nGcUao4wNyYZ9Z1kiNTUYQl7ob/RBmDzs5rY\n"
            + "mUahXAg0qyS7+a55eU/csShf5ATGzAXv+DDPcz8HrSTcHMEFpuyYooX6PrIZ07Ma\n"
            + "XtsJ2J4mhlySI5uOZVRDoaFY53MPQx5gud2quDz759IN/0gnDEEVAgED\n"
            + "-----END RSA PUBLIC KEY-----\n";
PEMReader pemReader = new PEMReader(new StringReader(pemKey));
RSAPublicKey rsaPubKey = (RSAPublicKey) pemReader.readObject();
System.out.println("Public key: "+rsaPubKey);

(Обратите внимание, что вам может понадобиться Security.addProvider(new BouncyCastleProvider()); где-то раньше.)

person Bruno    schedule 03.11.2010
comment
Я делаю это в андроиде. Я не могу импортировать PEMReader. Добавлена ​​компиляция 'org.bouncycastle:bcprov-jdk15on:1.56' в зависимость. - person madhuri H R; 09.08.2018
comment
@madhuriHR: BouncyCastle провела рефакторинг некоторых своих архитектур между 1.47 и 1.50 (2012-2013), и теперь эта функциональность разделена между PEMParser и JcaPEMKeyConverter - см. stackoverflow.com/questions/41421154/ или ответ Алена ODea ( включая мой комментарий). - person dave_thompson_085; 29.12.2018

ОБНОВЛЕНИЕ: значительно упрощены процесс и код благодаря @dave_thompson_085

Вы можете создать объект PublicKey из предоставленной строки следующим образом:

  1. Чтение информации об открытом ключе субъекта (SPKI) из двоичного DER (с использованием PEMParser Bouncy Castle)
  2. Подача SPKI в преобразователь для получения PublicKey (работает JcaPEMKeyConverter от Bouncy's Castle)

Предварительные требования для моего решения:

  1. Java 7+ (или вам нужно будет вручную развернуть попытку с ресурсами)
  2. Bouncy Castle bcprov-jdk15 в версии 1.51 или более поздней (НЕ работает в версии 1.50 или более ранней, не компилируется в версии 1.47 или более ранней)

Полный рабочий пример Java 7+:

import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;

import java.io.IOException;
import java.io.StringReader;
import java.security.PublicKey;

public interface PemToDer
{
    static void main(String[] args) throws IOException {
        createRsaPublicKey(
                "-----BEGIN RSA PUBLIC KEY-----\n" +
                "MIGHAoGBANAahj75ZIz9nXqW2H83nGcUao4wNyYZ9Z1kiNTUYQl7ob/RBmDzs5rY\n" +
                "mUahXAg0qyS7+a55eU/csShf5ATGzAXv+DDPcz8HrSTcHMEFpuyYooX6PrIZ07Ma\n" +
                "XtsJ2J4mhlySI5uOZVRDoaFY53MPQx5gud2quDz759IN/0gnDEEVAgED\n" +
                "-----END RSA PUBLIC KEY-----"
        );
    }

    static PublicKey createRsaPublicKey(String keystr) throws IOException {
        try (StringReader reader = new StringReader(keystr);
             PEMParser pemParser = new PEMParser(reader)) {
            SubjectPublicKeyInfo subjectPublicKeyInfo = (SubjectPublicKeyInfo) pemParser.readObject();
            JcaPEMKeyConverter pemKeyConverter = new JcaPEMKeyConverter();
            return pemKeyConverter.getPublicKey(subjectPublicKeyInfo);
        }
    }
}
person Alain O'Dea    schedule 19.09.2017
comment
Если вы используете подкласс PEMParser вместо PemReader, он возвращает структуру SubjectPublicKeyInfo, кодировку которой вы можете передать как X509EncodedKeySpec в фабрику ключей — или вы можете использовать JcaPEMKeyConverter, чтобы сделать последнее за вас. - person dave_thompson_085; 29.12.2018
comment
Ух ты. Это намного чище. Спасибо. Коррекция в ближайшее время. - person Alain O'Dea; 07.01.2019