我有一个RSA公钥证书。我可以使用具有。PEM扩展名或仅将其用作具有以下格式的字符串:
启动RSA公共密钥
{KEY}
-----结束RSA公钥-----
我试图使用此密钥向服务器发送加密的JSON。我尝试了许多其他相关堆栈溢出问题的解决方案,但没有一个答案不适合我。这个答案似乎有道理https://stackoverflow.com/a/43534042,但有些东西不能正常工作,可能是因为X509EncodedKeySpec期望的是DER编码的数据,而不是PEM,根据其中一条注释。但是在这种情况下,我应该用什么来处理PEM编码的数据呢?
Michael Fehr的回答说明了如何在没有第三方库的情况下加载PKCS#1格式的公钥。如果后者是一个要求,那么这就是你必须走的路
否则,如果您使用BouncyCastle,可能还会考虑一些不太复杂的解决方案,因此值得一提(尽管给出的答案已经被接受):
以下方法需要PKCS#1格式的公钥,经过PEM编码并将其加载到java.security.PublicKey实例中:
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import java.security.PublicKey;
import java.io.StringReader;
...
private static PublicKey getPublicKey(String publicKeyc) throws Exception {
PEMParser pemParser = new PEMParser(new StringReader(publicKeyc));
JcaPEMKeyConverter jcaPEMKeyConverter = new JcaPEMKeyConverter();
SubjectPublicKeyInfo subjectPublicKeyInfo = (SubjectPublicKeyInfo)pemParser.readObject();
PublicKey publicKey = jcaPEMKeyConverter.getPublicKey(subjectPublicKeyInfo);
return publicKey;
}
另一个类似紧凑的实现可以在这里找到。
要在Android中使用BouncyCastle,必须在构建的dependencies部分中引用与使用的API级别相对应的BouncyCastle依赖项。格雷德尔档案。我使用API级别28(Pie)并引用了以下依赖项(假设Android Studio):
implementation 'org.bouncycastle:bcpkix-jdk15on:1.65'
正如@Topaco已经评论的那样,您的RSA公钥是PEM编码的,但PKCS#1格式,而不是Java“开箱即用”可读的PKCS#8格式。
以下解决方案由@Maarten Bodewes在此提供(https://stackoverflow.com/a/54246646/8166854)将执行读取并将其转换为(Java)可用公钥的任务。
解决方案在我的OpenJdk11上运行,如果您使用的是“Android Java”,您可能需要更改Base64调用。没有必要像Bouncy Castle这样的外部库。请遵守Maarten关于钥匙长度的说明。
简单的输出:
Load RSA PKCS#1 Public Keys
pkcs1PublicKey: Sun RSA public key, 2048 bits
params: null
modulus: 30333480050529072539152474433261825229175303911986187056546130987160889422922632165228273249976997833741424393377152058709551313162877595353675051556949998681388601725684016724167050111037861889500002806879899578986908702627237884089998121288607696752162223715667435607286689842713475938751449494999920670300421827737208147069624343973533326291094315256948284968840679921633097541211738122424891429452073949806872319418453594822983237338545978675594260211082913078702997218079517998196340177653632261614031770091082266225991043014081642881957716572923856737534043425399435601282335538921977379429228634484095086075971
public exponent: 65537
代码:
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
public class LoadPkcs1PublicKeyPemSo {
// solution from https://stackoverflow.com/a/54246646/8166854 answered Jan 18 '19 at 1:36 Maarten Bodewes
private static final int SEQUENCE_TAG = 0x30;
private static final int BIT_STRING_TAG = 0x03;
private static final byte[] NO_UNUSED_BITS = new byte[] { 0x00 };
private static final byte[] RSA_ALGORITHM_IDENTIFIER_SEQUENCE =
{(byte) 0x30, (byte) 0x0d,
(byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x01,
(byte) 0x05, (byte) 0x00};
public static void main(String[] args) throws GeneralSecurityException, IOException {
System.out.println("Load RSA PKCS#1 Public Keys");
String rsaPublicKeyPem = "-----BEGIN RSA PUBLIC KEY-----\n" +
"MIIBCgKCAQEA8EmWJUZ/Osz4vXtUU2S+0M4BP9+s423gjMjoX+qP1iCnlcRcFWxt\n" +
"hQGN2CWSMZwR/vY9V0un/nsIxhZSWOH9iKzqUtZD4jt35jqOTeJ3PCSr48JirVDN\n" +
"Let7hRT37Ovfu5iieMN7ZNpkjeIG/CfT/QQl7R+kO/EnTmL3QjLKQNV/HhEbHS2/\n" +
"44x7PPoHqSqkOvl8GW0qtL39gTLWgAe801/w5PmcQ38CKG0oT2gdJmJqIxNmAEHk\n" +
"atYGHcMDtXRBpOhOSdraFj6SmPyHEmLBishaq7Jm8NPPNK9QcEQ3q+ERa5M6eM72\n" +
"PpF93g2p5cjKgyzzfoIV09Zb/LJ2aW2gQwIDAQAB\n" +
"-----END RSA PUBLIC KEY-----";
RSAPublicKey pkcs1PublicKey = getPkcs1PublicKeyFromString(rsaPublicKeyPem);
System.out.println("pkcs1PublicKey: " + pkcs1PublicKey);
}
public static RSAPublicKey getPkcs1PublicKeyFromString(String key) throws GeneralSecurityException {
String publicKeyPEM = key;
publicKeyPEM = publicKeyPEM.replace("-----BEGIN RSA PUBLIC KEY-----", "");
publicKeyPEM = publicKeyPEM.replace("-----END RSA PUBLIC KEY-----", "");
publicKeyPEM = publicKeyPEM.replaceAll("[\\r\\n]+", "");
byte[] pkcs1PublicKeyEncoding = Base64.getDecoder().decode(publicKeyPEM);
return decodePKCS1PublicKey(pkcs1PublicKeyEncoding);
}
/*
solution from https://stackoverflow.com/a/54246646/8166854 answered Jan 18 '19 at 1:36 Maarten Bodewes
The following code turns a PKCS#1 encoded public key into a SubjectPublicKeyInfo encoded public key,
which is the public key encoding accepted by the RSA KeyFactory using X509EncodedKeySpec -
as SubjectPublicKeyInfo is defined in the X.509 specifications.
Basically it is a low level DER encoding scheme which
wraps the PKCS#1 encoded key into a bit string (tag 0x03, and a encoding for the number of unused
bits, a byte valued 0x00);
adds the RSA algorithm identifier sequence (the RSA OID + a null parameter) in front -
pre-encoded as byte array constant;
and finally puts both of those into a sequence (tag 0x30).
No libraries are used. Actually, for createSubjectPublicKeyInfoEncoding, no import statements are even required.
Notes:
NoSuchAlgorithmException should probably be caught and put into a RuntimeException;
the private method createDERLengthEncoding should probably not accept negative sizes.
Larger keys have not been tested, please validate createDERLengthEncoding for those -
I presume it works, but better be safe than sorry.
*/
public static RSAPublicKey decodePKCS1PublicKey(byte[] pkcs1PublicKeyEncoding)
throws NoSuchAlgorithmException, InvalidKeySpecException
{
byte[] subjectPublicKeyInfo2 = createSubjectPublicKeyInfoEncoding(pkcs1PublicKeyEncoding);
KeyFactory rsaKeyFactory = KeyFactory.getInstance("RSA");
RSAPublicKey generatePublic = (RSAPublicKey) rsaKeyFactory.generatePublic(new X509EncodedKeySpec(subjectPublicKeyInfo2));
return generatePublic;
}
public static byte[] createSubjectPublicKeyInfoEncoding(byte[] pkcs1PublicKeyEncoding)
{
byte[] subjectPublicKeyBitString = createDEREncoding(BIT_STRING_TAG, concat(NO_UNUSED_BITS, pkcs1PublicKeyEncoding));
byte[] subjectPublicKeyInfoValue = concat(RSA_ALGORITHM_IDENTIFIER_SEQUENCE, subjectPublicKeyBitString);
byte[] subjectPublicKeyInfoSequence = createDEREncoding(SEQUENCE_TAG, subjectPublicKeyInfoValue);
return subjectPublicKeyInfoSequence;
}
private static byte[] concat(byte[] ... bas)
{
int len = 0;
for (int i = 0; i < bas.length; i++)
{
len += bas[i].length;
}
byte[] buf = new byte[len];
int off = 0;
for (int i = 0; i < bas.length; i++)
{
System.arraycopy(bas[i], 0, buf, off, bas[i].length);
off += bas[i].length;
}
return buf;
}
private static byte[] createDEREncoding(int tag, byte[] value)
{
if (tag < 0 || tag >= 0xFF)
{
throw new IllegalArgumentException("Currently only single byte tags supported");
}
byte[] lengthEncoding = createDERLengthEncoding(value.length);
int size = 1 + lengthEncoding.length + value.length;
byte[] derEncodingBuf = new byte[size];
int off = 0;
derEncodingBuf[off++] = (byte) tag;
System.arraycopy(lengthEncoding, 0, derEncodingBuf, off, lengthEncoding.length);
off += lengthEncoding.length;
System.arraycopy(value, 0, derEncodingBuf, off, value.length);
return derEncodingBuf;
}
private static byte[] createDERLengthEncoding(int size)
{
if (size <= 0x7F)
{
// single byte length encoding
return new byte[] { (byte) size };
}
else if (size <= 0xFF)
{
// double byte length encoding
return new byte[] { (byte) 0x81, (byte) size };
}
else if (size <= 0xFFFF)
{
// triple byte length encoding
return new byte[] { (byte) 0x82, (byte) (size >> Byte.SIZE), (byte) size };
}
throw new IllegalArgumentException("size too large, only up to 64KiB length encoding supported: " + size);
}
}
在那里~我是新来的flutter开发,我试图使用Node.js服务器发送一个公钥到flutter加密密码但是,它就是不工作,我试图通过JSON格式或通过PEM文件的flutter和使用[Flutter]-加密和[Flutter]-simple_rsa库做加密,但它仍然不能工作。我怎么能这么做?请帮忙,多谢。 [Node.js]-使用[Node rsa]创建密钥[Flatter]-使用[encryp
如何从Go中的字符串导入RSA公钥,以便用于加密数据? 我的程序应该执行以下操作: > 接收一个用Base64编码的公钥 将此公钥从Base64解码为字节 导入公钥,以便Go的RSA实现可以使用(问题在这个阶段) 加密AES密钥: 提前谢谢! 解决方案: 公钥必须使用crypto/x509包进行解码。 例如: 然后可以使用带有RSA的进行加密。
问题内容: 我正在编写一个用于传输文件的小型应用程序,或多或少地将其作为一种学习更多编程加密基础的方法。这个想法是生成一个RSA密钥对,交换公共密钥,并发送AES iv和密钥以进一步解密。我想用接收者的RSA公钥加密AES密钥,如下所示: 然后,我将密钥值写给接收器,并按如下方式解密: 在控制台的另一端,我将其作为输出: 此外,如果我创建一个大小为16的字节数组,并将cipher.doFinal(
userData.json:
我使用Delphi XE和Lockbox3.5,我想加密一个字符串,该字符串具有支付网关提供的公钥,需要操作,公钥类似于:------开始公钥------这里的职员------结束公钥------我无法使RSA编解码器读取该公钥,我的代码如下: 编解码器cdcRA链接到CryptoLibrary,密码为(RSA公钥加密系统*),链接模式为空,但此代码失败,并出现内存不足错误。谢谢你的提示。。 演示
我想得到一个文件内容的公钥,这是一个文件内容看起来像什么的例子(用生成): 如果我是对的,这不是公钥,但是可以从这个字符串中获取公钥。 这个答案回答了我的问题https://stackoverflow.com/a/19387517/2735398 但答案似乎不起作用。我有个例外: 当看到答案的评论时,我不是唯一有问题的人... 如何修复异常?或者有没有其他方法可以从字符串中获取公钥?