apache/pulsar · error · RuntimeException

SHA-256 algorithm not found

Error message

SHA-256 algorithm not found

What it means

The SHA-256 role anonymizer hashes the role string with MessageDigest.getInstance("SHA-256") and returns a Base64-encoded 'SHA256:'-prefixed digest. The JDK guarantees SHA-256 in every standard JRE, so this RuntimeException only fires when no SHA-256 provider can be found — i.e. the JCE provider list is broken or a heavily trimmed/custom JDK is in use. It is a defensive wrapper; in practice it indicates a broken runtime environment rather than bad input.

Source

Thrown at pulsar-broker-common/src/main/java/org/apache/pulsar/common/configuration/anonymizer/DefaultRoleAnonymizerType.java:53

         return REDACTED_VALUE;
      }
   },
   SHA256 {
      private static final String PREFIX = "SHA-256:";
      private static final FastThreadLocal<MessageDigest> DIGEST = new FastThreadLocal<MessageDigest>() {
         @Override
         protected MessageDigest initialValue() throws Exception {
            return MessageDigest.getInstance("SHA-256");
         }
      };

      @Override
      public String anonymize(String role) {
         try {
            byte[] hash = DIGEST.get().digest(role.getBytes());
            return PREFIX + Base64.getEncoder().encodeToString(hash);
         } catch (Exception e) {
            throw new RuntimeException("SHA-256 algorithm not found", e);
         }
      }
   },
   MD5 {
      private static final String PREFIX = "MD5:";
      private static final FastThreadLocal<MessageDigest> DIGEST = new FastThreadLocal<MessageDigest>() {
         @Override
         protected MessageDigest initialValue() throws Exception {
            // codeql[java/weak-cryptographic-algorithm] - md5 is sufficient for this use case
            return MessageDigest.getInstance("MD5");
         }
      };

      @Override
      public String anonymize(String role) {
         try {
            byte[] hash = DIGEST.get().digest(role.getBytes());
            return PREFIX + Base64.getEncoder().encodeToString(hash);

View on GitHub (pinned to 820761864e)

Solutions

  1. Restore the default JCE providers: check $JAVA_HOME/conf/security/java.security still lists security.provider.1=sun.security.provider.Sun (or equivalent).
  2. Run on a standard, unmodified JDK (Temurin/OpenJDK 8/11/17+) instead of a stripped runtime.
  3. If using GraalVM native-image, register SHA-256 with the native-image security services configuration (native-image.properties / resource config).
  4. Inspect the cause of the wrapping exception to confirm NoSuchAlgorithmException and which provider lookup failed.

Example fix

// before (java.security mis-edited)
#security.provider.1=sun.security.provider.Sun
// after
security.provider.1=sun.security.provider.Sun
security.provider.2=sun.security.rsa.SunRsaSign
...
Defensive patterns

Strategy: try-catch

Validate before calling

// Verify SHA-256 availability before enabling the anonymizer
boolean sha256Available;
try {
    java.security.MessageDigest.getInstance("SHA-256");
    sha256Available = true;
} catch (java.security.NoSuchAlgorithmException e) {
    sha256Available = false;
}

Try / catch

try {
    String anon = anonymizer.anonymize(role);
} catch (RuntimeException e) {
    throw new IllegalStateException("JRE is missing SHA-256 provider; check java.security and JDK", e);
}

Prevention

When it happens

Trigger: Calling anonymize(role) on the SHA256 anonymizer variant when MessageDigest.getInstance("SHA-256") (cached via the FastThreadLocal DIGEST) throws NoSuchAlgorithmException — effectively only on a JRE lacking the SUN provider.

Common situations: Running Pulsar on a stripped-down/custom JRE without standard crypto providers; a broken java.security configuration (mis-edited java.security file removing the SUN provider); exotic runtimes (some GraalVM native-image configs not registering the provider).

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/fdf1f6cea4984906. Report an issue: GitHub.