简体   繁体   English

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

[英]node crypto.publicEncrypt returns different value each time it is used

I'm trying to implement basic asymmetric encryption;我正在尝试实现基本的非对称加密; one service has a public key and encrypts a value with that public key and then another service receives the encrypted message, decodes it using the private key, and does something with the decrypted data.一个服务有一个公钥并使用该公钥加密一个值,然后另一个服务接收加密的消息,使用私钥对其进行解码,并对解密的数据执行某些操作。

The problem that I'm having is that every time I use the in-built crypto.publicEncrypt method, I get a different encrypted value returned.我遇到的问题是,每次我使用内置的crypto.publicEncrypt方法时,都会返回一个不同的加密值。 As far as I can tell, I'm using the same inputs, so as I understand it I should be seeing the same output.据我所知,我使用的是相同的输入,所以据我所知,我应该看到相同的 output。 Perhaps I have misunderstood this?也许我误解了这一点?

Here is my encryption utility;这是我的加密实用程序;

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',
//   format: 'pem',
// }).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,
    oaepHash: 'sha256',
    padding: constants.RSA_PKCS1_OAEP_PADDING,
  }, 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");
}

I have a jest test which looks like this;我有一个看起来像这样的笑话测试;

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

However it constantly fails as the result always seems to be different.然而它总是失败,因为结果似乎总是不同的。

I ran the encryption process twice in the encrypt function, to demonstrate the problem;我在encrypt function 中运行了两次加密过程,以演示问题; the two values which it logs out are completely different and I don't understand why.它注销的两个值完全不同,我不明白为什么。

  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)

At first I wondered if there was a problem with my multiline private key in my .env , but I can export my private and public keys (see commented out code) and when I log them out, they look as I would expect, which I think means the keyObjects are being created successfully.起初我想知道我的.env中的多行私钥是否有问题,但我可以导出我的私钥和公钥(请参阅注释掉的代码),当我将它们注销时,它们看起来和我预期的一样,我think 表示keyObjects已成功创建。 If the keys were not created successfully, maybe it would create new keys each time and that would cause this failure?如果没有成功创建密钥,也许它每次都会创建新的密钥,这会导致失败? But as far as I can tell, they are created successfully.但据我所知,它们是成功创建的。

I also read this answer which suggested that there might be a problem with the OpenSSL implementation on MacOS - I'm on MacOs Big Sur, Node 14.16.0 (LTS).我还阅读了这个答案,这表明 MacOS 上的 OpenSSL 实现可能存在问题 - 我在 MacOs Big Sur,节点 14.16.0 (LTS) 上。 So, I brew install openssl and then linked it, and now I can see that I am using OpenSSL rather than LibreSSL by checking like so;所以,我brew install openssl然后链接它,现在我可以通过这样的检查看到我使用的是 OpenSSL 而不是 LibreSSL;

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

However that doesn't seem to have made a difference.然而,这似乎并没有什么不同。

So, what can I do to make the encrypt function reliably return the same output, given the same input?那么,在给定相同输入的情况下,我该怎么做才能使加密 function 可靠地返回相同的 output?

EDIT编辑

I've updated my encryption util to the following and accepted that the result of the encryption will be different because it is encrypted with a unique session key as well as the public key, however all the output values decrypt correctly with the private key.我已将我的加密工具更新为以下内容,并接受加密结果会有所不同,因为它是使用唯一的 session 密钥和公钥加密的,但是所有 output 值都使用私钥正确解密。

import { createPublicKey, createPrivateKey, privateDecrypt, 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");
}

It turns out that my assumptions about crypto.PublicEncrypt were incorrect.事实证明,我对crypto.PublicEncrypt的假设是不正确的。 To quote from this answer引用这个答案

Pure function criterion 1: Calling the function with the same values must always yield the same return value纯 function 标准 1:使用相同的值调用 function 必须始终产生相同的返回值

This is impossible when doing asymmetric encryption because a random session key is generated for each operation.这在进行非对称加密时是不可能的,因为每次操作都会生成一个随机的 session 密钥。 The session key is encrypted with the public key, and then the session key is used to encrypt the payload. session 密钥用公钥加密,然后 session 密钥用于加密有效载荷。 The returned value is usually just an encoded version of two values: (1) the pubkey-encrypted session key, and (2) the session key -encrypted payload.返回的值通常只是两个值的编码版本:(1) 公钥加密的 session 密钥,以及 (2) session 密钥加密的有效负载。

Both of these values are going to be different each time you call the function because the session key is going to be different each time.每次调用 function 时,这两个值都会不同,因为 session 键每次都会不同。

However, despite the return values not comparing as equal, I would argue that they are semantically equal -- that is, if you decrypt each value with the matching private key, the decrypted values will compare as equal.然而,尽管返回值不相等,但我认为它们在语义上是相等的——也就是说,如果你用匹配的私钥解密每个值,解密后的值将比较相等。

So I updated my test to;所以我将我的测试更新为;

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

And it's now working.现在它正在工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Nodejs crypto.publicEncrypt 在不同的机器上产生不同的结果 - Nodejs crypto.publicEncrypt yields different results on different machines Node.js crypto publicEncrypt 返回过长的值 - Node.js crypto publicEncrypt returns a too long value Node.js crypto.publicEncrypt:&#39;错误:错误:0906D06C:PEM例程:PEM_read_bio:无起始行&#39; - Node.js crypto.publicEncrypt: 'Error: error:0906D06C:PEM routines:PEM_read_bio:no start line' Nodejs `crypto.publicEncrypt` 不会使用 `ssh-keygen rsa` 生成的公钥 - Nodejs `crypto.publicEncrypt` would not take public key generated by `ssh-keygen rsa` 如何在客户端JavaScript中使用crypto js publicEncrypt和privateDecrypt? - How can use crypto js publicEncrypt and privateDecrypt in client side javascript? Node.js加密PBKDF2函数在v8与v10上返回不同的值 - Node.js crypto PBKDF2 function returns different values on v8 vs v10 使用 AES 时,Crypto-js 每次运行时都会返回不同的值 - Crypto-js returns different values every time it's run when using AES 节点JS加密符号返回空字符串 - Node js crypto sign returns empty string 节点加密HMAC返回 <SlowBuffer> 代替字符串 - Node crypto HMAC returns <SlowBuffer> instead of String crypto-js 输出与节点加密不同 - crypto-js output is different from node crypto
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM