问题1:
NoSuchProviderException No such provider: BC?
原因:不能使用没有添加解密包,虽然import了Bouncy Castle,但是从来没有添加到使用到
解决方法:在security中添加provider
Security.addProvider(new BouncyCastleProvider());
问题2:
java.security.InvalidKeyException: Illegal key size or default parameters.
解决办法:因为原来的jce中的cipher类不支持PKCS7Padding,所以需要下载Java Cryptography Extension,并且覆盖jre中security中的两个文件。
官方下载地址
解决来源1
问题详解
问题3:
javax.crypto.BadPaddingException: pad block corrupted
at org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher$BufferedGenericBlockCipher.doFinal(Unknown Source)
at org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher.engineDoFinal(Unknown Source)
at javax.crypto.Cipher.doFinal(Cipher.java:2165)
at com.newlife.s4.util.AES256Util.wxInfoDecrypt(AES256Util.java:102)
at com.newlife.s4.util.AES256Util.main(AES256Util.java:119)
Disconnected from the target VM, address: '127.0.0.1:14544', transport: 'socket'
Process finished with exit code 0
错误可能:
(√)1.SecureRandom 产生随机数问题
原代码如下:
/**
* 解密步骤如下:
* (1)对加密串A做base64解码,得到加密串B
* (2)对商户key做md5,得到32位小写key* ( key设置路径:微信商户平台(pay.weixin.qq.com)-->账户设置-->API安全-->密钥设置 )
* (3)用key*对加密串B做AES-256-ECB解密(PKCS7Padding)
*
* @param keyStr (md5得到的字符串)
* @param content (解密内容)
* @return
*/
public static byte[] wxInfoDecrypt(String keyStr, byte[] content) throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, BadPaddingException, IllegalBlockSizeException, InvalidKeyException, UnsupportedEncodingException {
//通过md5得到的字符串,放入key生成器,生成key
SecureRandom secureRandom = new SecureRandom(keyStr.getBytes());
KeyGenerator keygen = KeyGenerator.getInstance("AES");
keygen.init(256, secureRandom);
SecretKey secretKey = keygen.generateKey();
//返回基本编码格式的密钥
byte[] enCodeFormat = secretKey.getEncoded();
//根据给定的字节数组构造一个密钥。enCodeFormat:密钥内容;"AES":与给定的密钥内容相关联的密钥算法的名称
SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
// SecretKeySpec key = new SecretKeySpec(keyStr.getBytes(), "AES");
//解密,添加BouncyCastle
Security.addProvider(new BouncyCastleProvider());
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decryptContent = cipher.doFinal(content);
//返回xml byte
return decryptContent;
}
修改后可运行代码:
public static byte[] wxInfoDecrypt(String keyStr, byte[] content) throws NoSuchAlgorithmException, NoSuchProviderException, NoSuchPaddingException, BadPaddingException, IllegalBlockSizeException, InvalidKeyException, UnsupportedEncodingException {
SecretKeySpec key = new SecretKeySpec(keyStr.getBytes(), "AES");
//解密,添加BouncyCastle
Security.addProvider(new BouncyCastleProvider());
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decryptContent = cipher.doFinal(content);
//返回xml byte
return decryptContent;
}
?????不太明白??????
(不详)2.多用户并发操作问题:https://blog.csdn.net/yszd2017/article/details/78422608
(×)3.解密内容长度问题:密钥有长度限制,但是内容并没有明确说明,应该是没有的,因为AES是对称分组编码,使用相同的密钥进行加密,然后将内容进行分组,再对每一组进行加密
(不详)4.As Yann Ramin said, using String is a failure for cipher in/output. This is binary data that
can contain 0x00
can contain values that are not defined or mapped to strange places in the encoding used
https://stackoverflow.com/questions/4560461/decryption-error-pad-block-corrupted
(×)5.编码问题 wx的是ISO-8859-1编码,我们正常的是utf-8编码
在微信社区看到用的都是utf-8编码
编码问题提问与非官方回答
官方回答,但是不知道是说签名还是解密
自己尝试时也不太明白
代码如下:
//本地使用的是utf-8编码,如果微信用的是iso-8859-1,那么粘贴过来使用的是哪种编码呢?
if (Arrays.equals(reqInfoStr.getBytes(StandardCharsets.ISO_8859_1), reqInfoStr.getBytes(StandardCharsets.UTF_8))){
System.out.println("ISO_8859_1 和 UTF_8 de Bytes相等");
}
//base64解码
byte[] reqInfoByte = java.util.Base64.getDecoder().decode(reqInfoStr.getBytes(StandardCharsets.ISO_8859_1));
byte[] reqInfoByteUtf8 = java.util.Base64.getDecoder().decode(reqInfoStr.getBytes(StandardCharsets.UTF_8));
if(Arrays.equals(reqInfoByte, reqInfoByteUtf8)){
System.out.println("Base64解码出来 ISO_8859_1 和 UTF_8 相等");
}
//apache 的md5返回的是全小写字符串,MD5Util是 全大写的
String md5Key = Objects.requireNonNull(MD5Util.MD5(mchKey)).toLowerCase();
String apacheMd5Key = Objects.requireNonNull(DigestUtils.md5Hex(mchKey));
if(md5Key.equals(apacheMd5Key)){
System.out.println("apacheMD5 he utilMD5 结果一致,除了大小写");
}
输出结果:
ISO_8859_1 和 UTF_8 de Bytes相等
Base64解码出来 ISO_8859_1 和 UTF_8 相等
apacheMD5 he utilMD5 结果一致,除了大小写
为什么呢?看一下ISO_8859_1 和 UTF_8的异同
UTF-8 is a multibyte encoding that can represent any Unicode character. ISO 8859-1 is a single-byte encoding that can represent the first 256 Unicode characters. Both encode ASCII exactly the same way.来源
UTF-8是不定长编码,ISO-8859-1是单字符编码,如果仅有字母或者数字,则一致?详解1 详解2
(×)6.MD5加密方式问题,如果使用apache的commons-codec就可以 问题提出来源
概念:一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。
密码散列函数(英语:Cryptographic hash function),又译为加密散列函数、密码散列函数、加密散列函数,是散列函数的一种。它被认为是一种单向函数,也就是说极其难以由散列函数输出的结果,回推输入的数据是什么。这样的单向函数被称为“现代密码学的驮马”。这种散列函数的输入数据,通常被称为消息(message),而它的输出结果,经常被称为消息摘要(message digest)或摘要(digest)。
所以md5就是对其做散列函数。并不算是加密算法
作用:像https、U盾等就是通过这样的机制保证数据的私密性和完整性,用来在公共网络中确认对方身份,确保数据在公共网络中不被人监听和篡改(即使别人截获了你的数据,他也不可能在短时间内破解;而且如果数据被篡改,通过哈希就可以发现)。 https://www.zhihu.com/question/19984234
md5具体加密过程:?????
网友评论