Js和Java用CryptoJS.pad.Pkcs7、AES/CBC/PKCS7Padding 实现加解密数据(crypto 您所在的位置:网站首页 js和java Js和Java用CryptoJS.pad.Pkcs7、AES/CBC/PKCS7Padding 实现加解密数据(crypto

Js和Java用CryptoJS.pad.Pkcs7、AES/CBC/PKCS7Padding 实现加解密数据(crypto

2024-07-15 04:16| 来源: 网络整理| 查看: 265

        最近开发遇到个对接接口的需求,而这个接口是前端的Ajax直接调用的,接口前后有进行加解密的处理,使用的是CryptoJS,加密模式为:padding: CryptoJS.pad.Pkcs7

前端的加密方式为

Pre-request Script:

var reqeust_data = { "data": { "你的参数1": "***", "你的参数2": "***", "你的参数3": "***" }, "req_time":Date.parse(new Date()), // 请求时间戳 "request_string":randomString(32), // 32位随机字符串 } var aes_key = pm.request.getHeaders().AES_KEY; console.log("传入参数 -> " + JSON.stringify(reqeust_data)); var en_reqdata = AES_CBC_encrypt(JSON.stringify(reqeust_data), aes_key); pm.environment.set("params",en_reqdata); // {{params}} 为接口传入body的参数 //Generate 32-bit random string function randomString(len) {   len = len || 32;   var $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';   var maxPos = $chars.length;   var random_str = '';   for (i = 0; i < len; i++) {     pwd += $chars.charAt(Math.floor(Math.random() * maxPos));   }    return random_str; } //aes encode function AES_CBC_encrypt(message, key) { let keyHex = CryptoJS.enc.Hex.parse(key); // let ivHex = CryptoJS.enc.Utf8.parse("0000000000000000"); let messageHex = CryptoJS.enc.Utf8.parse(message); let encrypted = CryptoJS.AES.encrypt(messageHex, keyHex, { iv: ivHex, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); return encrypted.toString(); } //aes decode function decrypt(word, keyStr){ //console.log('decrypt key:' + keyStr); let keyHex = CryptoJS.enc.Hex.parse(keyStr); // let ivHex = CryptoJS.enc.Utf8.parse("0000000000000000"); let base64 = CryptoJS.enc.Base64.parse(word); let src = CryptoJS.enc.Base64.stringify(base64); var decrypt = CryptoJS.AES.decrypt(src, keyHex, { iv: ivHex, mode:CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); return decrypt.toString(CryptoJS.enc.Utf8); }

请求完的解密Js脚本

Tests:

var aes_key = pm.request.getHeaders().AES_KEY; var result = decrypt(responseBody, aes_key); console.log("返回信息明文 -> " + result); //aes decode function decrypt(word, keyStr){ //console.log('decrypt key:' + keyStr); let keyHex = CryptoJS.enc.Hex.parse(keyStr); // let ivHex = CryptoJS.enc.Utf8.parse("0000000000000000"); let base64 = CryptoJS.enc.Base64.parse(word); let src = CryptoJS.enc.Base64.stringify(base64); var decrypt = CryptoJS.AES.decrypt(src, keyHex, { iv: ivHex, mode:CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 }); return decrypt.toString(CryptoJS.enc.Utf8); }

        那么现在需要用Java实现这个加密再请求接口的话,我们可以用Hutool先实现一个工具类,以便我们调用。但是对于Js中的CryptoJS,padding: CryptoJS.pad.Pkcs7,则对应Java中AES的默认模式是:AES/ECB/PKCS7Padding。而恰好Hutool的枚举类没有这个模式:

 而在Hutool的issue里面恰好有人提出这个问题,原作者也做出了回应

 单使用Hutool,里面是没有这个加密算法的,所以需要配合BC库才能使用

首先需要在Maven中导入BC库:

org.bouncycastle bcprov-jdk15on 1.68

Java标准库的java.security包提供了一种标准机制,允许第三方提供商无缝接入。我们要使用BouncyCastle提供的AES/ECB/PKCS7Padding算法,需要先把BouncyCastle注册一下(有的需要有的不需要,能跑就行):

其中,注册BouncyCastle是通过下面的语句实现的:

Security.addProvider(new BouncyCastleProvider());

 然后就开始写我们的加密工具类

package com.psds.credit.data.utils; import cn.hutool.core.util.HexUtil; import cn.hutool.crypto.Mode; import cn.hutool.crypto.symmetric.AES; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.apache.commons.codec.binary.Base64; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; /** * @author JMzz * @description */ @Slf4j public class AESUtil { private static String AES_KEY = "你的密钥"; private static final String IV_KEY = "0000000000000000"; public static String encrypt(String message, String key, Mode mode, String padding) { byte[] baseKey = null; if (StringUtils.isNotEmpty(key)) { baseKey = HexUtil.decodeHex(key); } else { baseKey = HexUtil.decodeHex(AES_KEY); } byte[] ivBytes = IV_KEY.getBytes(StandardCharsets.UTF_8); byte[] messageBytes = message.getBytes(StandardCharsets.UTF_8); AES aes = new AES(mode.name(), padding, baseKey, ivBytes); return new Base64().encodeAsString(aes.encrypt(messageBytes)); } public static String decrypt(String message, String key, Mode mode, String padding) { byte[] baseKey = null; if (StringUtils.isNotEmpty(key)) { baseKey = HexUtil.decodeHex(key); } else { baseKey = HexUtil.decodeHex(AES_KEY); } byte[] ivBytes = IV_KEY.getBytes(StandardCharsets.UTF_8); AES aes = new AES(mode.name(), padding, baseKey, ivBytes); return aes.decryptStr(message); } // 不用HexUtil.decodeHex,也可以这个方法 private static byte[] hexStringToByteArray(String s) { int len = s.length(); byte[] data = new byte[len / 2]; for (int i = 0; i < len; i += 2) { data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) 0 ? len : 32; String chars = "ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678"; int maxPos = chars.length(); StringBuilder pwd = new StringBuilder(); for (int i = 0; i < len; i++) { pwd.append(chars.charAt((int) (Math.random() * maxPos))); } return pwd.toString(); } }

解密就把得到的response.body()拿来decrypt就可以了。

对于AES/CBC/PKCS7Padding和AES/CBC/PKCS5Padding 的区别:

        PKCS5Padding 是 PKCS7Padding 的子集,可以理解 PKCS5Padding 是 PKCS7Padding 的一种特定 block 下的情况,JDK 的 PKCS5Padding 实现是依照 PKCS7Padding 的标准来实现的,所以 Java 中在构建 Cipher 的时候使用 PKCS5Padding 和 PKCS7Padding 没有区别。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有