使用给定公钥的 RSA 加密(在 Java 中)

2022-09-01 09:36:12

我正在寻找一个Java示例,如何使用给定的公钥进行RSA加密(我有base64格式,似乎是1024位长度)。

下面是我的代码,但我有无效密钥规范异常。

String publicKey = "AJOnAeTfeU4K+do5QdBM2BQUhfrRI2rYf/Gk4a3jZJB2ewekgq2VgLNislBdql/glA39w0NjXZyTg0mW917JdUlHqKoQ9765pJc4aTjvX+3IxdFhteyO2jE3vKX1GgA3i3n6+sMBAJiT3ax57i68mbT+KAeP1AX9199aj2W4JZeP";
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
byte[] res = new Base64Encoder().decode(publicKey.getBytes());
X509EncodedKeySpec KeySpec = new X509EncodedKeySpec(res);
RSAPublicKey pubKey = (RSAPublicKey)keyFactory.generatePublic(KeySpec);

// here the exception occurs..

Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] cipherData = cipher.doFinal(input.getBytes());
return cipherData;

请给我样品,


答案 1

以下是我如何设法仅使用RSA公钥加密字符串。

首先将 PEM 格式的公钥保存到文件名 pubkey.pem

-----BEGIN PUBLIC KEY-----
AJOnAeTfeU4K+do5QdBM2BQUhfrRI2rYf/Gk4...
-----END PUBLIC KEY-----

查找公有 RSA 密钥模量

$ openssl rsa -pubin -in pubkey.pem -modulus -noout
Modulus=F56D...

查找公有 RSA 密钥指数

$ openssl rsa -pubin -in pubkey.pem -text -noout
...
Exponent: 65537 (0x10001)

然后将它们插入到以下代码中。

BigInteger modulus = new BigInteger("F56D...", 16);
BigInteger pubExp = new BigInteger("010001", 16);

KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec(modulus, pubExp);
RSAPublicKey key = (RSAPublicKey) keyFactory.generatePublic(pubKeySpec);

Cipher cipher = Cipher.getInstance("RSA/ECB/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key);

byte[] cipherData = cipher.doFinal(text.getBytes());

答案 2

您的“密钥”不是有效的公钥。它是一个 Base64 字符串,在解码时,生成一个 129 字节的序列,第一个0x00,后跟 0x93。这不是 RSA 公钥的有效格式,但可疑地看起来像 1024 位整数的大端有符号编码(即 ASN.1 “INTEGER” 值返回和使用的编码类型)。RSA 公钥名义上由两个整数组成,一个是模数,另一个是公共指数。典型的RSA模量的长度为1024位,因此您很可能在这里拥有模量。您仍然需要公共指数来完成密钥。BigInteger.toByteArray()

X509EncodedKeySpec需要 ASN.1 结构的 DER 编码,该结构将算法标识为 RSA,并包含嵌套编码结构,该结构本身包含 RSA 公钥的两个整数。手动组装这样的结构可能很困难(这是可行的,但需要对ASN.1有一些深入的了解)。一个更简单的方法是使用:RSAPublicKeySpec

String modulusBase64 = "..."; // your Base64 string here
BigInteger modulus = new BigInteger(1,
        new Base64Encoder.decode(modulusBase64.getBytes("UTF-8")));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
RSAPublicKeySpec ks = new RSAPublicKeySpec(modulus, pubExp);
RSAPublicKey pubKey = (RSAPublicKey)keyFactory.generatePublic(KeySpec);

在上面,“”应该是一个包含公共指数,你不给。3 和 65537 是公共指数的传统值,但其他值是可能的,并且您没有提供足够的信息来区分公共指数(即,即使您没有使用正确的代码,您的代码也会看起来有效)。基本上,你只有一半的公钥;你应该问谁给你那一半,也送你另一半。pubExpBigInteger

注意:使用平台默认编码,这并不总是相同的。如果您坚持将字符串转换为字节序列,则应使用显式字符集名称,例如 ,否则,如果您的代码在俄语或中文系统上运行,则可能会遇到麻烦。另外,我不知道你的类来自哪里(它不是标准Java API的一部分),但很有可能它也可以直接在,或a上工作,使得转换步骤变得不必要。String.getBytes()"UTF-8"Base64EncoderStringStringReader


推荐