skylot/jadx · critical · JadxRuntimeException

Failed to build hash

Error message

Failed to build hash

What it means

Thrown by md5Sum(byte[]) when MessageDigest.getInstance("MD5") fails. MD5 is a mandatory algorithm in every standard Java JDK (mandated by JCA specification), so NoSuchAlgorithmException should never occur in a compliant JVM. The only realistic trigger is a non-compliant or severely stripped/custom JVM (e.g., a minimal embedded JVM, or a security provider configuration that removed MD5). The catch is defensive.

Source

Thrown at jadx-core/src/main/java/jadx/core/utils/files/FileUtils.java:501

	public static List<Path> fileNamesToPaths(List<String> fileNames) {
		return fileNames.stream().map(Paths::get).collect(Collectors.toList());
	}

	public static List<File> toFiles(List<Path> paths) {
		return paths.stream().map(Path::toFile).collect(Collectors.toList());
	}

	public static String md5Sum(String str) {
		return md5Sum(str.getBytes(StandardCharsets.UTF_8));
	}

	public static String md5Sum(byte[] data) {
		try {
			MessageDigest md = MessageDigest.getInstance("MD5");
			md.update(data);
			return bytesToHex(md.digest());
		} catch (Exception e) {
			throw new JadxRuntimeException("Failed to build hash", e);
		}
	}

	/**
	 * Hash timestamps of input files
	 */
	public static String buildInputsHash(List<Path> inputPaths) {
		try (ByteArrayOutputStream bout = new ByteArrayOutputStream();
				DataOutputStream data = new DataOutputStream(bout)) {
			List<Path> inputFiles = FileUtils.expandDirs(inputPaths);
			Collections.sort(inputFiles);
			data.write(inputPaths.size());
			data.write(inputFiles.size());
			for (Path inputFile : inputFiles) {
				FileTime modifiedTime = Files.getLastModifiedTime(inputFile);
				data.writeLong(modifiedTime.toMillis());
			}
			return FileUtils.md5Sum(bout.toByteArray());

View on GitHub (pinned to e738a26571)

Solutions

  1. Use a standard JDK (Oracle, OpenJDK, or a JCA-compliant JVM) that includes MD5.
  2. Check installed security providers: java.security.Security.getProviders() and verify MessageDigest hash algorithms.
  3. If MD5 was intentionally removed, patch md5Sum to use an alternative like SHA-256.

Example fix

// before
MessageDigest md = MessageDigest.getInstance("MD5"); // can throw

// after — verify provider support at startup
if (MessageDigest.isAvailable("MD5")) { // Java 17+; otherwise try/catch
    md = MessageDigest.getInstance("MD5");
} else {
    md = MessageDigest.getInstance("SHA-256");
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Check MD5 availability before use
public static boolean isMd5Available() {
    try {
        MessageDigest.getInstance("MD5");
        return true;
    } catch (Exception e) {
        return false;
    }
}

Try / catch

try {
    String hash = FileUtils.md5Sum(data);
} catch (JadxRuntimeException e) {
    if (e.getCause() instanceof NoSuchAlgorithmException) {
        // MD5 not available — use alternative or report environment issue
        LOG.error("MD5 not available on this JVM: {}", e.getCause().getMessage());
    }
}

Prevention

When it happens

Trigger: Running jadx on a non-standard JVM that does not include the MD5 algorithm. A custom security.provider configuration that explicitly deregisters MD5. An extremely minimal/embedded JVM that omits MessageDigest support.

Common situations: Embedded device JVMs with reduced crypto. A security policy (Java Security Manager or custom provider) that removed MD5. Extremely rare in practice — standard Oracle/OpenJDK, GraalVM, and Android all include MD5.

Related errors


AI-assisted analysis of skylot/jadx@e738a26571 (2026-08-14). Data as JSON: /api/errors/f2c74c8edb63d77b. Report an issue: GitHub.