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

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

下面是我的代码,但我有InvalidKeySpecexception。

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; 

请给我样品,

以下是我只使用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()); 

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

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); 

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

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

您的公钥真的是X509编码的吗? 如果没有,那么未编码的Keyspec应该会有所帮助。

您的公钥看起来不像Base64编码的1024位值。 1024位值需要1​​72个字符(最后一个是填充符= ),这里我们有175个字符。

对于测试,将String中的最后四个字符替换为单个 =并测试是否消除了exception。 这不会解决问题,但可能指向正确的方向。