侧边栏壁纸
  • 累计撰写 14 篇文章
  • 累计创建 22 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

jdk1.8 和jdk17 加解密问题

Administrator
2024-03-28 / 0 评论 / 0 点赞 / 75 阅读 / 13234 字
# 前言

**用一个第三方之前提供加签验签操作  本操作在线上访问该接口 是可以  但是在本地迟迟不行  在同事其他人本地即可运行  **

一、排查法?

**把代码的加密参数 跟同事的一一对比 后面发现一样 只有环境不一样 怀疑环境问题 本人jdk 17环境 由于同事是1.8 环境 **

二、使用步骤

1.源代码

package cn.cws.framework.core.common.util;

import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;


/**
 * @Author zw
 * @create 2024/3/27 10:46
 * @Description 
 */
@Slf4j
public class DanglangSender {

    /**
     * 发送当郎短信
     * @param mobile 接收人手机号
     * @param smsTemplate 模板
     * @param smsTemplate 替换的内容
     * @return 成功或者失败
     */
    public static boolean send(String mobile,String smsTemplate, Object[] params) {
        String smsMessage = (params==null||params.length ==0)?smsTemplate:String.format(smsTemplate,params);
        String post = sendResult(mobile, smsMessage);
        JSONObject jsonObject = JSONObject.parseObject(post);
        String errorCode = jsonObject.getString("code");
        if(errorCode.equalsIgnoreCase("SUCCESS")){
            return true;
        }else{
            log.error("发送当郎短信失败->接收人:{}-内容:{}-返回数据:{}",mobile,smsMessage,post);
            return false;
        }
    }

    /**
     * 发送当郎短信
     * @param mobile 接收人手机号
     * @param content 内容
     * @return 返回数据自己解析判断
     */
    public static String sendResult(String mobile,String content) {
        String addr = ""; //替换自己addr
        String appId = "";//AppID
        String pwd = "";//密钥
        String sign = parseByte2HexStr(Objects.requireNonNull(encrypt(String.valueOf(System.currentTimeMillis()), pwd)));//生成签名


        List<MtSmsReqInfoDetail> mtSmsReqInfoDetailList = new ArrayList<>();

        for (int i = 0; i < 1; i++){
            MtSmsReqInfoDetail mtSmsReqInfoDetail = new MtSmsReqInfoDetail();
            mtSmsReqInfoDetail.setMobile(mobile);
//			mtSmsReqInfoDetail.setSchtime("2017-05-26 19:54:00");
            mtSmsReqInfoDetail.setCustomSmsId(String.valueOf(System.currentTimeMillis()));
//			mtSmsReqInfoDetail.setExtendedCode("901");
            mtSmsReqInfoDetail.setSmscontent(content);
            mtSmsReqInfoDetailList.add(mtSmsReqInfoDetail);
        }
        String s = JSON.toJSONString(mtSmsReqInfoDetailList);

        byte[] b = encrypt(s, pwd);//AES加密
        String smsData = parseByte2HexStr(b);
        String info = "appId="+appId+"&sign="+sign+"&smsData="+smsData;
        String post = HttpUtil.post(addr, info);
        log.info("发送当郎短信->接收人:{}-内容:{}-返回数据:{}",mobile,content,post);
        return post;
    }


    @Data
    public static class MtSmsReqInfoDetail{
        private String mobile;
        private String customSmsId;
        private String smscontent;
    }





    /**
     * 加密
     *
     * @param content
     *            需要加密的内容
     * @param password
     *            加密密码
     * @return
     */
    public static byte[] encrypt(String content, String password) {
        try {
            KeyGenerator kgen = KeyGenerator.getInstance("AES");
            String os = System.getProperty("os.name");
            if(os.toLowerCase().startsWith("win")){
                kgen.init(128, new SecureRandom(password.getBytes()));
            }else{
                SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG" );
                secureRandom.setSeed(password.getBytes());
                kgen.init(128, secureRandom);
            }
            SecretKey secretKey = kgen.generateKey();
            byte[] enCodeFormat = secretKey.getEncoded();
            SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
            Cipher cipher = Cipher.getInstance("AES");// 创建密码器
            byte[] byteContent = content.getBytes("utf-8");
            cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化
            byte[] result = cipher.doFinal(byteContent);
            return result; // 加密
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 解密
     *
     * @param content
     *            待解密内容
     * @param password
     *            解密密钥
     * @return
     */
    public static byte[] decrypt(byte[] content, String password) {
        try {
            KeyGenerator kgen = KeyGenerator.getInstance("AES");
            String os = System.getProperty("os.name");
            if(os.toLowerCase().startsWith("win")){
                kgen.init(128, new SecureRandom(password.getBytes()));
            }else{
                SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG" );
                secureRandom.setSeed(password.getBytes());
                kgen.init(128, secureRandom);
            }

            SecretKey secretKey = kgen.generateKey();
            byte[] enCodeFormat = secretKey.getEncoded();
            SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
            Cipher cipher = Cipher.getInstance("AES");// 创建密码器
            cipher.init(Cipher.DECRYPT_MODE, key);// 初始化
            byte[] result = cipher.doFinal(content);
            return result; // 加密
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将二进制转换成16进制
     *
     * @param buf
     * @return
     */
    public static String parseByte2HexStr(byte buf[]) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < buf.length; i++) {
            String hex = Integer.toHexString(buf[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            sb.append(hex.toUpperCase());
        }
        return sb.toString();
    }

    /**
     * 将16进制转换为二进制
     *
     * @param hexStr
     * @return
     */
    public static byte[] parseHexStr2Byte(String hexStr) {
        if (hexStr.length() < 1)
            return null;
        byte[] result = new byte[hexStr.length() / 2];
        for (int i = 0; i < hexStr.length() / 2; i++) {
            int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
            int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2),
                    16);
            result[i] = (byte) (high * 16 + low);
        }
        return result;
    }

}

2.通过debug 怀疑是自己的问题

代码如下(示例):

    /**
     * 加密
     *
     * @param content
     *            需要加密的内容
     * @param password
     *            加密密码
     * @return
     */
    public static byte[] encrypt(String content, String password) {
        try {
            KeyGenerator kgen = KeyGenerator.getInstance("AES");
            String os = System.getProperty("os.name");
            //怀疑这里的问题 
            if(os.toLowerCase().startsWith("win")){
                kgen.init(128, new SecureRandom(password.getBytes()));
            }else{
                SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG" );
                secureRandom.setSeed(password.getBytes());
                kgen.init(128, secureRandom);
            }
            SecretKey secretKey = kgen.generateKey();
            byte[] enCodeFormat = secretKey.getEncoded();
            SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
            Cipher cipher = Cipher.getInstance("AES");// 创建密码器
            byte[] byteContent = content.getBytes("utf-8");
            cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化
            byte[] result = cipher.doFinal(byteContent);
            return result; // 加密
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (NoSuchPaddingException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IllegalBlockSizeException e) {
            e.printStackTrace();
        } catch (BadPaddingException e) {
            e.printStackTrace();
        }
        return null;
    }

**由于该代码是第三方提供 以为是没有问题 所以没有过多关注 毕竟线上老项目已经可以运行了的 由于需要项目使用 本地测试不行 后 我用for 打印 **secretKey 发现每次 都会重新生成一次 secretKey 尝试打印该变量

JDK8环境运行

image-nmjw.png

JDK17环境运行

image-zgxq.png

可以看到JDK17两次生成的secretKey值不同

小结

** 那么问题的直接原因应该是JDK8时每次生成的secretKey都相同,而JDK17都不同,导致加密后解密失败**

3. 改为自己认为是这里的代码问题

/**
 * 加密
 *
 * @param content
 *            需要加密的内容
 * @param password
 *            加密密码
 * @return
 */
public static byte[] encrypt(String content, String password) {
    try {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG" );
        secureRandom.setSeed(password.getBytes());
        kgen.init(128, secureRandom);
        SecretKey secretKey = kgen.generateKey();
        byte[] enCodeFormat = secretKey.getEncoded();
        SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
        Cipher cipher = Cipher.getInstance("AES");// 创建密码器
        byte[] byteContent = content.getBytes("utf-8");
        cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化
        byte[] result = cipher.doFinal(byteContent);
        return result; // 加密
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (NoSuchPaddingException e) {
        e.printStackTrace();
    } catch (InvalidKeyException e) {
        e.printStackTrace();
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    } catch (IllegalBlockSizeException e) {
        e.printStackTrace();
    } catch (BadPaddingException e) {
        e.printStackTrace();
    }
    return null;
}

经过自己测试 发现完美可行


总结

** 那么问题的直接原因应该是JDK8时每次生成的secretKey都相同,而JDK17都不同,导致加密后 对方第三方 解密失败**

0
广告 广告

评论区