#788 批量修改所有使用字符串的getBytes方法的地方,显式使用utf-8编码,以免某些场景下出问题

This commit is contained in:
Binary Wang 2018-10-12 20:22:16 +08:00
parent ec5cc69abb
commit 34cea664ba
8 changed files with 72 additions and 73 deletions

View File

@ -1,12 +1,14 @@
package me.chanjar.weixin.common.util; package me.chanjar.weixin.common.util;
import lombok.extern.slf4j.Slf4j; import java.nio.charset.StandardCharsets;
import org.apache.commons.codec.binary.Hex;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException; import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Hex;
import lombok.extern.slf4j.Slf4j;
/** /**
* <pre> * <pre>
@ -27,9 +29,9 @@ public class SignUtils {
public static String createHmacSha256Sign(String message, String key) { public static String createHmacSha256Sign(String message, String key) {
try { try {
Mac sha256 = Mac.getInstance("HmacSHA256"); Mac sha256 = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(), "HmacSHA256"); SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
sha256.init(secretKeySpec); sha256.init(secretKeySpec);
byte[] bytes = sha256.doFinal(message.getBytes()); byte[] bytes = sha256.doFinal(message.getBytes(StandardCharsets.UTF_8));
return Hex.encodeHexString(bytes).toUpperCase(); return Hex.encodeHexString(bytes).toUpperCase();
} catch (NoSuchAlgorithmException | InvalidKeyException e) { } catch (NoSuchAlgorithmException | InvalidKeyException e) {
SignUtils.log.error(e.getMessage(), e); SignUtils.log.error(e.getMessage(), e);

View File

@ -1,22 +1,22 @@
/** /*
* 对公众平台发送给公众账号的消息加解密示例代码. * 对公众平台发送给公众账号的消息加解密示例代码.
* *
* @copyright Copyright (c) 1998-2014 Tencent Inc. * @copyright Copyright (c) 1998-2014 Tencent Inc.
*/ */
// ------------------------------------------------------------------------
package me.chanjar.weixin.common.util.crypto; package me.chanjar.weixin.common.util.crypto;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Arrays; import java.util.Arrays;
/** /**
* 提供基于PKCS7算法的加解 * 提供基于PKCS7算法的加解.
*
* @author tencent
*/ */
public class PKCS7Encoder { public class PKCS7Encoder {
private static final Charset CHARSET = StandardCharsets.UTF_8;
private static final Charset CHARSET = Charset.forName("utf-8");
private static final int BLOCK_SIZE = 32; private static final int BLOCK_SIZE = 32;
/** /**
@ -28,20 +28,17 @@ public class PKCS7Encoder {
public static byte[] encode(int count) { public static byte[] encode(int count) {
// 计算需要填充的位数 // 计算需要填充的位数
int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE); int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE);
if (amountToPad == 0) {
amountToPad = BLOCK_SIZE;
}
// 获得补位所用的字符 // 获得补位所用的字符
char padChr = chr(amountToPad); char padChr = chr(amountToPad);
String tmp = new String(); StringBuilder tmp = new StringBuilder();
for (int index = 0; index < amountToPad; index++) { for (int index = 0; index < amountToPad; index++) {
tmp += padChr; tmp.append(padChr);
} }
return tmp.getBytes(CHARSET); return tmp.toString().getBytes(CHARSET);
} }
/** /**
* 删除解密后明文的补位字符 * 删除解密后明文的补位字符.
* *
* @param decrypted 解密后的明文 * @param decrypted 解密后的明文
* @return 删除补位字符后的明文 * @return 删除补位字符后的明文
@ -55,12 +52,12 @@ public class PKCS7Encoder {
} }
/** /**
* 将数字转化成ASCII码对应的字符用于对明文进行补码 * 将数字转化成ASCII码对应的字符用于对明文进行补码.
* *
* @param a 需要转化的数字 * @param a 需要转化的数字
* @return 转化得到的字符 * @return 转化得到的字符
*/ */
public static char chr(int a) { private static char chr(int a) {
byte target = (byte) (a & 0xFF); byte target = (byte) (a & 0xFF);
return (char) target; return (char) target;
} }

View File

@ -1,21 +1,21 @@
package me.chanjar.weixin.common.util.crypto; package me.chanjar.weixin.common.util.crypto;
import org.apache.commons.codec.binary.Base64; import java.io.StringReader;
import org.w3c.dom.Document; import java.nio.charset.Charset;
import org.w3c.dom.Element; import java.nio.charset.StandardCharsets;
import org.xml.sax.InputSource; import java.util.Arrays;
import java.util.Random;
import javax.crypto.Cipher; import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.SecretKeySpec;
import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
import java.io.StringReader;
import java.nio.charset.Charset; import org.apache.commons.codec.binary.Base64;
import java.nio.charset.StandardCharsets; import org.w3c.dom.Document;
import java.util.Arrays; import org.w3c.dom.Element;
import java.util.Random; import org.xml.sax.InputSource;
/** /**
* <pre> * <pre>
@ -25,6 +25,8 @@ import java.util.Random;
* 需要导入架包commons-codec-1.9或commons-codec-1.8等其他版本 * 需要导入架包commons-codec-1.9或commons-codec-1.8等其他版本
* 官方下载地址http://commons.apache.org/proper/commons-codec/download_codec.cgi * 官方下载地址http://commons.apache.org/proper/commons-codec/download_codec.cgi
* </pre> * </pre>
*
* @author Tencent
*/ */
public class WxCryptUtil { public class WxCryptUtil {
@ -164,8 +166,7 @@ public class WxCryptUtil {
ByteGroup byteCollector = new ByteGroup(); ByteGroup byteCollector = new ByteGroup();
byte[] randomStringBytes = randomStr.getBytes(CHARSET); byte[] randomStringBytes = randomStr.getBytes(CHARSET);
byte[] plainTextBytes = plainText.getBytes(CHARSET); byte[] plainTextBytes = plainText.getBytes(CHARSET);
byte[] bytesOfSizeInNetworkOrder = number2BytesInNetworkOrder( byte[] bytesOfSizeInNetworkOrder = number2BytesInNetworkOrder(plainTextBytes.length);
plainTextBytes.length);
byte[] appIdBytes = this.appidOrCorpid.getBytes(CHARSET); byte[] appIdBytes = this.appidOrCorpid.getBytes(CHARSET);
// randomStr + networkBytesOrder + text + appid // randomStr + networkBytesOrder + text + appid
@ -252,7 +253,7 @@ public class WxCryptUtil {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
String xmlContent, from_appid; String xmlContent, fromAppid;
try { try {
// 去除补位字符 // 去除补位字符
byte[] bytes = PKCS7Encoder.decode(original); byte[] bytes = PKCS7Encoder.decode(original);
@ -264,14 +265,14 @@ public class WxCryptUtil {
xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength),
CHARSET); CHARSET);
from_appid = new String( fromAppid = new String(
Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length), CHARSET); Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length), CHARSET);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
// appid不相同的情况 // appid不相同的情况
if (!from_appid.equals(this.appidOrCorpid)) { if (!fromAppid.equals(this.appidOrCorpid)) {
throw new RuntimeException("AppID不正确"); throw new RuntimeException("AppID不正确");
} }

View File

@ -1,9 +1,9 @@
package me.chanjar.weixin.common.util.http; package me.chanjar.weixin.common.util.http;
import org.apache.commons.lang3.StringUtils; import java.nio.charset.StandardCharsets;
import java.io.UnsupportedEncodingException; import org.apache.commons.lang3.StringUtils;
public class URIUtil { public class URIUtil {
@ -16,27 +16,22 @@ public class URIUtil {
int l = input.length(); int l = input.length();
StringBuilder o = new StringBuilder(l * 3); StringBuilder o = new StringBuilder(l * 3);
try { for (int i = 0; i < l; i++) {
for (int i = 0; i < l; i++) { String e = input.substring(i, i + 1);
String e = input.substring(i, i + 1); if (!ALLOWED_CHARS.contains(e)) {
if (ALLOWED_CHARS.indexOf(e) == -1) { byte[] b = e.getBytes(StandardCharsets.UTF_8);
byte[] b = e.getBytes("utf-8"); o.append(getHex(b));
o.append(getHex(b)); continue;
continue;
}
o.append(e);
} }
return o.toString(); o.append(e);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} }
return input; return o.toString();
} }
private static String getHex(byte buf[]) { private static String getHex(byte[] buf) {
StringBuilder o = new StringBuilder(buf.length * 3); StringBuilder o = new StringBuilder(buf.length * 3);
for (int i = 0; i < buf.length; i++) { for (byte aBuf : buf) {
int n = buf[i] & 0xff; int n = aBuf & 0xff;
o.append("%"); o.append("%");
if (n < 0x10) { if (n < 0x10) {
o.append("0"); o.append("0");

View File

@ -1,6 +1,7 @@
package com.github.binarywang.wxpay.bean.notify; package com.github.binarywang.wxpay.bean.notify;
import java.io.Serializable; import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import javax.crypto.Cipher; import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec; import javax.crypto.spec.SecretKeySpec;
@ -48,7 +49,7 @@ public class WxPayRefundNotifyResult extends BaseWxPayResult implements Serializ
String reqInfoString = result.getReqInfoString(); String reqInfoString = result.getReqInfoString();
try { try {
final String keyMd5String = DigestUtils.md5Hex(mchKey).toLowerCase(); final String keyMd5String = DigestUtils.md5Hex(mchKey).toLowerCase();
SecretKeySpec key = new SecretKeySpec(keyMd5String.getBytes(), "AES"); SecretKeySpec key = new SecretKeySpec(keyMd5String.getBytes(StandardCharsets.UTF_8), "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key); cipher.init(Cipher.DECRYPT_MODE, key);

View File

@ -4,6 +4,7 @@ import java.io.ByteArrayInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.Serializable; import java.io.Serializable;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.DocumentBuilderFactory;
@ -192,7 +193,7 @@ public abstract class BaseWxPayResult implements Serializable {
this.xmlDoc = DocumentBuilderFactory this.xmlDoc = DocumentBuilderFactory
.newInstance() .newInstance()
.newDocumentBuilder() .newDocumentBuilder()
.parse(new ByteArrayInputStream(this.xmlString.getBytes("UTF-8"))); .parse(new ByteArrayInputStream(this.xmlString.getBytes(StandardCharsets.UTF_8)));
return xmlDoc; return xmlDoc;
} catch (SAXException | IOException | ParserConfigurationException e) { } catch (SAXException | IOException | ParserConfigurationException e) {
throw new RuntimeException("非法的xml文本内容" + this.xmlString); throw new RuntimeException("非法的xml文本内容" + this.xmlString);

View File

@ -3,6 +3,7 @@ package com.github.binarywang.wxpay.service.impl;
import java.io.File; import java.io.File;
import java.io.FileReader; import java.io.FileReader;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.security.PublicKey; import java.security.PublicKey;
@ -126,7 +127,7 @@ public class EntPayServiceImpl implements EntPayService {
.getPublicKey((SubjectPublicKeyInfo) reader.readObject()); .getPublicKey((SubjectPublicKeyInfo) reader.readObject());
cipher.init(Cipher.ENCRYPT_MODE, publicKey); cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encrypt = cipher.doFinal(srcString.getBytes()); byte[] encrypt = cipher.doFinal(srcString.getBytes(StandardCharsets.UTF_8));
return Base64.encodeBase64String(encrypt); return Base64.encodeBase64String(encrypt);
} }
} catch (Exception e) { } catch (Exception e) {
@ -138,7 +139,7 @@ public class EntPayServiceImpl implements EntPayService {
try { try {
String publicKeyStr = this.getPublicKey(); String publicKeyStr = this.getPublicKey();
Path tmpFile = Files.createTempFile("payToBank", ".pem"); Path tmpFile = Files.createTempFile("payToBank", ".pem");
Files.write(tmpFile, publicKeyStr.getBytes()); Files.write(tmpFile, publicKeyStr.getBytes(StandardCharsets.UTF_8));
return tmpFile.toFile(); return tmpFile.toFile();
} catch (Exception e) { } catch (Exception e) {
throw new WxPayException("生成加密公钥文件时发生异常", e); throw new WxPayException("生成加密公钥文件时发生异常", e);
@ -162,7 +163,7 @@ public class EntPayServiceImpl implements EntPayService {
"p7kM7BoaY2goFgYAe4DsI8Fh33dCOiKyVwIDAQAB\n" + "p7kM7BoaY2goFgYAe4DsI8Fh33dCOiKyVwIDAQAB\n" +
"-----END RSA PUBLIC KEY-----"; "-----END RSA PUBLIC KEY-----";
Path tmpFile = Files.createTempFile("payToBank", ".pem"); Path tmpFile = Files.createTempFile("payToBank", ".pem");
Files.write(tmpFile, key.getBytes()); Files.write(tmpFile, key.getBytes(StandardCharsets.UTF_8));
System.out.println(new EntPayServiceImpl(null).encryptRSA(tmpFile.toFile(), "111111")); System.out.println(new EntPayServiceImpl(null).encryptRSA(tmpFile.toFile(), "111111"));
} }

View File

@ -1,19 +1,20 @@
package com.github.binarywang.wxpay.bean.notify; package com.github.binarywang.wxpay.bean.notify;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import javax.inject.Inject;
import org.apache.commons.codec.binary.Base64;
import org.testng.annotations.*;
import com.github.binarywang.wxpay.config.WxPayConfig; import com.github.binarywang.wxpay.config.WxPayConfig;
import com.github.binarywang.wxpay.exception.WxPayException; import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.testbase.ApiTestModule; import com.github.binarywang.wxpay.testbase.ApiTestModule;
import org.apache.commons.codec.binary.Base64;
import org.testng.annotations.Guice;
import org.testng.annotations.Test;
import javax.crypto.Cipher; import static org.testng.Assert.*;
import javax.crypto.spec.SecretKeySpec;
import javax.inject.Inject;
import java.math.BigInteger;
import java.security.MessageDigest;
import static org.testng.Assert.assertNotNull;
/** /**
* <pre> * <pre>
@ -71,10 +72,10 @@ public class WxPayRefundNotifyResultTest {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
final MessageDigest md5 = MessageDigest.getInstance("MD5"); final MessageDigest md5 = MessageDigest.getInstance("MD5");
md5.update(this.wxPayConfig.getMchKey().getBytes()); md5.update(this.wxPayConfig.getMchKey().getBytes(StandardCharsets.UTF_8));
final String keyMd5String = new BigInteger(1, md5.digest()).toString(16).toLowerCase(); final String keyMd5String = new BigInteger(1, md5.digest()).toString(16).toLowerCase();
SecretKeySpec key = new SecretKeySpec(keyMd5String.getBytes(), "AES"); SecretKeySpec key = new SecretKeySpec(keyMd5String.getBytes(StandardCharsets.UTF_8), "AES");
cipher.init(Cipher.ENCRYPT_MODE, key); cipher.init(Cipher.ENCRYPT_MODE, key);
System.out.println(Base64.encodeBase64String(cipher.doFinal(xml.getBytes()))); System.out.println(Base64.encodeBase64String(cipher.doFinal(xml.getBytes(StandardCharsets.UTF_8))));
} }
} }