如何在java中使用RSA PublicKey加密数据?

问题描述 投票:0回答:1

我有一个带参数的 json 响应:

 "jwk":{
    "kty": "string",
    "n": "string",
    "e": "string",
    "alg": "string",
    "ext": bool
  },
 "pem": "--BEGIN RSA PUBLIC KEY--...SOMEKEY...--END RSA PUBLIC KEY--",
 "alg": {
    "name": "string",
    "hash": {
        "name": "string
    }
 }
}

我需要使用 RSA 公钥加密数据。 我正在尝试获取“pem”,清除它并创建公钥

String clearKey = rsaKey.replace("--BEGIN RSA PUBLIC KEY--", "").replace("--END RSA PUBLIC KEY--", "").replace("\\s","");
byte[] prByte = Base64.getDecoder().decode(clearKey);
KeyFactory keyFactory = KeyFactory.getInstanse("RSA");
keyFactory.generatePrivate(new PKCS8EEncodedKeySpec(prByte));

但是在这一步我有一个错误

:java.security.InvalidKeyException: IOException: algid parse error not a sequence

这段代码后面也有错误

byte[] prByte = Base64.getDecoder().decode(clearKey);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(prBytes);
PublicKey publicKey = keyFactory.generatePublic("keySpec"):

我知道 RSA PUBLIC KEY 也许应该映射到 RSAPublicKey 但为此我需要“n”和“e”属性?

java encryption rsa
1个回答
0
投票

RSA 公钥没有以您显示的字符串开头和结尾的 PEM 格式:所有 PEM 格式均以五个连字符、大写“BEGIN”、一个或多个大写单词的标签或类型描述、五个连字符和一个换行符开头;后面是一行或多行 base64,然后是类似的行,其中使用“END”而不是“BEGIN”,并且可选地“END”行之后的换行符可以省略。 请参阅维基百科以及其中引用的RFC 7468

如果您的“PEM”实际上采用我(以及维基百科和7468)描述的格式,而不是您发布的格式,那么它是OpenSSL(最初是SSLeay)基于简单直接的ASN.1定义的“传统”格式由 PKCS1 定义的格式。这与 X.509 定义并由 Java 用作

X509EncodedKeySpec
的 X.509“SPKI”(SubjectPublicKeyInfo)格式不同。 (它与 Java 用于私钥的 PKCS8 格式更加不同,因为公钥不是私钥。)然而,它是
相关的
,因为 SPKI 格式实际上是包含 AlgorithmIdentifier 的 ASN.1 SEQUENCE其中(令人惊讶!)标识了算法以及包含特定于算法的数据的位串,以及对于 RSA,特定于算法的数据is PKCS1 PKCS8EncodedKeySpec,因此 RSA 密钥的 SPKI 的 DER 编码包含作为 OpenSSL 定义的
RSAPublicKey
文件中找到的 PKCS1 数据的后缀。
有两种方法可以直接使用这种“传统”PEM 格式:

    通过构建 ASN.1“包装器”来构建同一密钥的 SPKI 格式,然后将其提供给
  1. BEGIN/END RSA PUBLIC KEY

    
    

  2. 使用来自
  3. https://www.bouncycastle.org

    的 bcpkix+bcprov,其 KeyFactory.getInstance("RSA") .generatePublic( new X509EncodedKeySpec( spki )) 类与

    PEMParser
    结合可以直接处理传统的 RSA 公钥(以及许多其他格式)。
    
    

  4. 这两种方法都已被询问并回答过多次。参见:

如何在Java中从String加载RSA公钥进行签名验证?
在没有库的情况下用 Java 读取 PKCS#1 或 SPKI 公钥
Java中解析RSA公钥失败
RSA 我应该使用 X.509 还是 PKCS #1
(还有更多链接) 如何在两种风格的公钥格式之间进行转换,一种是“BEGIN RSA PUBLIC KEY”,另一种是“BEGIN PUBLIC KEY”
(背景但不是Java) 将 PKCS1

privatekey

转换为 PKCS8 的类似问题也经常出现。我在 Java: Convert DKIM private key from RSA to DER for JavaMail 中写了一个相当于方法 1 的答案(即“包装” PKCS1 私钥以提供 PKCS8),另外两个人在 Getting RSA private key from 中也做了类似的事情PEM BASE64 编码的私钥文件 。修改我在 #23709898 中的方法,将 publickey-to-SPKI 而不是 privatekey-to-PKCS8 给出: JcaPEMKeyConverter

但是由于您还有 JWK 表格,您还有第三种选择:

获取 jwk n 和 e 值(从您使用的任何 JSON 类/表示形式),将每个值转换为(正)BigInteger,将它们放入
    // input: b64 contains the base64 _data_ from a BEGIN/END RSA PUBLIC KEY file // (i.e. with the BEGIN/END lines and linebreaks removed) byte[] oldder = Base64.getDecoder().decode (b64); // concatenate the mostly-fixed prefix plus the PKCS#1 data final byte[] prefix = {0x30,(byte)0x82,0,0, // SEQUENCE(lenTBD) 0x30,0x0d, 6,9,0x2a,(byte)0x86,0x48,(byte)0x86,(byte)0xf7,0x0d,1,1,1, 5,0, // AlgID for rsaEncryption,NULL 3,(byte)0x82,0,0,0 }; // BITSTRING(lenTBD) + unused byte[] newder = new byte [prefix.length + oldder.length]; System.arraycopy (prefix,0, newder,0, prefix.length); System.arraycopy (oldder,0, newder,prefix.length, oldder.length); // and patch the (variable) lengths to be correct int len = oldder.length+1, loc = prefix.length-3; newder[loc] = (byte)(len>>8); newder[loc+1] = (byte)len; len = newder.length-4; loc = 2; newder[loc] = (byte)(len>>8); newder[loc+1] = (byte)len; PublicKey pubkey = KeyFactory.getInstance("RSA") .generatePublic( new X509EncodedKeySpec( newder ));
  1. 中并通过
    RSAPublicKeySpec
    运行:
    
    
  2. KeyFactory
© www.soinside.com 2019 - 2024. All rights reserved.