首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >用NodeJS加密<RSA_PKCS1_OAEP_PADDING>填充和<sha256> oaepHash解密

用NodeJS加密<RSA_PKCS1_OAEP_PADDING>填充和<sha256> oaepHash解密
EN

Stack Overflow用户
提问于 2021-05-04 17:13:13
回答 1查看 1K关注 0票数 2

我需要解密来自用NodeJS构建的外部服务的一些信息。该服务请求base64格式的RSA (2048)公钥,以便对信息进行加密。

我正在用Java创建密钥对:

代码语言:javascript
运行
复制
    KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
    kpg.initialize(2048);
    KeyPair kp = kpg.generateKeyPair();
    PublicKey pubkey = kp.getPublic();
    PrivateKey privkey = kp.getPrivate();

    String pemPublicString = "-----BEGIN PUBLIC KEY-----\n";
    pemPublicString = pemPublicString+Base64.getEncoder().encodeToString(pubkey.getEncoded())+"\n";
    pemPublicString = pemPublicString+"-----END PUBLIC KEY-----\n";
    
    String pemPrivateString = "-----BEGIN RSA PRIVATE KEY-----\n";
    pemPrivateString = pemPrivateString+Base64.getEncoder().encodeToString(privkey.getEncoded())+"\n";
    pemPrivateString = pemPrivateString+"-----END RSA PRIVATE KEY-----\n";
    
    //Send to node js service
    String base64publickey = Base64.getEncoder().encodeToString(pemPublicString.getBytes());

    //Store for decrypting
    String base64privatekey = Base64.getEncoder().encodeToString(pemPrivateString.getBytes());

外部服务对信息进行加密,如下所示,并返回字节:

代码语言:javascript
运行
复制
  crypto.publicEncrypt(
  {
    key: publicKey,
    padding: crypto.constants.RSA_PKCS1_OAEP_PADDING,
    oaepHash: "sha256",
  },
    dataToEncrypt
  );

我试图以以下方式解密Java中的信息:

代码语言:javascript
运行
复制
    public String decrypt(String payload, String privateKey){
      byte [] ciphertext = payload.getBytes(StandardCharsets.UTF_8);
      Cipher oaepFromInit = Cipher.getInstance("RSA/ECB/OAEPPadding");
      OAEPParameterSpec oaepParams = new OAEPParameterSpec("SHA-256", "MGF1", new 
      MGF1ParameterSpec("SHA-1"), PSource.PSpecified.DEFAULT);
      oaepFromInit.init(Cipher.DECRYPT_MODE, getRSAPrivateKeyFrom(privateKey), oaepParams);
      byte[] pt = oaepFromInit.doFinal(ciphertext);
      return new String(pt, StandardCharsets.UTF_8);
    }

    private PrivateKey getRSAPrivateKeyFrom(String content) {
      byte[] decodedBytes = Base64.getDecoder().decode(content);
      String decodedString = new String(decodedBytes);
      Security.addProvider(new BouncyCastleProvider());
      PEMParser pemParser = new PEMParser(new StringReader(decodedString));
      JcaPEMKeyConverter converter = new JcaPEMKeyConverter().setProvider("BC");
      Object object = pemParser.readObject();
      PrivateKey k = converter.getPrivateKey((PrivateKeyInfo) object);
      return k;
   }

现在我得到了一个BadPadding异常,知道有什么问题吗?提前谢谢。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-05-05 09:57:46

发布的代码没有显示NodeJS代码如何导出密文。Java代码的decrypt()中的以下一行:

代码语言:javascript
运行
复制
 byte[] ciphertext = payload.getBytes(StandardCharsets.UTF_8);

意味着您使用了Utf-8编码。这是一个常见的错误,破坏了密文(请参阅这里)。而不是Utf-8,而是应用二进制到文本编码,例如Base64。

然后,密码文本的导出将在NodeJS中使用以下方式完成:

代码语言:javascript
运行
复制
var chiphertextBase64 = ciphertext.toString('base64');

以及在Java中的导入:

代码语言:javascript
运行
复制
import java.util.Base64;
...
byte[] ciphertext = Base64.getDecoder().decode(payload);  

在NodeJS代码中,OAEP (RSAES-OAEP)被指定为填充。crypto.publicEncrypt()与参数oaepHash一起应用于两个对象的相同的摘要、OAEP和MGF1摘要。因此,oaepHash: "sha256"为这两个摘要指定了SHA256。

相反,Java允许单独(和不同)规范OAEP和MGF1摘要。SHA256用于decrypt()中的OAEP摘要,SHA1用于MGF1摘要。后者与NodeJS代码不一致,需要更改为SHA256:

代码语言:javascript
运行
复制
OAEPParameterSpec oaepParams = new OAEPParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-256"), PSource.PSpecified.DEFAULT);

这个bug已经在Maarten Bodewes的第一条评论中被怀疑了。

在发布的代码中,PEM编码的pemPublicStringpemPrivateString密钥分别被Base64编码为base64publickeybase64privatekey。这是不必要的,因为PEM编码密钥的主体已经被Base64编码,页眉和页脚由ASCII字符组成。因此,第二次Base64编码没有带来任何好处,但是关键数据不必要地扩大了缺点(Base64开销: 33%,参见这里)。另一方面,如果服务需要双Base64编码的公钥,则必须遵守。

在生成密钥时,发布的Java代码隐式地使用私钥的PKCS#8格式。您可以使用privkey.getFormat()验证这一点,它将输出PKCS#8。PKCS#8的关联页眉是-----BEGIN PRIVATE KEY-----和页脚-----END PRIVATE KEY-----。您当前使用的页眉和页脚都属于PEM编码的PKCS#1私钥,因此与密钥数据不一致。这一问题已在Maarten Bodewes的第二次评论中讨论过。

顺便说一句,PKCS#8密钥可以很容易地导入,而不用BouncyCastle使用PKCS8EncodedKeySpec。对于这个唯一的页眉,页脚和行中断必须被删除,其余的必须被Base64解码(DER编码),例如这里

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67389228

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档