我用的是Pino美元.我正在try 加密日志(log)流并将其写入文件.我可以实现这一点的一种方法是创建一个pipeline,在其中我可以转换数据并加密其内容,如下所示(效果很好):

import build from "pino-abstract-transport";
import { pipeline, Transform } from "node:stream";
import crypto from "node:crypto";

const ALGORITHM = "aes-256-ctr";

export default async function (options: { password: string }) {
  const password = Buffer.from(options.password, "hex");

  const iv = crypto.randomBytes(16);

  return build(function (source) {
    const myTransportStream = new Transform({
      autoDestroy: true,
      objectMode: true,
      transform(chunk, _enc, end) {
        const encrypt = crypto.createCipheriv(ALGORITHM, password, iv);
        const data = encrypt.update(JSON.stringify(chunk));
        const encrypted = Buffer.concat([data, encrypt.final()]);

        this.push(encrypted.toString("hex") + '\n');

        end();
      },
    });
    pipeline(source,  myTransportStream, () => {});
    return myTransportStream;
  }, {
    enablePipelining: true,
  });
}

我如何才能重用相同的const encrypt = crypto.createCipheriv(ALGORITHM, password, iv);个实例,而不是每次都创建一个新的实例?我是否通过进行这种重构获得了一些性能?

我试过这个:

import build from "pino-abstract-transport";
import { pipeline, Transform } from "node:stream";
import crypto from "node:crypto";

const ALGORITHM = "aes-256-ctr";

export default async function (options: { password: string }) {
  let initiated = false;
  const password = Buffer.from(options.password, "hex");

  const iv = crypto.randomBytes(16);

  const encrypt = crypto.createCipheriv(ALGORITHM, password, iv);
  return build(function (source) {
    const myTransportStream = new Transform({
      autoDestroy: true,
      objectMode: true,
      transform(chunk, _enc, end) {
        if (!initiated) {
          initiated = true;
          this.push(Buffer.concat([iv, chunk]));
        } else {
          this.push(chunk);
        }

        end();
      },
    });
    pipeline(source, encrypt, myTransportStream, () => {});
    return myTransportStream;
  }, {
    enablePipelining: true,
  });
}

但我得到了:

TypeError [ERR_INVALID_ARG_TYPE]: The "chunk" argument must be of type string or an instance of Buffer or Uint8Array. Received an instance of Object
    at new NodeError (node:internal/errors:372:5)
    at _write (node:internal/streams/writable:312:13)
    at Cipheriv.Writable.write (node:internal/streams/writable:334:10)
    at Transform.ondata (node:internal/streams/readable:754:22)
    at Transform.emit (node:events:527:28)
    at addChunk (node:internal/streams/readable:315:12)
    at readableAddChunk (node:internal/streams/readable:289:9)
    at Transform.Readable.push (node:internal/streams/readable:228:10)
    at push (/mnt/spare/ent/back/Plugin-Stix-Core-API/node_modules/split2/index.js:76:10)
    at Transform.transform [as _transform] (/mnt/spare/ent/back/Plugin-Stix-Core-API/node_modules/split2/index.js:44:7)
Emitted 'error' event on ThreadStream instance at:

不必担心微观优化,但如果您能够并且想要指出/提出论点,请随意这样做.

我使用的是Fastify的Pino配置,它基本上与Vanilla Pino包的配置相同:

    transport: {
      pipeline: [
        {
          target: "./transform-log.js",
          options: {
            password:
              "f8647d5417039b42c88a75897109049378cdfce528a7e015656bd23cd18fb78a",
          },
        },
        {
          target: "pino/file",
          options: {
            destination: file,
          },
        },
      ],
    },

推荐答案

我如何才能重用相同的const encrypt = crypto.createCipheriv(ALGORITHM, password, iv);个实例,而不是每次都创建一个新的实例?

你可以,也不应该.由于您需要指出IV,因此应该清楚该函数不是为了重用而创建的,因为对于每个消息,IV应该是不同的.

 this.push(Buffer.concat([iv, chunk]));

这肯定是错误的.对于CBC模式,您可以不受影响,但在CTR模式下,明文的每一位/字节都与内部创建的key stream进行异或运算.因此,明文/密文的每个位/字节都是完全独立的.这意味着,前缀IV在生成chunk的密文时不能处理anything.

我是否通过进行这种重构获得了一些性能?

不,这不太可能,也不太可能值得付出这样的努力.

它可能会略微提高性能,因为理论上不存在用于AES的第二个子密钥派生.然而,这是一个非常轻量级的操作.它还可以重复使用一些缓冲区,但AES也不需要大缓冲区.

IV需要是唯一的,因此您应该在每次运行创建的密码实例时创建一个新的IV.例如,对于CTR模式,使用某种序列号而不是随机可能更有效.不过,请注意,任何冲突will几乎完全 destruct 了您想要实现的任何保密性.

我强烈建议你只在两次手术之间保留 keys .

您也可以存储一个大的同步计数器来充当现时值,但请注意,保持这样的计数器同步是一个相当棘手的问题.由于这样的随机数通常是协议的一部分,例如消息计数器,所以在开始加密时提供IV,即作为参数而不是字段,仍然是更好的.

Javascript相关问答推荐

仅圆角的甜甜圈图表

Rehype将hashtag呈现为URL

使用useEffect,axios和useParams进行react测试

数字时钟在JavaScript中不动态更新

html + java script!需要帮助来了解为什么我得到(无效的用户名或密码)

显示图—如何在图例项上添加删除线效果?

为什么按钮会随浮动属性一起移动?

JS,当你点击卡片下方的绿色空间,而它是在它的背后转动时,

JS:XML insertBefore插入元素

Eval vs函数()返回语义

Vaadin定制组件-保持对javascrip变量的访问

将范围 Select 器添加到HighChart面积图

当我点击一个按钮后按回车键时,如何阻止它再次被点击

ngOnChanges仅在第二次调用时才触发

脚本语法错误只是一个字符串,而不是一个对象?

如何将对象推送到firestore数组?

将以前缓存的 Select 器与querySelector()一起使用

无法向甜甜圈图表上的ChartJSImage添加可见标签

将字符串解释为数字;将其重新编码为另一个基数

带元素数组的Mongo聚合