crypto 自己写的cipher加密chacha20-poly1305算法最优化增强性能,不用时间戳匹配

'use strict';
const crypto = require('crypto');

class Cipher {
    constructor(key) {
        this.key = Buffer.alloc(32);
        this.key.write(key);
        this.nonce = [undefined, undefined]; // [encryptNonce, decryptNonce]
        this.aad = [Buffer.alloc(16, 0xaa), Buffer.alloc(16, 0xaa)]; // [encryptAAD, decryptAAD]
    }

    encrypt(raw) {
        let cipher;
        if (this.nonce[0] === undefined) {
            // 生成完整的 12 字节 nonce
            this.nonce[0] = Buffer.alloc(12, 0x70);
            let sec = Math.floor(Date.now() / 1000);
            let rand = Math.floor((Math.random() - 0.5) * 10); // 减少随机偏移范围
            this.nonce[0].writeBigUInt64BE(BigInt(sec + rand)); // 前 8 字节为时间戳 + 随机偏移
            crypto.randomBytes(4).copy(this.nonce[0], 8); // 后 4 字节随机填充
        } else {
            // 后续加密,递增 nonce
            let n = this.nonce[0].readBigUInt64BE();
            n++;
            this.nonce[0].writeBigUInt64BE(n);
        }

        cipher = crypto.createCipheriv('chacha20-poly1305', this.key, this.nonce[0], { authTagLength: 16 });
        cipher.setAAD(this.aad[0]);

        let data = cipher.update(raw);
        cipher.final();
        let mac = cipher.getAuthTag();

        // 返回完整 nonce (12 字节) + 加密数据 + authTag
        return Buffer.concat([this.nonce[0], data, mac]);
    }

    decrypt(msg) {
        if (msg.length < 12 + 16) { // nonce(12) + authTag(16)
            throw new Error('message too short to decrypt.');
        }

        // 提取完整的 12 字节 nonce
        const nonce = msg.slice(0, 12);
        const data = msg.slice(12, -16);
        const mac = msg.slice(-16);

        let decipher;
        try {
            // 直接使用提取的 nonce
            decipher = crypto.createDecipheriv('chacha20-poly1305', this.key, nonce, { authTagLength: 16 });
            decipher.setAAD(this.aad[1]);
            let raw = decipher.update(data);
            decipher.setAuthTag(mac);
            decipher.final();

            // 更新解密 nonce 状态
            this.nonce[1] = nonce;
            return raw;
        } catch (e) {
            throw new Error('Failed to decrypt: invalid nonce or key.');
        }
    }
}

module.exports = Cipher;

动态 nonce 的作用
动态 nonce 的主要目的是确保每次加密时使用的 nonce 都是唯一的,从而防止重放攻击(replay attacks)和确保加密的随机性。在你的原始代码中,nonce 的前 8 字节是基于时间戳和随机偏移生成的,后 4 字节是随机填充的。

修改后的 nonce 逻辑
加密时:仍然生成动态 nonce(前 8 字节基于时间戳 + 随机偏移,后 4 字节随机填充)。

解密时:直接使用加密数据中传递的完整 nonce,不再需要时间戳猜测逻辑。

是否影响加密效果
安全性:修改后的代码仍然保持了动态 nonce 的唯一性和随机性,因此安全性没有降低。

重放攻击防护:由于 nonce 仍然是动态生成的,重放攻击的风险仍然被有效避免。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值