diff --git a/weixin-java-miniapp/pom.xml b/weixin-java-miniapp/pom.xml index 7c0b2ce8..e8a0b9c6 100644 --- a/weixin-java-miniapp/pom.xml +++ b/weixin-java-miniapp/pom.xml @@ -70,6 +70,11 @@ redis.clients jedis + + org.bouncycastle + bcpkix-jdk15on + 1.59 + org.projectlombok lombok diff --git a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/crypt/WxMaCryptUtils.java b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/crypt/WxMaCryptUtils.java index e05bac5f..23ea851b 100644 --- a/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/crypt/WxMaCryptUtils.java +++ b/weixin-java-miniapp/src/main/java/cn/binarywang/wx/miniapp/util/crypt/WxMaCryptUtils.java @@ -1,19 +1,27 @@ package cn.binarywang.wx.miniapp.util.crypt; -import cn.binarywang.wx.miniapp.config.WxMaConfig; -import me.chanjar.weixin.common.util.crypto.PKCS7Encoder; -import org.apache.commons.codec.binary.Base64; - +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.security.AlgorithmParameters; +import java.security.Key; +import java.security.Security; +import java.util.Arrays; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; -import java.nio.charset.StandardCharsets; -import java.security.AlgorithmParameters; + +import org.apache.commons.codec.binary.Base64; +import org.bouncycastle.jce.provider.BouncyCastleProvider; + +import cn.binarywang.wx.miniapp.config.WxMaConfig; +import me.chanjar.weixin.common.util.crypto.PKCS7Encoder; /** * @author Binary Wang */ public class WxMaCryptUtils extends me.chanjar.weixin.common.util.crypto.WxCryptUtil { + private static final Charset UTF_8 = StandardCharsets.UTF_8; + public WxMaCryptUtils(WxMaConfig config) { this.appidOrCorpid = config.getAppid(); this.token = config.getToken(); @@ -21,8 +29,9 @@ public class WxMaCryptUtils extends me.chanjar.weixin.common.util.crypto.WxCrypt } /** - * AES解密 + * AES解密. * + * @param sessionKey session_key * @param encryptedData 消息密文 * @param ivStr iv字符串 */ @@ -34,9 +43,40 @@ public class WxMaCryptUtils extends me.chanjar.weixin.common.util.crypto.WxCrypt Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(Base64.decodeBase64(sessionKey), "AES"), params); - return new String(PKCS7Encoder.decode(cipher.doFinal(Base64.decodeBase64(encryptedData))), StandardCharsets.UTF_8); + return new String(PKCS7Encoder.decode(cipher.doFinal(Base64.decodeBase64(encryptedData))), UTF_8); + } catch (Exception e) { + throw new RuntimeException("AES解密失败!", e); + } + } + + + /** + * AES解密. + * + * @param sessionKey session_key + * @param encryptedData 消息密文 + * @param ivStr iv字符串 + */ + public static String decryptAnotherWay(String sessionKey, String encryptedData, String ivStr) { + byte[] keyBytes = Base64.decodeBase64(sessionKey.getBytes(UTF_8)); + + int base = 16; + if (keyBytes.length % base != 0) { + int groups = keyBytes.length / base + (keyBytes.length % base != 0 ? 1 : 0); + byte[] temp = new byte[groups * base]; + Arrays.fill(temp, (byte) 0); + System.arraycopy(keyBytes, 0, temp, 0, keyBytes.length); + keyBytes = temp; + } + + Security.addProvider(new BouncyCastleProvider()); + Key key = new SecretKeySpec(keyBytes, "AES"); + try { + Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC"); + cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(Base64.decodeBase64(ivStr.getBytes(UTF_8)))); + return new String(cipher.doFinal(Base64.decodeBase64(encryptedData.getBytes(UTF_8))), UTF_8); } catch (Exception e) { - throw new RuntimeException("AES解密失败", e); + throw new RuntimeException("AES解密失败!", e); } } diff --git a/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/util/crypt/WxMaCryptUtilsTest.java b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/util/crypt/WxMaCryptUtilsTest.java new file mode 100644 index 00000000..76b4e967 --- /dev/null +++ b/weixin-java-miniapp/src/test/java/cn/binarywang/wx/miniapp/util/crypt/WxMaCryptUtilsTest.java @@ -0,0 +1,35 @@ +package cn.binarywang.wx.miniapp.util.crypt; + + +import org.testng.annotations.*; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + *
+ *
+ * Created by Binary Wang on 2018/12/25.
+ * 
+ * + * @author Binary Wang + */ +public class WxMaCryptUtilsTest { + @Test + public void testDecrypt() { + String sessionKey = "7MG7jbTToVVRWRXVA885rg=="; + String encryptedData = "BY6VOgcWbwGcyrunK0ECWI8rnDsT69DucZ+M78tc1aL9aM/3bEAHFYd4fu7kRjWhD4YfjObw44T9vUqKyHIjbKs6hvtEasZZEIW35x4a91xVgN48ZqZ7MTQqUlP13kDUlkuwYh+/8g8yceu4kNbjowYrhihx+SV7CfjKCveJ7TSepr5Z7aLv1o+rfeelfOwn++WN/YoQsuZ6S3L4fWlWe5DAAUnFUI6cJvxxCohVzbrVXhyH2AqQdSjH2WnMYFeaGFIbcoxMznlk7oEwFn+hBj63dyT/swdYQfEdzuyCBmKXy8d6l1RKVX6Y65coTD8kIlbr+FKsqYrXVUIUBSwehqYuOdhYWZ9Bntl5DWU1oqzAPCnMn2cAIoQpQPKP7IGSxMOvCNAMhVXbE7BvnWuVuGF+AM5tXAa9IVUhcMImGwLQqm4iV5uBd+5OcFObh3A4VJk9iBCBWSkBHa/rV9CVoY0bFv2F9/2Hv82++Ybl274="; + String ivStr = "TarMFjnzHVxy8pdS93wQbw=="; + System.out.println(WxMaCryptUtils.decrypt(sessionKey, encryptedData, ivStr)); +// System.out.println(WxMaCryptUtils.decryptAnotherWay(sessionKey, encryptedData, ivStr)); + } + + @Test + public void testDecryptAnotherWay() { + String encryptedData = "CiyLU1Aw2KjvrjMdj8YKliAjtP4gsMZMQmRzooG2xrDcvSnxIMXFufNstNGTyaGS9uT5geRa0W4oTOb1WT7fJlAC+oNPdbB+3hVbJSRgv+4lGOETKUQz6OYStslQ142dNCuabNPGBzlooOmB231qMM85d2/fV6ChevvXvQP8Hkue1poOFtnEtpyxVLW1zAo6/1Xx1COxFvrc2d7UL/lmHInNlxuacJXwu0fjpXfz/YqYzBIBzD6WUfTIF9GRHpOn/Hz7saL8xz+W//FRAUid1OksQaQx4CMs8LOddcQhULW4ucetDf96JcR3g0gfRK4PC7E/r7Z6xNrXd2UIeorGj5Ef7b1pJAYB6Y5anaHqZ9J6nKEBvB4DnNLIVWSgARns/8wR2SiRS7MNACwTyrGvt9ts8p12PKFdlqYTopNHR1Vf7XjfhQlVsAJdNiKdYmYVoKlaRv85IfVunYzO0IKXsyl7JCUjCpoG20f0a04COwfneQAGGwd5oa+T8yO5hzuyDb/XcxxmK01EpqOyuxINew=="; + String ivStr = "r7BXXKkLb8qrSNn05n0qiA=="; + String sessionKey = "tiihtNczf5v6AKRyjwEUhQ=="; + + assertThat(WxMaCryptUtils.decrypt(sessionKey, encryptedData, ivStr)) + .isEqualTo(WxMaCryptUtils.decryptAnotherWay(sessionKey, encryptedData, ivStr)); + } +}