NationalSecurityAgency/ghidra · error · NumberFormatException

Bad base64 encoding

Error message

Bad base64 encoding

What it means

Thrown by Base64Lite.decodeLongBase64 when a character in the input string maps to a negative value in the decode table, i.e. it is not one of the 64 valid RFC-4648 URL/filename-safe characters (A-Z, a-z, 0-9, '-', '_'). It is an unchecked NumberFormatException. This is the BSim-internal base64 used for compact long encodings (e.g. signature ids), not standard MIME base64.

Source

Thrown at Ghidra/Features/BSim/src/main/java/ghidra/features/bsim/query/elastic/Base64Lite.java:114

    		else {
    			buffer[pos++] = encode[chunk];
    			seenNonZero = true;
    		}
    	}
    	return new String(buffer,0,pos);
    }

    /**
     * Decode (up to 11) base64 characters to produce a long
     * @param val is the String to decode
     * @return the decode long
     */
    public static long decodeLongBase64(String val) {
    	long res = 0;
    	for(int i=0;i<val.length();++i) {
    		int chunk = decode[val.charAt(i)];
    		if (chunk < 0)
    			throw new NumberFormatException("Bad base64 encoding");
    		res <<= 6;
    		res |= chunk;
    	}
    	return res;
    }
}

View on GitHub (pinned to d5f144c24d)

Solutions

  1. Ensure the value was produced by Base64Lite.encodeLongBase64 (URL-safe alphabet, no padding).
  2. Strip whitespace/newlines and remove any '=' padding before decoding.
  3. If the source is standard base64, translate '+'->'-' and '/'->'_' before passing to decodeLongBase64.
  4. Limit input to <=11 characters and verify every char is in the URL-safe alphabet.

Example fix

// before
long v = Base64Lite.decodeLongBase64(s); // throws on '+' / '/' / '='

// after
String safe = s.replace('+', '-').replace('/', '_').replaceAll("[=\\s]", "");
long v = Base64Lite.decodeLongBase64(safe);
Defensive patterns

Strategy: validation

Validate before calling

private static final String SAFE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
boolean isBase64Lite(String s) {
    for (int i = 0; i < s.length(); i++) if (SAFE.indexOf(s.charAt(i)) < 0) return false;
    return s.length() <= 11;
}
if (!isBase64Lite(val)) throw new NumberFormatException("not Base64Lite: " + val);
long v = Base64Lite.decodeLongBase64(val);

Type guard

boolean isBase64LiteSafe(String s) {
    if (s == null || s.length() > 11) return false;
    for (int i = 0; i < s.length(); i++) {
        char c = s.charAt(i);
        if (!((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '-' || c == '_')) return false;
    }
    return true;
}

Try / catch

try {
    return Base64Lite.decodeLongBase64(val);
} catch (NumberFormatException e) {
    String safe = val.replace('+', '-').replace('/', '_').replaceAll("[=\\s]", "");
    return Base64Lite.decodeLongBase64(safe);
}

Prevention

When it happens

Trigger: Calling decodeLongBase64(val) with a string containing standard base64 characters like '+' or '/', whitespace, '=' padding, or any char outside the 0-127 ASCII range / not in the encode alphabet. Reached when decoding stored signature/hash longs from an elastic or XML source.

Common situations: Data encoded with a standard (MIME) base64 encoder instead of Base64Lite; '+' or '/' characters present; stray whitespace/newlines or '=' padding not stripped; truncated or corrupted field; mixing Base64Lite output with another base64 variant.

Related errors


AI-assisted analysis of NationalSecurityAgency/ghidra@d5f144c24d (2026-08-14). Data as JSON: /api/errors/5ed31ddaa6135c16. Report an issue: GitHub.