解密的字符串在后续节点会话中未正确编码

Decrypted string is not encoded properly in subsequent Node sessions

我有 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 中,并且在检索它时,我有时需要对其进行解密。出于某种原因,当我重新启动节点会话时,它忘记了如何读取它。

有趣的是我可以在新的 node 终端中 decrypt(encrypt("another string")) => "another string" 并且它会工作,但原来的字符串不再工作了。

此处解密步骤失败,因为您正在为行中的每个会话生成新密钥:

const ENCRYPTION_KEY = crypto.randomBytes(32);

如果您像这样记录密钥:

console.log( { key: ENCRYPTION_KEY.toString("hex") });

您会看到每个 运行 的密钥都不同。因此,我们无法解密前一个会话的加密数据是有道理的!

如果改为使用固定密钥:

const ENCRYPTION_KEY = Buffer.from("8b3d2068cf410479451eef41fe07d43e62ec80b962ae30cd99f7698499acfd61", "hex");

每个会话的输出应该在下一个会话中解密。

当然我们不想在代码中留下密钥,因此最好为此目的使用环境变量。