月度归档: 2022 年 11 月

  • 微信支付平台证书返回解密方法封装

    废话不多说,直接上代码:

    package com.isuidian.util;
    
    import java.io.IOException;
    import java.security.*;
    import java.util.Base64;
    
    import javax.crypto.Cipher;
    import javax.crypto.NoSuchPaddingException;
    import javax.crypto.spec.GCMParameterSpec;
    import javax.crypto.spec.SecretKeySpec;
    
    public class WechatStaticUtil {
    
        private static final int KEY_LENGTH_BYTE = 32;
        private static final int TAG_LENGTH_BIT = 128;
    
        public static String decryptToString(byte[] apiV3Key, byte[] associatedData, byte[] nonce, String ciphertext) throws GeneralSecurityException, IOException {
    
            if (apiV3Key.length != KEY_LENGTH_BYTE) {
                throw new IllegalArgumentException("无效的ApiV3Key,长度必须为32个字节");
            }
    
            try {
                Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
    
                SecretKeySpec key = new SecretKeySpec(apiV3Key, "AES");
                GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH_BIT, nonce);
                cipher.init(Cipher.DECRYPT_MODE, key, spec);
                cipher.updateAAD(associatedData);
    
                return new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), "utf-8");
            } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
                throw new IllegalStateException(e);
            } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
                throw new IllegalArgumentException(e);
            }
        }
    
    }
    

     

     

  • NoSuchMethodError kotlin.collections.ArraysKt.copyInto([B[BIII)[B

    查了网络资料,大概原因就是:springboot版本跟okhttp的jar包冲突,因此提示调用的方法没有。

    解决方法:

    方法一:(已验证)

    指定kotlib-stdlib的版本,在pom中加入如下依赖:

    <!-- https://mvnrepository.com/artifact/org.jetbrains.kotlin/kotlin-stdlib -->
    <dependency>
        <groupId>org.jetbrains.kotlin</groupId>
        <artifactId>kotlin-stdlib</artifactId>
        <version>1.3.70</version>
    </dependency>

    方法二:(未验证)

    把okhttp3的4.x版本改成3.x版本:

            <dependency>
                <groupId>com.squareup.okhttp3</groupId>
                <artifactId>okhttp</artifactId>
                <version>3.14.8</version>
            </dependency>

     

  • JDK的AES加密异常java.security.InvalidKeyException: Illegal key size 的解决方法

    今天在调用获取微信支付平台证书V3接口时,需要对其内容进行解密。根据官方的demo如下:

    static final int KEY_LENGTH_BYTE = 32;
    	static final int TAG_LENGTH_BIT = 128;
    
    	public String decryptToString(byte[] apiV3Key, byte[] associatedData, byte[] nonce, String ciphertext) throws GeneralSecurityException, IOException {
    
    		if (apiV3Key.length != KEY_LENGTH_BYTE) {
    			throw new IllegalArgumentException("无效的ApiV3Key,长度必须为32个字节");
    		}
    
    		try {
    			Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
    
    			SecretKeySpec key = new SecretKeySpec(apiV3Key, "AES");
    			GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH_BIT, nonce);
    
    			cipher.init(Cipher.DECRYPT_MODE, key, spec);
    			cipher.updateAAD(associatedData);
    
    			return new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), "utf-8");
    		} catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
    			throw new IllegalStateException(e);
    		} catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
    			throw new IllegalArgumentException(e);
    		}
    	}

    发现执行到 cipher.init(Cipher.DECRYPT_MODE, key, spec); 的时候报 java.security.InvalidKeyException: Illegal key size 错误。

    经过资料查阅,得出原因如下:

    JDK受版本安全限制,默认只允许128位长度以内的。秘钥长度,如果密钥大于128, 会抛出java.security.InvalidKeyException: Illegal key size 异常. java运行时环境默认读到的是受限的policy文件. 文件位于${java_home}/jre/lib/security, 这种限制是因为美国对软件出口的控制所造成的的.JDK1.8之后已经兼容了该问题。

    解决方案:

    方法一:升级不受限制JDK版本
    升级JDK9级以上版本,未测试

    方法二:替换JDK受限文件级配置
    JDK7的下载地址: Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files 7 Download
    JDK8的下载地址: JCE Unlimited Strength Jurisdiction Policy Files for JDK/JRE 8 Download
    下载后解压,可以看到local_policy.jar和US_export_policy.jar以及readme.txt
    如果安装了JRE,将两个jar文件放到%JRE_HOME%\lib\security目录下覆盖原来的文件
    如果安装了JDK,还要将两个jar文件也放到%JDK_HOME%\jre\lib\security目录下覆盖原来文件

    方法三:JDK1.8 代码策略修改
    JDK1.8 已经支持不受限的jar,但配置默认是受限的
    修改代码配置,在加密之前,修改不受限配置.

    WXBizMsgCrypt wxcpt = createWXBizMsgCrypt(suiteId, getCorpId(postData), false);
    Security.setProperty("crypto.policy", "unlimited");
    sMsg = wxcpt.decryptMsg(msgSignature, timestamp, nonce, postData);