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

  1. Call Signature.initSign(privateKey) (optionally with a SecureRandom) on mSignature before any data is written.
  2. Audit the subclass initialization path; check the cause message ('object not initialized properly').
  3. Create a fresh Signature instance per signing operation instead of reusing across jars.
  4. 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

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)