我有需要加密的crypto.randomBytes(30).toString("hex")
形式的文本。
下面是我使用的加密和解密算法。
import crypto from "crypto";
const ALGORITHM = "aes-256-ctr";
const IV_LENGTH = 16;
const ENCRYPTION_KEY = crypto.randomBytes(32);
export const encrypt = (text: string) => {
const iv = crypto.randomBytes(IV_LENGTH);
const cipher = crypto.createCipheriv(ALGORITHM, ENCRYPTION_KEY, iv);
const encryptedText = cipher.update(text, "utf8", "base64") + cipher.final("base64");
return `${iv.toString("hex")}:${encryptedText}`;
};
export const decrypt = (text: string) => {
const textParts = text.split(":");
const iv = Buffer.from(textParts.shift(), "hex");
const decipher = crypto.createDecipheriv(ALGORITHM, ENCRYPTION_KEY, iv);
const encryptedText = Buffer.from(textParts.join(":"), "base64");
return decipher.update(encryptedText, "base64", "utf8") + decipher.final("utf8");
};
我在终端中运行node
,并且能够在类似repl
的环境中使用这些功能。
当我处于该node
会话中时,会看到以下内容:
const encryptedText = encrypt("0e1819ff39ce47ec80488896a16520bc6b8fcd7d55dc918c96c61ff8e426")
// Output: "9fa7486458345eae2b46687a81a9fcf5:LOrlVD06eotggmIPAq0z9yzP/EHoeQyZyK6IiBYKZMIWvWYLekmSe73OjlgXdWJVOrcTyWS/eP3UU2yv"
const decryptedText = decrypt(encryptedText);
// Output: "0e1819ff39ce47ec80488896a16520bc6b8fcd7d55dc918c96c61ff8e426"
就像我想要的一样!
如果退出node
会话,然后打开一个新的node
会话并复制并粘贴以解密相同的字符串,则会得到以下信息:
const decryptedText = decrypt(ENCRYPTED_TEXT_FROM_ABOVE)
// Output: "�Z<�\r����S78V��z|Z\u0013��\u001a}�����@ߩ����Ɣh���*����y\b�\u001d���l'�m�'�"
为什么会这样?发生了什么变化?显然,节点似乎不再知道如何显示字符或其他内容。我不知道现在是什么编码。
之所以遇到此问题,是因为我将加密的数据存储在Postgres中,并且在检索时有时需要对其进行解密。由于某些原因,当我重新启动节点会话时,它会忘记如何读取它。
有趣的是,我可以在新的decrypt(encrypt("another string")) => "another string"
终端中使用node
,它可以工作,但是原来的字符串不再起作用。
解密步骤在这里失败,因为您正在为该行中的每个会话生成一个新密钥:
const ENCRYPTION_KEY = crypto.randomBytes(32);
如果您这样登录密钥:
console.log( { key: ENCRYPTION_KEY.toString("hex") });
您将看到每次运行的键都不相同。因此,我们无法解密先前会话中的加密数据是很有意义的!
如果更改为使用固定键:
const ENCRYPTION_KEY = Buffer.from("8b3d2068cf410479451eef41fe07d43e62ec80b962ae30cd99f7698499acfd61", "hex");
每个会话的输出应在下一个中解密。
当然,我们不想在代码中保留键,因此为此目的最好使用环境变量。