Как мы преобразуем String из 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 API openSSL PEM_write_bio_RSAPublicKey(bio, rsa);
Ответы
Ответ 1
вызывая PEM_write_bio_RSAPublicKey
, только модуль ключа и открытый показатель кодируются в выходные данные PEM. Однако X509EncodedKeySpec
ожидается в этом формате ключа ASN.1:
SubjectPublicKeyInfo ::= SEQUENCE {
algorithm AlgorithmIdentifier,
subjectPublicKey BIT STRING }
Вы должны использовать функцию PEM_write_bio_PUBKEY
, которая кодирует открытый ключ, используя структуру SubjectPublicKeyInfo, которая, как ожидалось, X509EncodedKeySpec
Другое возможное решение для декодирования ключа. К сожалению, я не думаю, что это можно сделать только со стандартным JDK API, но это можно сделать с помощью Bouncycastle library
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);
}
Ответ 2
BouncyCastle PEMReader сделает это за вас:
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());
где-то раньше.)
Ответ 3
Вы можете создать объект PublicKey из строки, которую вы указали, следующим образом:
- PEM декодирует строку двоичному DER (используя Bouncy Castle PemReader)
- Подача двоичного DER в парсер ASN.1 (работает Bouncy Castle ASN1InputStream)
- Получить анализируемые данные ASN.1 из анализатора (как Bouncy Castle ASN1Primitive)
- Интерпретируйте данные ASN.1 как ключ RSA (используя Bouncy Castle RSAPublicKey)
- Построить спецификацию для ключа JSSE factory, включая модуль и показатель ключа RSA (с помощью Bouncy Castle RSAPublicKeySpec)
- Используйте ключ JSSE factory, чтобы создать объект открытого ключа (необходимый объект JSCE PublicKey)
Я надеялся на более простой, но не мог найти его. Я также не мог использовать другие решения для работы.
Предварительные требования для моего решения:
- Java 7+ (или вам нужно вручную развернуть try-with-resources)
- Bouncy Castle bcprov-jdk15on 1.53 или новее (возможно, возможно, работа с ранее, но я его не тестировал)
Полный рабочий пример Java 7+:
import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.pkcs.RSAPublicKey;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemReader;
import java.io.IOException;
import java.io.StringReader;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPublicKeySpec;
public interface PemToDer
{
static void main(String[] args) throws
NoSuchAlgorithmException, IOException, InvalidKeySpecException
{
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, NoSuchAlgorithmException, InvalidKeySpecException
{
try (StringReader reader = new StringReader(keystr);
PemReader pemReader = new PemReader(reader))
{
PemObject pem = pemReader.readPemObject();
byte[] der = pem.getContent();
ASN1InputStream in = new ASN1InputStream(der);
ASN1Primitive primitive = in.readObject();
RSAPublicKey key = RSAPublicKey.getInstance(primitive);
RSAPublicKeySpec spec = new RSAPublicKeySpec(
key.getModulus(), key.getPublicExponent()
);
KeyFactory factory = KeyFactory.getInstance("RSA");
return factory.generatePublic(spec);
}
}
}