英文:
Failed to parse RSA publicKey in Java
问题
以下是代码的翻译部分:
我正在使用以下代码块来解析任何RSA公钥进行加密。
static byte[] encrypt(byte[] publicKey, byte[] inputData) throws Exception {
PublicKey key = KeyFactory.getInstance(ALGORITHM).generatePublic(new X509EncodedKeySpec(publicKey));
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encryptedBytes = cipher.doFinal(inputData);
return encryptedBytes;
}
public static String getEncrypted(String data, String key) throws Exception {
byte[] keyBytes = Base64.getDecoder().decode(key);
return new String(Base64.getEncoder().encode(encrypt(keyBytes, data.getBytes())));
}
但对于以下RSA公钥:
MIIBCgKCAQEAs6YyGDXibkazM7QSeFBXjkAn5A8P87k+nuU6v5+zLJiD1KwkZ/SYnLwVSluOx19AzPHj07abDTJtthKtKpp2997UiV4CNUSzkZM1Eorf1+iLFhqeOiz9J5tYfFkKN5qPzwoPK4aFz35hQi7R1ORF9rFDPL+Ex79Tc+ABQF/CH5tn/NTXCNUYzLezg2Y1VOZGNhxd2LIv/29ZDxpJS8dD34H20HMMZCMGGolTXUIxVKI3cR0d1XzNCvAx3jcSkEUEPPH0lfusXqQOfCxJSIjorAzi5ucaWicvXYq6BNGulPqLoGBZnJ4HrFQF0oq1SU4i60VHqOgoiqMPQ+8cyjFBHQIDAQAB
在解析时我遇到了以下异常:
Caused by: java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException: algid parse error, not a sequence
at sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:205)
at java.security.KeyFactory.generatePublic(KeyFactory.java:334)
Caused by: java.security.InvalidKeyException: IOException: algid parse error, not a sequence
at sun.security.x509.X509Key.decode(X509Key.java:397)
at sun.security.x509.X509Key.decode(X509Key.java:402)
at sun.security.rsa.RSAPublicKeyImpl.<init>(RSAPublicKeyImpl.java:86)
at sun.security.rsa.RSAKeyFactory.generatePublic(RSAKeyFactory.java:298)
at sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:201)
有任何想法是什么出了问题以及如何创建一个通用的RSA公钥解析代码吗?
英文:
I am using the following code block to parse any RSA public key to encrypt.
static byte[] encrypt(byte[] publicKey, byte[] inputData) throws Exception {
PublicKey key = KeyFactory.getInstance(ALGORITHM).generatePublic(new X509EncodedKeySpec(publicKey));
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encryptedBytes = cipher.doFinal(inputData);
return encryptedBytes;
}
public static String getEncrypted(String data, String key) throws Exception {
byte[] keyBytes = Base64.getDecoder().decode(key);
return new String(Base64.getEncoder().encode(encrypt(keyBytes, data.getBytes())));
}
But for the following RSA public Key
MIIBCgKCAQEAs6YyGDXibkazM7QSeFBXjkAn5A8P87k+nuU6v5+zLJiD1KwkZ/SYnLwVSluOx19AzPHj07abDTJtthKtKpp2997UiV4CNUSzkZM1Eorf1+iLFhqeOiz9J5tYfFkKN5qPzwoPK4aFz35hQi7R1ORF9rFDPL+Ex79Tc+ABQF/CH5tn/NTXCNUYzLezg2Y1VOZGNhxd2LIv/29ZDxpJS8dD34H20HMMZCMGGolTXUIxVKI3cR0d1XzNCvAx3jcSkEUEPPH0lfusXqQOfCxJSIjorAzi5ucaWicvXYq6BNGulPqLoGBZnJ4HrFQF0oq1SU4i60VHqOgoiqMPQ+8cyjFBHQIDAQAB
while parsing I am getting the following exception
Caused by: java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException: algid parse error, not a sequence
at sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:205)
at java.security.KeyFactory.generatePublic(KeyFactory.java:334)
Caused by: java.security.InvalidKeyException: IOException: algid parse error, not a sequence
at sun.security.x509.X509Key.decode(X509Key.java:397)
at sun.security.x509.X509Key.decode(X509Key.java:402)
at sun.security.rsa.RSAPublicKeyImpl.<init>(RSAPublicKeyImpl.java:86)
at sun.security.rsa.RSAKeyFactory.generatePublic(RSAKeyFactory.java:298)
at sun.security.rsa.RSAKeyFactory.engineGeneratePublic(RSAKeyFactory.java:201)
Any idea what is failing and how to make a generic RSA public key parsing code.
答案1
得分: 2
以下是翻译好的内容:
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.opensl.PEMParser;
import java.io.IOException;
import java.io.StringReader;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.Security;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
public class MainSO {
public static void main(String[] args) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
System.out.println("https://stackoverflow.com/questions/63454577/failed-to-parse-rsa-publickey-in-java");
Security.addProvider(new BouncyCastleProvider());
String rsaPublicKeyHeader = "-----BEGIN RSA PUBLIC KEY-----\n";
String rsaPublicKeyFooter = "\n-----END RSA PUBLIC KEY-----";
String rsaPublicKeyString = "MIIBCgKCAQEAs6YyGDXibkazM7QSeFBXjkAn5A8P87k+nuU6v5+zLJiD1KwkZ/SYnLwVSluOx19AzPHj07abDTJtthKtKpp2997UiV4CNUSzkZM1Eorf1+iLFhqeOiz9J5tYfFkKN5qPzwoPK4aFz35hQi7R1ORF9rFDPL+Ex79Tc+ABQF/CH5tn/NTXCNUYzLezg2Y1VOZGNhxd2LIv/29ZDxpJS8dD34H20HMMZCMGGolTXUIxVKI3cR0d1XzNCvAx3jcSkEUEPPH0lfusXqQOfCxJSIjorAzi5ucaWicvXYq6BNGulPqLoGBZnJ4HrFQF0oq1SU4i60VHqOgoiqMPQ+8cyjFBHQIDAQAB";
PEMParser pemParser = new PEMParser(new StringReader(rsaPublicKeyHeader +
rsaPublicKeyString + rsaPublicKeyFooter));
SubjectPublicKeyInfo subjectPublicKeyInfo = (SubjectPublicKeyInfo) pemParser.readObject();
byte[] publicKey = subjectPublicKeyInfo.getEncoded();
// original code starts here
PublicKey key = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(publicKey));
// check key
System.out.println("key: " + key);
}
}
英文:
Your public key (here just the Base64-encoded part) seems to be a 'RSA Public Key'
and not a 'Public Key'. The later is the format that Java is been able to work with.
To read the 'RSA Public Key' you need the Bouncy Castle library and additional 7 lines of code. As you have the key without the 'wrapping' header and footer I add the two
line manually.
Please keep in mind that the following code has no proper exception handling and is for educational purposes only.
result:
key: Sun RSA public key, 2048 bits
params: null
modulus: 22678610734153400983507431374302231631648011897672768754638644005690558018788055145838420912495825001883497816406549666369767766949853573723573636289962789479998547620264293389522975840594912755684410510779642046063268111520844008640320545114702934792800828432077361704284837605938354936920018742130341245366517474980128047515437565419306561322350155414838564407700303406271838590880852369997316303577351737008942081641382006211591786506015023574950120763293965668830106827392978781367691242570394862298000041087969687942746452359360224223895623579995775734139473237799095359767270215802792812274542667250920043135261
public exponent: 65537
code:
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMParser;
import java.io.IOException;
import java.io.StringReader;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.Security;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
public class MainSO {
public static void main(String[] args) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
System.out.println("https://stackoverflow.com/questions/63454577/failed-to-parse-rsa-publickey-in-java");
Security.addProvider(new BouncyCastleProvider());
String rsaPublicKeyHeader = "-----BEGIN RSA PUBLIC KEY-----\n";
String rsaPublicKeyFooter = "\n-----END RSA PUBLIC KEY-----";
String rsaPublicKeyString = "MIIBCgKCAQEAs6YyGDXibkazM7QSeFBXjkAn5A8P87k+nuU6v5+zLJiD1KwkZ/SYnLwVSluOx19AzPHj07abDTJtthKtKpp2997UiV4CNUSzkZM1Eorf1+iLFhqeOiz9J5tYfFkKN5qPzwoPK4aFz35hQi7R1ORF9rFDPL+Ex79Tc+ABQF/CH5tn/NTXCNUYzLezg2Y1VOZGNhxd2LIv/29ZDxpJS8dD34H20HMMZCMGGolTXUIxVKI3cR0d1XzNCvAx3jcSkEUEPPH0lfusXqQOfCxJSIjorAzi5ucaWicvXYq6BNGulPqLoGBZnJ4HrFQF0oq1SU4i60VHqOgoiqMPQ+8cyjFBHQIDAQAB";
PEMParser pemParser = new PEMParser(new StringReader(rsaPublicKeyHeader +
rsaPublicKeyString + rsaPublicKeyFooter));
SubjectPublicKeyInfo subjectPublicKeyInfo = (SubjectPublicKeyInfo) pemParser.readObject();
byte[] publicKey = subjectPublicKeyInfo.getEncoded();
// original code starts here
PublicKey key = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(publicKey));
// check key
System.out.println("key: " + key);
}
}
答案2
得分: 2
你的问题与 https://stackoverflow.com/questions/31941413/invalidkeyspecexception-algid-parse-error-not-a-sequence 中的问题类似,尽管不完全相同。就像PKCS8是几乎任何算法中私钥的通用格式一样,通过包含标识算法的AlgorithmIdentifier和算法特定数据,Java使用了通用格式SubjectPublicKeyInfo(SPKI),由X.509/PKIX定义,用于公钥,Java称之为X509EncodedKeySpec
,包含AlgId和算法特定数据。(有关详细信息,请参阅java.security.Key
的javadoc;由于某种原因,我目前无法访问docs.oracle.com
获取链接。)您只拥有由PKCS1 RSAPublicKey定义的算法特定数据。
您可以使用BouncyCastle手动解析和使用它(https://stackoverflow.com/questions/33425446/creating-rsa-public-key-from-string),或者将其转换为SPKI并使用(https://stackoverflow.com/questions/54238568/reading-a-pkcs1-or-spki-public-key-in-java-without-libraries)。或者(在使用BC或其他ASN.1库的情况下),您可以使用与#31941413中相同的方法,只是省略Integer版本(0),并将数据包装在DERBitString中,而不是DEROctetString中,或者使用我在https://stackoverflow.com/questions/53924326/rsa-should-i-use-x-509-or-pkcs-1 中展示的更简单、更直接的方法。
请注意,这不是“通用”的格式。您的格式与算法通用相反,这正是SPKI和PCKS8的目的。它也不是应用程序通用;除其他外,OpenSSH、PGP、Microsoft、PKCS11、JWK和XML都使用与此不同且不易与Java兼容的公钥格式。
英文:
Your problem is analagous to the problem in https://stackoverflow.com/questions/31941413/invalidkeyspecexception-algid-parse-error-not-a-sequence, though not the same. Just like PKCS8 is a generic format for private keys in (almost) any algorithm, by containing both an AlgorithmIdentifier that identifies the algorithm and algorithm-specific data, Java uses the generic format SubjectPublicKeyInfo (SPKI) defined by X.509/PKIX for public keys, which Java calls X509EncodedKeySpec
, containing an AlgId plus algorithm-specific data. (See the javadoc for java.security.Key
; for some reason I am currently unable to access docs.oracle.com
to get a link.) You have only the algorithm-specific data defined by PKCS1 RSAPublicKey.
You can parse and use it 'manually' with BouncyCastle, or convert it to SPKI and use that. Or (given BC or another ASN.1 library) you could use the same approach as in #31941413 except omit the Integer version (0) and wrap the data in a DERBitString instead of a DEROctetString, or the simpler and more direct approach I show in https://stackoverflow.com/questions/53924326/rsa-should-i-use-x-509-or-pkcs-1 .
Note this is not 'generic'. Your format is the opposite of algorithm-generic, which as noted is the purpose of SPKI and PCKS8. It is also not applciation-generic; among other things OpenSSH, PGP, Microsoft, PKCS11, JWK, and XML all use publickey formats different from this and not easily compatible with Java.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论