Exemple #1
0
  /**
   * 对xml消息加密
   *
   * @param appId 应用ID
   * @param encodingAesKey 加密密钥
   * @param xmlContent 原始消息体
   * @return aes加密后的消息体
   * @throws WeixinException
   */
  public static String aesEncrypt(String appId, String encodingAesKey, String xmlContent)
      throws WeixinException {
    byte[] randomBytes = StringUtil.getBytesUtf8(RandomUtil.generateString(32));
    byte[] xmlBytes = StringUtil.getBytesUtf8(xmlContent);
    int xmlLength = xmlBytes.length;
    byte[] orderBytes = new byte[4];
    orderBytes[3] = (byte) (xmlLength & 0xFF);
    orderBytes[2] = (byte) (xmlLength >> 8 & 0xFF);
    orderBytes[1] = (byte) (xmlLength >> 16 & 0xFF);
    orderBytes[0] = (byte) (xmlLength >> 24 & 0xFF);
    byte[] appidBytes = StringUtil.getBytesUtf8(appId);

    int byteLength = randomBytes.length + xmlLength + orderBytes.length + appidBytes.length;
    // ... + pad: 使用自定义的填充方式对明文进行补位填充
    byte[] padBytes = PKCS7Encoder.encode(byteLength);
    // random + endian + xml + appid + pad 获得最终的字节流
    byte[] unencrypted = new byte[byteLength + padBytes.length];
    byteLength = 0;
    // src:源数组;srcPos:源数组要复制的起始位置;dest:目的数组;destPos:目的数组放置的起始位置;length:复制的长度
    System.arraycopy(randomBytes, 0, unencrypted, byteLength, randomBytes.length);
    byteLength += randomBytes.length;
    System.arraycopy(orderBytes, 0, unencrypted, byteLength, orderBytes.length);
    byteLength += orderBytes.length;
    System.arraycopy(xmlBytes, 0, unencrypted, byteLength, xmlBytes.length);
    byteLength += xmlBytes.length;
    System.arraycopy(appidBytes, 0, unencrypted, byteLength, appidBytes.length);
    byteLength += appidBytes.length;
    System.arraycopy(padBytes, 0, unencrypted, byteLength, padBytes.length);
    try {
      byte[] aesKey = Base64.decodeBase64(encodingAesKey + "=");
      // 设置加密模式为AES的CBC模式
      Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
      SecretKeySpec keySpec = new SecretKeySpec(aesKey, Consts.AES);
      IvParameterSpec iv = new IvParameterSpec(aesKey, 0, 16);
      cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
      // 加密
      byte[] encrypted = cipher.doFinal(unencrypted);
      // 使用BASE64对加密后的字符串进行编码
      return Base64.encodeBase64String(encrypted);
    } catch (Exception e) {
      throw new WeixinException("-40006", "AES加密失败:" + e.getMessage());
    }
  }
Exemple #2
0
  /**
   * 对密文进行解密.
   *
   * @param text 需要解密的密文
   * @return 解密得到的明文
   * @throws AesException aes解密失败
   */
  String decrypt(String text) throws AesException {
    byte[] original;
    try {
      // 设置解密模式为AES的CBC模式
      Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
      SecretKeySpec key_spec = new SecretKeySpec(aesKey, "AES");
      IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16));
      cipher.init(Cipher.DECRYPT_MODE, key_spec, iv);

      // 使用BASE64对密文进行解码
      byte[] encrypted = Base64.decodeBase64(text);

      // 解密
      original = cipher.doFinal(encrypted);
    } catch (Exception e) {
      e.printStackTrace();
      throw new AesException(AesException.DecryptAESError);
    }

    String xmlContent, from_appid;
    try {
      // 去除补位字符
      byte[] bytes = PKCS7Encoder.decode(original);

      // 分离16位随机字符串,网络字节序和AppId
      byte[] networkOrder = Arrays.copyOfRange(bytes, 16, 20);

      int xmlLength = recoverNetworkBytesOrder(networkOrder);

      xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), CHARSET);
      from_appid = new String(Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length), CHARSET);
    } catch (Exception e) {
      e.printStackTrace();
      throw new AesException(AesException.IllegalBuffer);
    }

    // appid不相同的情况
    if (!from_appid.equals(appId)) {
      throw new AesException(AesException.ValidateAppidError);
    }
    return xmlContent;
  }
Exemple #3
0
 /**
  * 对AES消息解密
  *
  * @param appId
  * @param encodingAesKey aes加密的密钥
  * @param encryptContent 加密的消息体
  * @return 解密后的字符
  * @throws WeixinException
  */
 public static String aesDecrypt(String appId, String encodingAesKey, String encryptContent)
     throws WeixinException {
   byte[] aesKey = Base64.decodeBase64(encodingAesKey + "=");
   byte[] original;
   try {
     // 设置解密模式为AES的CBC模式
     Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
     SecretKeySpec key_spec = new SecretKeySpec(aesKey, Consts.AES);
     IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16));
     cipher.init(Cipher.DECRYPT_MODE, key_spec, iv);
     // 使用BASE64对密文进行解码
     byte[] encrypted = Base64.decodeBase64(encryptContent);
     // 解密
     original = cipher.doFinal(encrypted);
   } catch (Exception e) {
     throw new WeixinException("-40007", "AES解密失败" + e.getMessage());
   }
   String xmlContent, fromAppId;
   try {
     // 去除补位字符
     byte[] bytes = PKCS7Encoder.decode(original);
     // 获取表示xml长度的字节数组
     byte[] lengthByte = Arrays.copyOfRange(bytes, 16, 20);
     // 获取xml消息主体的长度(byte[]2int)
     // http://my.oschina.net/u/169390/blog/97495
     int xmlLength =
         lengthByte[3] & 0xff
             | (lengthByte[2] & 0xff) << 8
             | (lengthByte[1] & 0xff) << 16
             | (lengthByte[0] & 0xff) << 24;
     xmlContent = StringUtil.newStringUtf8(Arrays.copyOfRange(bytes, 20, 20 + xmlLength));
     fromAppId = StringUtil.newStringUtf8(Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length));
   } catch (Exception e) {
     throw new WeixinException("-40008", "xml内容不合法" + e.getMessage());
   }
   // 校验appId是否一致
   if (!fromAppId.trim().equals(appId)) {
     throw new WeixinException(
         "-40005", "校验AppID失败,expect " + appId + ",but actual is " + fromAppId);
   }
   return xmlContent;
 }
Exemple #4
0
  /**
   * 对明文进行加密.
   *
   * @param text 需要加密的明文
   * @return 加密后base64编码的字符串
   * @throws AesException aes加密失败
   */
  String encrypt(String randomStr, String text) throws AesException {
    ByteGroup byteCollector = new ByteGroup();
    byte[] randomStrBytes = randomStr.getBytes(CHARSET);
    byte[] textBytes = text.getBytes(CHARSET);
    byte[] networkBytesOrder = getNetworkBytesOrder(textBytes.length);
    byte[] appidBytes = appId.getBytes(CHARSET);

    // randomStr + networkBytesOrder + text + appid
    byteCollector.addBytes(randomStrBytes);
    byteCollector.addBytes(networkBytesOrder);
    byteCollector.addBytes(textBytes);
    byteCollector.addBytes(appidBytes);

    // ... + pad: 使用自定义的填充方式对明文进行补位填充
    byte[] padBytes = PKCS7Encoder.encode(byteCollector.size());
    byteCollector.addBytes(padBytes);

    // 获得最终的字节流, 未加密
    byte[] unencrypted = byteCollector.toBytes();

    try {
      // 设置加密模式为AES的CBC模式
      Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
      SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
      IvParameterSpec iv = new IvParameterSpec(aesKey, 0, 16);
      cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);

      // 加密
      byte[] encrypted = cipher.doFinal(unencrypted);

      // 使用BASE64对加密后的字符串进行编码
      String base64Encrypted = base64.encodeToString(encrypted);

      return base64Encrypted;
    } catch (Exception e) {
      e.printStackTrace();
      throw new AesException(AesException.EncryptAESError);
    }
  }