微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

节点 crypto.publicEncrypt 每次使用都会返回不同的值

如何解决节点 crypto.publicEncrypt 每次使用都会返回不同的值

我正在尝试实现基本的非对称加密;一个服务有一个公钥并用该公钥加密一个值,然后另一个服务接收加密的消息,使用私钥对其进行解码,并对解密的数据进行处理。

我遇到的问题是,每次使用内置的 crypto.publicEncrypt 方法时,都会返回不同的加密值。据我所知,我使用的是相同的输入,所以据我所知,我应该看到相同的输出。也许我误解了这一点?

这是我的加密实用程序;

import { createPublicKey,createPrivateKey,privateDecrypt,publicEncrypt,constants } from "crypto";

const privateKeyPem = process.env.ENCRYPTION_PRIVATE_KEY;
const privateKeyPemFixed = privateKeyPem.replace(/\\n/g,"\n");
const privateKey = createPrivateKey(privateKeyPemFixed);
const publicKey = createPublicKey(privateKey);

// const private1 = privateKey.export({
//   type: 'pkcs1',//   format: 'pem',// }).toString("base64");

// const public1 = publicKey.export({
//   type: 'pkcs1',// }).toString("base64");

export const encrypt = (text: string): string => {
  const buffer = Buffer.from(text);

  const encrypted1 = publicEncrypt(   {
      key: publicKey,oaepHash: 'sha256',padding: constants.RSA_PKCS1_OAEP_PADDING,},buffer);

  const encrypted2 = publicEncrypt({
    key: publicKey,buffer);

  console.log(encrypted1.toString("base64"));
  console.log(encrypted2.toString("base64"));

  return encrypted1.toString("base64");
}

export const decrypt = (cipher: string): string => {
  const buffer = Buffer.from(cipher);
  const decrypted = privateDecrypt(privateKey,buffer);
  return decrypted.toString("utf8");
}

我有一个看起来像这样的笑话测试;

import { encrypt } from "./encryption";

describe("encryption",() => {

  const helloWorld = "Hello world";
  const encryptedHelloWorld = "IIisobkVsZxKiR0e5nwyIHjsww/ebrKXI0hzDbdTdC8KMU2rc57IRX9krhVThVma2no7gZcMvbfwJsRjHz1s7NoBiT+BitgYlI/LE1jMpFd5Bmghy2S93F/wGFRWA4DMAqdw32I9s8CRKVvellxkh3ZlJ5NyzxWG8kVfc11CrEMD+1sqo2e9cFCcTdx5jEVYpCgITy7X2vDxUwOPQ7bK8K56kU5ivQhUfyoHjd9VclRUxfBaSzOwLJQqK6RJPbNwuUfILcCaR72GTf4zWMhQqIvs/zHhSu+S9QQYPVvmZ1SzqqJaCM9mM6Cvl8Gn2brwcMB003f0CFb8WFimogM6lQ==";

  it("should encrypt text",() => {
    const received = encrypt(helloWorld);
    expect(received).toEqual(encryptedHelloWorld);
  });
});

然而它总是失败,因为结果似乎总是不同。

我在 encrypt 函数中运行了两次加密过程,以演示问题;它注销的两个值完全不同,我不明白为什么。

  console.log
    aDWDWcE+Zs92/rp2DLJN8UTgwHPTg6TDqFPIrC3ODVIfZgo5uaQV0NTSESPPPAGHhHeKiWB8JFnVewJaEN7iz9StzRepaL3+DFpD/CvhA8L7o8CQ5CTeScqL9HedVkM7O4MziMHkTJy0Li7EjP/6xdp8Caw+m6EsqvQ9Yd3qN4OTwrsMWmItLIaAHmkB/4UPhMqVnddVnwBUVb7toJ5rvGc/uktZkZPuHdzjri0XSW//ltHHFCi3zneoJ92v/myYZOtWTyBDTmrgUtzC5fHbsSVdnD9IyWTRf72fz1Hjf2z8xFdFsdugo/+0qzOwE77K4BkgukeIDwhAxmdIr5yo4w==

      at encrypt (utils/encryption.ts:33:11)

  console.log
    LROC3KIjXJVoQVawJYZUYqT7rhXC8enb6O9ipY9VnOFMilFM00NHGiF3FHJQLWqac5zWFFZg2ofygANqT7Y5rQRtePcUEM5bleuHvMaDdOAEXSdOK4PTbiCqZCAIPd79VVsW9gk2+vhKHbsq78AXhycCgUiOVjv25ooluDvqj3CQ+sTR+5cbatYO5kpXWwpu/BmPlRZYwsLUldpCuUPAYbkItKmQmiq/FWw1+z9Vx8mMKYhPtLuSTxnRrJ2Hn1eQm2EkuEeWQAEp+TJYaBsi93NalqmcWDo5swNe5HFPUH4hV7xtMtTZv82Wu9uNJ+ADUTD1B2mKDzKr0M0yNEYcGA==

      at encrypt (utils/encryption.ts:34:11)

起初我想知道我的 .env 中的多行私钥是否有问题,但我可以导出我的私钥和公钥(请参阅注释掉的代码),当我将它们注销时,它们看起来像我希望,我认为这意味着 keyObjects 正在成功创建。如果密钥没有成功创建,也许它每次都会创建新的密钥,这会导致这个失败?但据我所知,它们已成功创建。

我还阅读了 this answer,这表明 MacOS 上的 OpenSSL 实现可能存在问题 - 我使用的是 MacOs Big Sur,Node 14.16.0 (LTS)。所以,我 brew install openssl 然后链接它,现在我可以通过像这样检查来看到我使用的是 OpenSSL 而不是 LibreSSL;

➜  website git:(master) ✗ openssl version
OpenSSL 1.1.1j  16 Feb 2021

然而,这似乎并没有什么不同。

那么,如果输入相同,我该怎么做才能使 encrypt 函数可靠地返回相同的输出

编辑

我已将我的加密实用程序更新为以下内容并接受加密的结果会有所不同,因为它使用唯一的会话密钥和公钥进行加密,但是所有输出值都使用私有密钥正确解密键。

import { createPublicKey,publicEncrypt } from "crypto";

const privateKeyPem = process.env.ENCRYPTION_PRIVATE_KEY;
const privateKeyPemFixed = privateKeyPem.replace(/\\n/g,"\n");
const privateKey = createPrivateKey(privateKeyPemFixed);
const publicKey = createPublicKey(privateKey);

export const encrypt = (text: string): string => {
  const buffer = Buffer.from(text,"utf8");
  const encrypted = publicEncrypt(publicKey,buffer);
  return encrypted.toString("base64");
}

export const decrypt = (cipher: string): string => {
  const buffer = Buffer.from(cipher,"base64");
  const decrypted = privateDecrypt(privateKey,buffer);
  return decrypted.toString("utf8");
}

解决方法

事实证明,我对 crypto.PublicEncrypt 的假设是错误的。引用自 this answer

纯函数准则1:调用具有相同值的函数必须始终产生相同的返回值

在进行非对称加密时这是不可能的,因为每次操作都会生成一个随机会话密钥。会话密钥使用公钥加密,然后会话密钥用于加密负载。返回值通常只是两个值的编码版本:(1) 公钥加密的会话密钥,以及 (2) 会话密钥加密的有效负载。

每次调用函数时,这两个值都会不同,因为每次的会话密钥都会不同。

然而,尽管返回值比较不相等,但我认为它们在语义上是相等的——也就是说,如果你用匹配的私钥解密每个值,解密后的值将比较相等。

所以我更新了我的测试;

import { decrypt,encrypt } from "./encryption";

describe("encryption",() => {

  it("should encrypt and decrypt text",() => {
    const encrypted = encrypt("Hello World");
    const decrypted = decrypt(encrypted);
    expect(decrypted).toEqual("Hello World");
  });
});

现在可以使用了。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。