Nodejs下对zip文件加密解密后,在java端对该文件进行相同的加密解密

在日常开发中,我们经常需要对敏感数据或文件进行加密以保护其安全性。本文将介绍如何使用Node.jscrypto模块实现文件加密和解密的功能。

const fs = require('fs')
const path = require("path")

1. 加密文件

function encryptFile(sourceFilePath, targetEncryptedPath, password) {
    return new Promise((resolve, reject) => {
        const input = fs.createReadStream(sourceFilePath);
        const output = fs.createWriteStream(targetEncryptedPath);

        const algorithm = 'aes-256-cbc';

        // 从密码中生成加密密钥和初始化向量
        const key = crypto.scryptSync(password, 'salt', 32);
        const iv = Buffer.alloc(16, 0);

        const cipher = crypto.createCipheriv(algorithm, key, iv);

        input.pipe(cipher).pipe(output);

        output.on('finish', () => {
            resolve();
        });

        cipher.on('error', (err) => {
            reject(err);
        });
    });
}

在加密函数中,我们首先创建了一个读取流(input)和一个写入流(output),用于分别读取源文件和写入加密后的文件。然后,我们选择了一种对称加密算法(aes-256-cbc)来加密文件内容。

通过密码生成加密密钥和初始化向量,我们使用crypto.createCipheriv方法创建了一个加密器(cipher)。接着,我们通过管道将读取流连接到加密器上,再将加密器通过管道连接到写入流上。这样,读取流中的数据会经过加密器进行加密,并写入到目标文件中。

最后,我们通过监听写入流的finish事件来表示加密过程完成,并通过Promiseresolve方法返回结果。

2. 解密文件

function decryptFile(sourceEncryptedPath, targetDecryptedPath, password) {
    return new Promise((resolve, reject) => {
        const input = fs.createReadStream(sourceEncryptedPath);
        const output = fs.createWriteStream(targetDecryptedPath);

        const algorithm = 'aes-256-cbc';

        // 从密码中生成加密密钥和初始化向量
        const key = crypto.scryptSync(password, 'salt', 32);
        const iv = Buffer.alloc(16, 0);

        const decipher = crypto.createDecipheriv(algorithm, key, iv);

        input.pipe(decipher).pipe(output);

        output.on('finish', () => {
            resolve();
        });

        decipher.on('error', (err) => {
            reject(err);
        });
    });
}

解密函数的实现与加密函数类似。我们同样创建了一个读取流和一个写入流,用于分别读取加密文件和写入解密后的文件。然后,我们使用crypto.createDecipheriv方法创建了一个解密器(decipher),并将解密器通过管道连接到写入流上。

3. 使用示例

const sourceFilePath = '/path/to/source/file.zip';
const targetEncryptedPath = '/path/to/target/encrypted/file.zip';
const targetDecryptedPath = '/path/to/target/decrypted/file.zip';
const password = 'secretpassword';

encryptFile(sourceFilePath, targetEncryptedPath, password)
    .then(() => {
        console.log('文件加密完成');
        return decryptFile(targetEncryptedPath, targetDecryptedPath, password);
    })
    .then(() => {
        console.log('文件解密完成');
    })
    .catch((err) => {
        console.error('加密或解密过程出错:', err);
    });

在使用示例中,我们定义了源文件路径(sourceFilePath)、目标加密文件路径(targetEncryptedPath)、目标解密文件路径(targetDecryptedPath)和密码(password)。然后,我们调用encryptFile函数来加密源文件,并在加密完成后调用decryptFile函数来解密已加密的文件。

通过上述代码,我们可以实现对文件的加密和解密操作,保护敏感数据的安全性。唯一的缺点就是加密后如果不通过代码解密,使用压缩软件不能直接打开。

下面是使用java代码来对该zip文件进行加密解密原理相同,

1. 导入所需的依赖

首先,我们需要导入以下依赖,以使用SCryptAES算法相关的类和方法。

import org.bouncycastle.crypto.generators.SCrypt;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

2. 解密zip压缩包

下面是解密zip压缩包的方法实现。

public static void decryptFile(MultipartFile sourceEncryptedFile, String targetDecryptedPath, String password) {
    try {
        // scrypt参数
        byte[] salt = "salt".getBytes(StandardCharsets.UTF_8);
        int costParameter = 16384; // CPU cost parameter (N)
        int blockSize = 8; // Block size parameter (r)
        int parallelizationParameter = 1; // Parallelization parameter (p)
        int keyLength = 32; // 密钥长度

        // 使用scrypt生成密钥
        byte[] keyBytes = SCrypt.generate(password.getBytes(StandardCharsets.UTF_8), salt, costParameter, blockSize, parallelizationParameter, keyLength);
        SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");

        // 初始化向量
        byte[] iv = new byte[16]; // 默认全部是0

        // 将 MultipartFile 转换为临时文件
        File sourceEncryptedTempFile = File.createTempFile("source_encrypted", ".zip");
        sourceEncryptedFile.transferTo(sourceEncryptedTempFile);

        // 解密过程
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, new IvParameterSpec(iv));

        try (FileInputStream fileInputStream = new FileInputStream(sourceEncryptedTempFile);
             FileOutputStream fileOutputStream = new FileOutputStream(targetDecryptedPath)) {

            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = fileInputStream.read(buffer)) != -1) {
                fileOutputStream.write(cipher.update(buffer, 0, bytesRead));
            }
            fileOutputStream.write(cipher.doFinal());
        }

        // 删除临时文件
        sourceEncryptedTempFile.delete();
    } catch (Exception e) {
        e.printStackTrace();
    }
}

在解密方法中,我们首先定义了scrypt参数,包括saltcostParameterblockSizeparallelizationParameterkeyLength。使用这些参数,我们通过调用SCrypt.generate方法生成加密密钥。

然后,我们初始化向量iv为16个字节的0。接下来,我们将MultipartFile类型的加密文件转换为临时文件,并将其传输到临时文件中。

在解密过程中,我们使用AES算法的CBC模式和PKCS5Padding填充方式创建一个Cipher对象。通过调用cipher.init方法,我们将Cipher对象设置为解密模式,并传入加密密钥和初始化向量。

随后,我们使用FileInputStream读取加密文件,将解密后的数据写入到目标解密路径的FileOutputStream中。最后,我们通过调用cipher.doFinal方法来处理最后的数据块。

完成解密操作后,我们删除临时文件。

3. 加密zip压缩包

下面是加密zip压缩包的方法实现。

public static void encryptFile(String sourceFilePath, String targetEncryptedPath, String password, HttpServletResponse response) {
    try {
        // scrypt参数
        byte[] salt = "salt".getBytes(StandardCharsets.UTF_8);
        int costParameter = 16384; // CPU cost parameter (N)
        int blockSize = 8; // Block size parameter (r)
        int parallelizationParameter = 1; // Parallelization parameter (p)
        int keyLength = 32; // 密钥长度

        // 使用scrypt生成密钥
        byte[] keyBytes = SCrypt.generate(password.getBytes(StandardCharsets.UTF_8), salt, costParameter, blockSize, parallelizationParameter, keyLength);
        SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");

        // 初始化向量
        byte[] iv = new byte[16]; // 默认全部是0

        // 加密过程
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, new IvParameterSpec(iv));

        // 设置响应头
        response.setContentType("application/zip"); // 定义输出类型
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-Disposition", "attachment; filename=encrypted.zip");

        // 获取输出流
        ServletOutputStream out = response.getOutputStream();

        try (FileInputStream fileInputStream = new FileInputStream(sourceFilePath)) {
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = fileInputStream.read(buffer)) != -1) {
                byte[] encryptedBytes = cipher.update(buffer, 0, bytesRead);
                out.write(encryptedBytes);
            }
            byte[] finalEncryptedBytes = cipher.doFinal();
            out.write(finalEncryptedBytes);
        }

        out.flush();
        out.close();

    } catch (Exception e) {
        e.printStackTrace();
    }
}

在加密方法中,我们同样使用相同的scrypt参数和密钥生成方式来生成加密密钥。

然后,我们初始化向量iv为16个字节的0。接下来,我们使用AES算法的CBC模式和PKCS5Padding填充方式创建一个Cipher对象。通过调用cipher.init方法,我们将Cipher对象设置为加密模式,并传入加密密钥和初始化向量。

随后,我们设置响应头信息,包括内容类型、允许跨域访问、字符编码和附件文件名。

通过获取ServletOutputStream对象,我们可以将加密后的数据直接写入到HTTP响应中。

在加密过程中,我们使用FileInputStream读取源文件,并将加密后的数据通过调用out.write方法写入到输出流中。最后,我们通过调用cipher.doFinal方法来处理最后的数据块。

完成加密操作后,我们刷新输出流并关闭它。

4. 使用示例

下面是使用示例代码,演示了如何调用加密和解密方法。

MultipartFile sourceEncryptedFile = ...; // 从请求中获取加密文件
String targetDecryptedPath = ...; // 目标解密路径
String password = ...; // 密码

decryptFile(sourceEncryptedFile, targetDecryptedPath, password); // 解密操作

String sourceFilePath = ...; // 源文件路径
String targetEncryptedPath = ...; // 目标加密路径
String password = ...; // 密码
HttpServletResponse response = ...; // HTTP响应对象

encryptFile(sourceFilePath, targetEncryptedPath, password, response); // 加密操作

  • 24
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
RSA(Rivest-Shamir-Adleman)是一种非对称加密算法,它使用公钥和私钥来加密和解密数据。在Node.js中,我们可以使用`crypto`模块来实现RSA加密和解密。 首先,我们需要生成RSA密钥对。可以使用以下代码生成一个新的RSA密钥对: ```javascript const crypto = require('crypto'); const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', { modulusLength: 2048, publicKeyEncoding: { type: 'pkcs1', format: 'pem' }, privateKeyEncoding: { type: 'pkcs1', format: 'pem' } }); console.log('公钥:'); console.log(publicKey); console.log('私钥:'); console.log(privateKey); ``` 生成的公钥和私钥将以PEM格式显示。 接下来,我们可以使用生成的公钥进行加密,私钥进行解密。以下是一个示例: ```javascript const crypto = require('crypto'); // 加密 function encrypt(data, publicKey) { const buffer = Buffer.from(data, 'utf8'); const encrypted = crypto.publicEncrypt(publicKey, buffer); return encrypted.toString('base64'); } // 解密 function decrypt(encryptedData, privateKey) { const buffer = Buffer.from(encryptedData, 'base64'); const decrypted = crypto.privateDecrypt(privateKey, buffer); return decrypted.toString('utf8'); } // 使用示例 const plaintext = 'Hello, RSA!'; const encrypted = encrypt(plaintext, publicKey); console.log('加密后的数据:', encrypted); const decrypted = decrypt(encrypted, privateKey); console.log('解密后的数据:', decrypted); ``` 请注意,这只是一个基本示例,实际使用时可能需要处理更复杂的数据和错误处理。 希望这可以帮助到你!如有任何问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

沉浮yu大海

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值