pxb1988/dex2jar · error · IOException
SignatureException:
Error message
SignatureException:
What it means
Thrown by AbstractJarSign's signature-wrapping OutputStream.write(byte[]) when java.security.Signature.update(byte[], int, int) throws SignatureException, rewrapped as an IOException. Signature.update only fails when the signature engine is not in a valid signing state, meaning mSignature was never initialized with initSign or was already finalized.
Solutions
- Call Signature.initSign(privateKey) (optionally with a SecureRandom) on mSignature before any data is written.
- Audit the subclass initialization path; check the cause message ('object not initialized properly').
- Create a fresh Signature instance per signing operation instead of reusing across jars.
- Abort and restart the signing operation if the failure occurred mid-run; do not keep writing after sign().
Example fix
// before
Signature mSignature = Signature.getInstance("SHA1withRSA");
// missing initSign
outputStream.write(jarBytes); // throws SignatureException
// after
Signature mSignature = Signature.getInstance("SHA1withRSA");
mSignature.initSign(privateKey, new SecureRandom());
outputStream.write(jarBytes); Defensive patterns
Strategy: validation
Validate before calling
// Ensure the signer is initialized before streaming bytes
if (!signatureInitialized) {
signature.initSign(privateKey, new SecureRandom());
signatureInitialized = true;
}
Type guard
static boolean readyToSign(java.security.Signature s) {
try { s.update(new byte[0]); return true; }
catch (java.security.SignatureException e) { return false; }
}
Try / catch
try {
signedOut.write(bytes);
} catch (IOException e) {
if (e.getMessage() != null && e.getMessage().startsWith("SignatureException:")) {
throw new IllegalStateException("Signature not initialized; call initSign(privateKey) first", e);
}
throw e;
}
Prevention
- Call Signature.initSign(privateKey) immediately after getInstance(), before creating the output stream.
- Use a fresh Signature instance per jar; never reuse across signing operations.
- Stop writing bytes the moment sign() has been called.
- Keep signing single-threaded; java.security.Signature is not thread-safe.
When it happens
Trigger: Writing bytes through the signed output stream while mSignature has not had Signature.initSign(privateKey) called, or continuing to write after sign() was invoked.
Common situations: Custom AbstractJarSign subclasses that forget initialization; reusing one Signature across multiple jars; writes flushed after signature generation began; aborted signing runs that keep streaming.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
AI-assisted analysis of pxb1988/dex2jar@b5bda4fb49 (2026-09-08).
Data as JSON: /api/errors/afbdb5f9e692a5b5.
Report an issue: GitHub.
Appendix: source
Thrown at dex-tools/src/main/java/com/googlecode/d2j/signapk/AbstractJarSign.java:66
private int mCount;
private Signature mSignature;
public SignatureOutputStream(OutputStream out, Signature sig) {
super(out);
mSignature = sig;
mCount = 0;
}
public int size() {
return mCount;
}
@Override
public void write(byte[] b) throws IOException {
try {
mSignature.update(b, 0, b.length);
} catch (SignatureException e) {
throw new IOException("SignatureException: " + e);
}
out.write(b);
mCount += b.length;
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
try {
mSignature.update(b, off, len);
} catch (SignatureException e) {
throw new IOException("SignatureException: " + e);
}
out.write(b, off, len);
mCount += len;
}
@Override
public void write(int b) throws IOException {
View on GitHub (pinned to b5bda4fb49)