binarywang/WxJava · critical · IllegalStateException

HmacSHA256 signature failed

Error message

HmacSHA256 signature failed

What it means

Thrown by `calcKnowledgeSignature` when the JCE `Mac.getInstance("HmacSHA256")` or `mac.init(...)` raises a GeneralSecurityException, wrapped as IllegalStateException. HmacSHA256 is mandatory in every JDK, so in practice this only fires on a corrupted/custom security provider, a bad SecretKeySpec, or a severely misconfigured JVM.

Source

Thrown at weixin-java-aispeech/src/main/java/me/chanjar/weixin/aispeech/util/WxAispeechSignUtil.java:31

public final class WxAispeechSignUtil {
  private WxAispeechSignUtil() {
  }

  public static String calcDialogSign(String token, long timestamp, String nonce, String body) {
    String bodyMd5 = DigestUtils.md5Hex(defaultString(body));
    return DigestUtils.md5Hex(defaultString(token) + timestamp + defaultString(nonce) + bodyMd5);
  }

  public static String calcKnowledgeSignature(String secretKey, long timestamp, String nonce, String requestId,
                                              String requestBody) {
    String payload = timestamp + "\n" + defaultString(nonce) + "\n" + defaultString(requestId) + "\n"
      + defaultString(requestBody);
    try {
      Mac mac = Mac.getInstance("HmacSHA256");
      mac.init(new SecretKeySpec(defaultString(secretKey).getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
      return bytesToHex(mac.doFinal(payload.getBytes(StandardCharsets.UTF_8)));
    } catch (GeneralSecurityException e) {
      throw new IllegalStateException("HmacSHA256 signature failed", e);
    }
  }

  public static String encryptAesCbcToBase64(String plainText, String aesKey) {
    try {
      byte[] keyBytes = decodeAesKey(aesKey);
      Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
      cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyBytes, "AES"), new IvParameterSpec(Arrays.copyOf(keyBytes, 16)));
      byte[] encrypted = cipher.doFinal(defaultString(plainText).getBytes(StandardCharsets.UTF_8));
      return Base64.encodeBase64String(encrypted);
    } catch (GeneralSecurityException e) {
      throw new IllegalStateException("AES CBC encrypt failed", e);
    }
  }

  public static String decryptAesCbcFromBase64(String cipherTextBase64, String aesKey) {
    try {
      byte[] keyBytes = decodeAesKey(aesKey);

View on GitHub (pinned to 1c43293a3c)

Solutions

  1. Confirm the JVM provides HmacSHA256: run a tiny `Mac.getInstance("HmacSHA256")` test.
  2. Remove or fix any custom security provider registered via `java.security`.
  3. Use a standard JDK distribution rather than a stripped image.
  4. Inspect the wrapped cause exception for the exact algorithm/provider error.
Defensive patterns

Strategy: try-catch

Validate before calling

// Sanity-check the JCE provider at startup
try {
    javax.crypto.Mac.getInstance("HmacSHA256");
} catch (java.security.NoSuchAlgorithmException e) {
    throw new IllegalStateException("JVM lacks HmacSHA256", e);
}

Try / catch

try {
    String sig = WxAispeechSignUtil.calcKnowledgeSignature(secretKey, ts, nonce, reqId, body);
} catch (IllegalStateException e) {
    // unwrap GeneralSecurityException; provider/algorithm problem
    log.error("HmacSHA256 unavailable on this JVM", e.getCause());
    throw e;
}

Prevention

When it happens

Trigger: An exotic JCE provider that does not implement HmacSHA256; a SecurityManager/provider override stripping algorithms; running on a stripped JVM image lacking the HmacSHA256 algorithm.

Common situations: Custom/JNI security provider misconfigured; hardened/restricted JRE; rarely a JDK bug.

Related errors


AI-assisted analysis of binarywang/WxJava@1c43293a3c (2026-08-14). Data as JSON: /api/errors/b428b42be539b4e6. Report an issue: GitHub.