当前位置: 首页 > news >正文

Javascript使用Sodium库实现 aead_xchacha20poly1305_ietf加密解密,以及与后端的密文交互

Node.js环境安装 sodium-native (其他库可能会出现加密解密失败,如果要使用不一样的库,请自行验证)

npm install sodium-native

示例代码,使用的是 sodium-native v4.3.2 (其他版本可能会有变化,如果要使用,请自行验证)

const sodium = require('sodium-native');

(async () => {
    await sodium.ready;

    
    // 1. 要加密的消息
    const message = "Hello, world!";

    try {
        // 2. 将消息转换为 Uint8Array
        const messageBytes = new TextEncoder().encode(message);

        // 生成随机的密钥和 nonce
        const key = new Uint8Array(sodium.crypto_aead_xchacha20poly1305_ietf_KEYBYTES); /* 创建一个 32 字节的空Uint8Array : [
  0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0
]*/
        const nonce = new Uint8Array(sodium.crypto_aead_xchacha20poly1305_ietf_NPUBBYTES); /* 创建一个 24 字节的空Uint8Array: [
  0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0,
  0, 0, 0, 0, 0, 0, 0, 0
] */
        #实际开发中,key和nonce会指定,否则影响加密解密
        sodium.randombytes_buf(key); // 填充随机数据到 key
        sodium.randombytes_buf(nonce); // 填充随机数据到 nonce
        
        console.log("随机生成的密钥:", key);
        console.log("随机生成的 nonce:", nonce);

        // 创建一个足够大的缓冲区来存储加密后的数据和认证标签
        const ciphertext = new Uint8Array(messageBytes.length + sodium.crypto_aead_xchacha20poly1305_ietf_ABYTES);
        // 创建一个足够大的缓冲区来存储解密后的数据(不包括认证标签)
        const decrypted = new Uint8Array(ciphertext.length - sodium.crypto_aead_xchacha20poly1305_ietf_ABYTES);
        const additionalData = new Uint8Array(); // 可以为空,或者包含额外的认证数据

        // 3. 加密
        sodium.crypto_aead_xchacha20poly1305_ietf_encrypt(
            ciphertext, // 加密后的缓冲区
            messageBytes, // 将消息转换为 Uint8Array
            additionalData, // 附加数据(可选)
            null, // 附加数据的 nonce(可选)
            nonce, // 随机生成的 nonce
            key // 随机生成的密钥
        );

        // 输出加密相关信息
        console.log("加密后的密文:", ciphertext);

        // 4. 解密
        sodium.crypto_aead_xchacha20poly1305_ietf_decrypt(
            decrypted, // 解密后的缓冲区
            null, // 不需要预先分配空间
            ciphertext, // 密文
            additionalData, // 附加数据(可选)
            nonce, // 随机生成的 nonce
            key // 随机生成的密钥
        );

        if (decrypted) {
            // 解密成功
            const decryptedMessage = new TextDecoder().decode(decrypted);
            console.log("解密后的消息:", decryptedMessage);
        } else {
            console.log("解密失败");
        }
    } catch (error) {
        console.error("加密或解密过程中发生错误:", error);
    }
})();

加密解密正确可用,输出结果:

我们可以看到,在javascript里,无论是key,nonce,还是加密后的密文,都是十进制数组(Uint8Array),对应是typescript的Buffer类,这点我们可以通过查看加密方法的定义

然而在实际开发中,我们很多时候需要前端和后端进行密文的互相解密加密,这里有一些需要注意的地方。

以python为例,python实现加密解密的方法:

pip install pynacl
import nacl.bindings
from nacl.utils import random
import nacl.secret
 
key = random(nacl.bindings.crypto_aead_xchacha20poly1305_ietf_KEYBYTES)
#也可以是读取key文件获得key,比较常见的做法
# with open('/keyfile/key.cas-ie-key','rb') as file:
#         key = file.read()
decimal_array = [byte for byte in key]
print("随机生成的Key:", key)
nonce = random(nacl.bindings.crypto_aead_xchacha20poly1305_ietf_NPUBBYTES) #实际开发中,key和nonce会指定,否则影响加密解密
print("随机生成的nonce:", nonce)
 
message = b"Hello, world!"
 
ciphertext = nacl.bindings.crypto_aead_xchacha20poly1305_ietf_encrypt(message, None, nonce, key)
print("加密后的密文:",ciphertext)
print("解密后的明文:", nacl.bindings.crypto_aead_xchacha20poly1305_ietf_decrypt(ciphertext, None, nonce, key))

得到结果:

可以看到,python端的key,nonce,和密文,都是字节串bytes,调用方法时,也是传入的字节串参数。而javascript里则是十进制数组,调用方法时,也是传入的十进制数组参数(Uint8Array,对应typescript的Buffer)。

所以,python的密文在javascript端解密,javascript的密文在python端解密,是不能直接用对方的key,nonce,和密文的。

我们需要将字节串bytes和Unit8Array进行相互转换

从python端到javascript:

#在python端转换为十进制数组
decimal_array = [byte for byte in ciphertext]#key,nonce同理

#结果:[108, 13, 97, 116, 187, 108, 69, 252, 135, 246, 107, 42, 39, 176, 94, 232, 140, 247, 152, 2, 239, 29, 23, 172, 131, 254, 30, 77, 46]

javascript端转换为Uint8Array后再传入方法里:

const ciphertext = new Uint8Array([108, 13, 97, 116, 187, 108, 69, 252, 135, 246, 107, 42, 39, 176, 94, 232, 140, 247, 152, 2, 239, 29, 23, 172, 131, 254, 30, 77, 46])
#key,nonce同理

从javascript到python端:

#在python里直接把js的数组转换为字节串即可
#key,nonce同理
ciphertext = bytes(unint8array_from_js)

相关文章:

  • Web 自动化测试提速利器:Aqua 的 Web Inspector (检查器)使用详解
  • MySQL 选择数据库
  • SQL Server 创建用户并授权
  • 【算法基础】--前缀和
  • Spring全面讲解(无比详细)
  • [Android]DialogLifeCycle禁止点击背景关闭弹窗
  • 0099__Visual Studio 引入外部静态库与动态库
  • MySQL 插入更新语句(insert…on duplicate key update语句 )
  • VMware安装Centos 9虚拟机+设置共享文件夹+远程登录
  • 跳跃游戏(力扣55)
  • Python爬虫基础文件操作
  • 【OS安装与使用】part6-ubuntu 22.04+CUDA 12.4运行MARL算法(多智能体强化学习)
  • python学习
  • Jenkins整合Jmeter实现接口自动化测试
  • nacos编写瀚高数据库插件
  • 【Linux专栏】rsync 同步文件时自动创建目录
  • VMWare安装Debian操作系统
  • Could not download npm for node v14.21.3(nvm无法下载节点v14.21.3的npm)
  • HTTP 常见状态码技术解析(应用层)
  • Blender小技巧和注意事项
  • 韶关一企业将消防安装工程肢解发包,广东住建厅:罚款逾五万
  • “16+8”“生酮饮食”,网红减肥法究竟靠谱吗?
  • 商务部新闻发言人就暂停17家美国实体不可靠实体清单措施答记者问
  • 秦洪看盘|指标股发力,A股渐有突破态势
  • 落实中美经贸高层会谈重要共识,中方调整对美加征关税措施
  • 四部门:到2025年底,全国行政村5G通达率超过90%