Search code examples
javaandroidcryptographydigital-signaturebouncycastle

BouncyCastle, different behaviour for signature on Desktop / Android


I use the following code in order to sign data:

static public byte[] sign(byte[] data, PrivateKey privateKey, int saltLength) throws Exception {
    Signature instance = Signature.getInstance("SHA256withRSA/PSS", provider);
    MGF1ParameterSpec mgf1ParameterSpec = new MGF1ParameterSpec("SHA-256");
    PSSParameterSpec pssParameterSpec = new PSSParameterSpec("SHA-256", "MGF1",mgf1ParameterSpec , saltLength, 1);
    instance.setParameter(pssParameterSpec);
    instance.initSign(privateKey);
    instance.update(data);
    return instance.sign();
}

(The code is very similar for checking sign)

On desktop, the code is working fine, and signature can be checked with other platform (tested with python, node, ...).

On Android, the "saltLength" is not read, and is forced to 32bits, so I can't sign / verify signature from device on other platform if another "saltLength" is used. (I verified it by brute-forcing saltLength value on desktop).

I really don't know how to debug it, the very same Java code has different behavior between launched on desktop or Android. Any idea how to force "saltLength" on Android?


Solution

  • Ok, so after many tests on both desktop and Android side... I've still haven't found what's the origin of the problem (I'm guessing a different implementation of java.security.Signature$SignatureImpl but not sure ...)

    However, I've found a work around for anyone encountering the same problem. I created the following class:

    public class SHA256withRSACustomPadding extends PSSSignatureSpi {
        public SHA256withRSACustomPadding(int padding) {
            super(new RSABlindedEngine(), new PSSParameterSpec("SHA-256", "MGF1", new MGF1ParameterSpec("SHA-256"), padding, 1));
        }
    
        public void initSign(PrivateKey privateKey) throws InvalidKeyException {
            engineInitSign(privateKey);
        }
    
        public void update(byte[] data) throws SignatureException {
            engineUpdate(data,0,data.length);
        }
    
        public byte[] sign() throws SignatureException {
            return engineSign();
        }
    
        public void initVerify(PublicKey publicKey) throws InvalidKeyException {
            engineInitVerify(publicKey);
        }
    
        public boolean verify(byte[] data) throws SignatureException {
            return engineVerify(data);
        }
    }
    

    And updated my previous code with:

    static public byte[] sign(byte[] data, PrivateKey privateKey, int saltLength) throws Exception {
        SHA256withRSACustomPadding instance = new SHA256withRSACustomPadding(padding);
        instance.initSign(privateKey);
        instance.update(data);
        return instance.sign();
    }