【发布时间】:2021-03-01 13:49:20
【问题描述】:
我正在尝试实现基本的非对称加密;一个服务有一个公钥并使用该公钥加密一个值,然后另一个服务接收加密的消息,使用私钥对其进行解码,并对解密的数据进行处理。
我遇到的问题是,每次我使用内置的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',
// 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");
}
我有一个看起来像这样的笑话测试;
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,节点 14.16.0 (LTS) 上。所以,我 brew install openssl 然后链接它,现在我可以通过这样的检查看到我使用的是 OpenSSL 而不是 LibreSSL;
➜ website git:(master) ✗ openssl version
OpenSSL 1.1.1j 16 Feb 2021
但这似乎并没有什么不同。
那么,在给定相同输入的情况下,如何使加密函数可靠地返回相同的输出?
编辑
我已将我的加密工具更新为以下内容,并接受加密结果会有所不同,因为它是使用唯一会话密钥和公钥加密的,但是所有输出值都使用私钥正确解密键。
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");
}
【问题讨论】:
-
对于您的加密,您使用的是“RSA_PKCS1_OAEP_PADDING”,它具有重要的安全性功能 - 它添加了一些随机数据,因此最后每个密文看起来不同,使用相同的密钥和输入.还有其他填充模式,例如 PKCS#1.5,但一些库将其标记为“已弃用”,因为它会生成在很多环境中不安全的确定性签名(每次运行看起来都一样)。
-
@MichaelFehr 谢谢你,这对我的理解很有用
标签: node.js encryption-asymmetric node-crypto