Node.js中AES加密和其它语言不一致问题解决办法

Node.js中AES加密与其他语言不一致问题解决办法

问题描述

在使用Node.js进行AES加密时,可能会出现与其他语言不一致的问题。主要表现为使用相同的密钥和明文,使用不同的语言加密后得到的密文不同。

原因分析

AES加密的过程中有很多细节需要注意,各种语言可能会实现不一样,导致加密结果不同。比如:

  • 不同语言的填充方式可能不同。
  • 不同语言的加密模式(ECB、CBC、CTR等)也可能不同。
  • 不同语言的密钥规定长度不同,可能需要进行特殊处理。

因此,需要在Node.js中使用AES加密时,确保各种细节与其他语言相同,才能保证加密结果的一致性。

解决办法

步骤一:选择加密模式和填充方式

在使用AES加密时,需要指定具体的加密模式和填充方式。这两者需要与其他使用的语言相同,才能保证加密结果的一致性。

以CBC模式和PKCS7填充方式为例,代码如下:

const crypto = require('crypto');
const algorithm = 'aes-128-cbc';   // 加密算法
const key = Buffer.from('0123456789abcdef0123456789abcdef', 'hex');  // 必须为16/24/32字节长度的字符串或Buffer
const iv = Buffer.from('0123456789abcdef', 'hex');  // 偏移量也必须为16字节
const plaintext = 'hello world';  // 待加密的明文

const cipher = crypto.createCipheriv(algorithm, key, iv);
cipher.update(plaintext, 'utf8');  // 输入编码为utf8
const ciphertext = cipher.final();

步骤二:密钥处理

在使用AES加密时,密钥需要特殊处理以保证正确加密。具体处理方式需要与其他使用的语言相同。

以Java为例,Java默认将字符串转为UTF-16的字节数组再进行加密。因此,在Node.js中进行加密时,也需要将密钥转为相同的编码形式。代码如下:

// 将密钥转为16进制表示的字符串
const keyStr = '0123456789abcdef0123456789abcdef';
// 将16进制字符串转为Buffer
const key = Buffer.from(keyStr, 'hex');

// 将字符串按照UTF-16解码为UCS-2编码的Buffer
const keyUCS2 = Buffer.from(keyStr, 'utf16le');
// 将UCS-2编码的Buffer转为UTF-8编码的Buffer
const keyUTF8 = iconv.encode(iconv.decode(keyUCS2, 'ucs2'), 'utf8');

步骤三:加密数据

进行加密时,需要保证加密数据的编码方式与其他使用的语言相同。一般来说,都采用UTF-8或ASCII编码。

以Java为例,Java默认使用UTF-8编码。因此,Node.js中的加密数据也需要采用UTF-8编码。代码如下:

const plaintext = 'hello world';  // 待加密的明文
const plaintextBuffer = Buffer.from(plaintext, 'utf8');

示例说明

示例一

假设有以下Java代码:

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;

public class Example {

    public static String encrypt(String plaintext, String key) throws Exception {
        byte[] plaintextBytes = plaintext.getBytes("UTF-8");
        byte[] keyBytes = key.getBytes("UTF-8");
        byte[] ivBytes = new byte[16];
        SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
        IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
        byte[] ciphertextBytes = cipher.doFinal(plaintextBytes);
        return Base64.getEncoder().encodeToString(ciphertextBytes);
    }

    public static void main(String[] args) throws Exception {
        String plaintext = "hello world";
        String key = "0123456789abcdef0123456789abcdef";
        String ciphertext = encrypt(plaintext, key);
        System.out.println(ciphertext);
    }
}

该代码将使用AES/CBC/PKCS5Padding模式对"hello world"进行加密,并输出加密结果。其中密钥为"0123456789abcdef0123456789abcdef"。

在Node.js中进行加密,可以使用以下代码:

const crypto = require('crypto');
const algorithm = 'aes-128-cbc';
const keyStr = '0123456789abcdef0123456789abcdef';
const iv = Buffer.alloc(16);
const plaintext = 'hello world';

const keyBuffer = Buffer.from(keyStr, 'hex');

// 将密钥从UTF-8转换为UTF-16BE,然后转换为Buffer
const keyUCS2 = Buffer.from(keyStr, 'utf16le');
const keyBufferFromUCS2 = Buffer.from(keyUCS2.toString('hex'), 'hex');

const cipher = crypto.createCipheriv(algorithm, keyBufferFromUCS2, iv);
cipher.update(plaintext, 'utf8');
const ciphertext = cipher.final().toString('base64');

console.log(ciphertext);

该代码与Java代码使用相同的加密模式和填充方式,将密钥从UTF-8转换为UTF-16BE,采用UTF-8编码明文,最终输出相同的加密结果。

示例二

假设有以下Python代码:

import base64
from Crypto.Cipher import AES

def pkcs7_padding(data):
    padding_len = 16 - len(data) % 16
    padding = bytes([padding_len] * padding_len)
    return data + padding

def encrypt(plaintext, key):
    plaintext_bytes = plaintext.encode('utf-8')
    key_bytes = key.encode('utf-8')
    iv = b'\x00' * 16
    cipher = AES.new(key_bytes, AES.MODE_CBC, iv)
    plaintext_padded = pkcs7_padding(plaintext_bytes)
    ciphertext_bytes = cipher.encrypt(plaintext_padded)
    return base64.b64encode(ciphertext_bytes).decode('utf-8')

def main():
    plaintext = 'hello world'
    key = '0123456789abcdef0123456789abcdef'
    ciphertext = encrypt(plaintext, key)
    print(ciphertext)

if __name__ == '__main__':
    main()

该代码使用Python的Crypto库,使用AES/CBC/PKCS7Padding模式对"hello world"进行加密,并输出加密结果。其中密钥为"0123456789abcdef0123456789abcdef"。

在Node.js中进行加密,可以使用以下代码:

const crypto = require('crypto');
const algorithm = 'aes-128-cbc';
const keyStr = '0123456789abcdef0123456789abcdef';
const iv = Buffer.alloc(16);
const plaintext = 'hello world';

const keyBuffer = Buffer.from(keyStr, 'hex');

// 将密钥从UTF-8转换为UTF-16BE,然后转换为Buffer
const keyUCS2 = Buffer.from(keyStr, 'utf16le');
const keyBufferFromUCS2 = Buffer.from(keyUCS2.toString('hex'), 'hex');

const cipher = crypto.createCipheriv(algorithm, keyBufferFromUCS2, iv);
cipher.setAutoPadding(false);
const plaintextBuffer = Buffer.from(plaintext, 'utf8');
const padding = 16 - plaintextBuffer.length % 16;
const paddingBuffer = Buffer.alloc(padding, padding);
const plaintextPadded = Buffer.concat([plaintextBuffer, paddingBuffer]);
const ciphertextBuffer = Buffer.concat([cipher.update(plaintextPadded), cipher.final()]);
const ciphertext = ciphertextBuffer.toString('base64');

console.log(ciphertext);

该代码与Python代码使用相同的加密模式和填充方式,将密钥从UTF-8转换为UTF-16BE,采用UTF-8编码明文,最终输出相同的加密结果。

总结

在使用Node.js进行AES加密时,需要注意以下几个方面以保证与其他语言的一致性:

  • 选择正确的加密模式和填充方式。
  • 对密钥进行特殊处理以保证一致性。
  • 使用相同的编码方式处理明文和密文。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Node.js中AES加密和其它语言不一致问题解决办法 - Python技术站

(0)
上一篇 2023年6月8日
下一篇 2023年6月8日

相关文章

  • 轻松创建nodejs服务器(10):处理上传图片

    让我来详细讲解如何在Node.js服务器中处理上传图片。这里我将分为以下几个步骤: 添加multer中间件 编写上传文件的处理函数 将上传的图片文件存储到本地 返回上传后的图片信息 以下是详细的说明: 1. 添加multer中间件 首先需要安装和添加multer中间件,它是用于处理文件上传的Node.js中间件。 通过以下命令来安装multer: npm i…

    node js 2023年6月8日
    00
  • JS异步错误捕获的一些事小结

    JS异步错误捕获的一些事小结 背景 随着前端项目逐渐变大、代码逐渐复杂,异步错误的捕获成为前端开发中的难点之一。本文将结合实际应用场景,介绍JS异步错误捕获的一些事情。 具体内容 Promise Promise的错误捕获是一个重要的部分,一般来说我们需要用到 then() 中的第二个参数来进行错误捕获。示例代码如下: fetch(‘http://exampl…

    node js 2023年6月8日
    00
  • nodejs实现超简单生成二维码的方法

    下面是详细的“nodejs实现超简单生成二维码的方法”的攻略。 1. 安装依赖 首先,我们需要安装两个npm包:qrcode和fs。qrcode用于生成二维码,fs用于读写文件。 可以使用以下命令安装: npm install qrcode fs –save 2. 创建一个生成二维码的函数 我们可以创建一个函数 generateQRCode 来生成二维码。…

    node js 2023年6月8日
    00
  • 基于Node.js实现压缩和解压缩的方法

    基于Node.js实现压缩和解压缩的方法有很多种,常见的有使用zlib和tar模块,下面将分别详细介绍。 使用zlib模块 安装zlib模块 在命令行中输入以下命令安装zlib模块: npm install zlib 压缩文件 使用以下代码将文件进行压缩: const fs = require(‘fs’); const zlib = require(‘zli…

    node js 2023年6月8日
    00
  • Node登录权限验证token验证实现的方法示例

    Node登录权限验证token验证是一种常用的用户认证方式。下面是实现这种验证的方法示例: 1. 生成Token 在编写代码之前,需要首先使用node.js的jsonwebtoken模块生成一个Token字符串。示例代码如下: const jwt = require(‘jsonwebtoken’); // 生成Token的函数 function genera…

    node js 2023年6月8日
    00
  • 关于JSON解析中获取不存在的key问题

    在JSON解析中,如果试图获取一个不存在的key,会导致程序抛出异常。为了处理这种情况,需要添加相应的逻辑来处理异常。 以下是一些处理不存在key的示例: 示例一:使用try-except处理KeyError异常 在Python中,获取一个不存在的key会引发一个KeyError异常,我们可以使用try-except语句来捕获这个异常,例如: import …

    node js 2023年6月8日
    00
  • 在Debian(Raspberry Pi)树莓派上安装NodeJS的教程详解

    当在Debian (Raspberry Pi)上安装NodeJS时,我们需要按照以下步骤进行操作: 步骤1:更新系统 在安装任何新软件之前,请确保更新您的系统。为此,请打开终端并输入以下命令: sudo apt-get update sudo apt-get upgrade 步骤2:安装NodeJS 可以通过以下任意一种方法来安装NodeJS: 方法1:通过…

    node js 2023年6月8日
    00
  • JS中自定义定时器让它在某一时刻执行

    JS中自定义定时器在某一时刻执行是通过setTimeout()函数或setInterval()函数实现的。下面将详细介绍这两个函数的用法。 1. setTimeout() setTimeout()函数是JS中的全局函数,用于在指定的时间后执行一个函数或一段代码。其语法如下: setTimeout(function, milliseconds, arg1, a…

    node js 2023年6月8日
    00
合作推广
合作推广
分享本页
返回顶部