Signature Difference.

Issue #1 closed
Ragneli Nepal created an issue

I am trying to ascertain the signature created by jose4j is correct. In order to do that I have created a java key store. I read the private key from it.

Using Jose4j I do following: Map<String, Object> claimsMap=null; try{ claimsMap = JsonUtil.parseJson(claims); }catch(Exception ex){ ex.printStackTrace(); }

        JsonWebSignature jws = new JsonWebSignature();
        jws.setPayload((claims));
        jws.setKeyIdHeaderValue("5");
        jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
        jws.setKey(key);

        String compactSerialization = jws.getCompactSerialization();

Similarly I have done following ( a typical signing) in my portion of code: Signature signature = Signature.getInstance(algorithm); // here algorithm is SHA256withRSA signature.initSign(key); signature.update(bytes); return signature.sign(); I made sure input provided for both the methods are same. However for some reason signature calculated is different.

Your input will be appreciated. Thank you. rn

Comments (11)

  1. Brian Campbell repo owner

    I've written tests against the examples in JWS and also informally done some interoperability testing with other implementations. So I'm reasonably confident in the correctness of the implementation. But I certainly can't rule out the possibility of bugs/mistakes in jose4j code :)

    The JWS signature is calculated over the JWS Signing Input (the concatenation of the Encoded JWS Header, a period ('.') character, and the Encoded JWS Payload) - are you singing over the same thing in your typical signing test?

    Can you provide more code/context of around your tests? The key probably isn't important but how you determine what is signed probably is (i.e. where do the bytes of signature.update(bytes) come from?).

  2. Ragneli Nepal reporter

    Thank you Brian for such a prompt response. Here what I am doing.

    To use jose4j. I wrote following method.

     public  JsonWebSignature buildSignedJWT(Key key) throws JoseException, IOException
            {
             this.buildJSONReservedTokens();
             String claims=this.serializeTokens();
    
    
    
                Map<String, Object> claimsMap=null;
                try{
                claimsMap = JsonUtil.parseJson(claims);
                }catch(Exception ex){
                    ex.printStackTrace();
                }
                ExampleEcKeysFromJws eekfjws=new ExampleEcKeysFromJws();
                JsonWebSignature jws = new JsonWebSignature();
                jws.setPayload((claims));
                jws.setKeyIdHeaderValue("5");
                jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
                jws.setKey(key);
    
                String compactSerialization = jws.getCompactSerialization();
                System.out.println("Compact Serialization");
                System.out.println(compactSerialization);
                System.out.println("Header");
                System.out.println(jws.getHeader());
                System.out.println("PayLoad");
                System.out.println(jws.getPayload());
                System.out.println("Signature");
                return jws;
    
            }
    //Build JSON tokens looks like following:
    
    public  void buildJSONReservedTokens() {
    
            container.put("iss", "dxi");
            container.put("exp", String.valueOf(  dt.plusHours(3).getMillis()));
            container.put("nbf", String.valueOf(dt.minusMinutes(3).getMillis()));
            container.put("iat", String.valueOf(dt.getMillis()));
            container.put("dest", "urn:dest.org");
            container.put("prn", "cio");
            container.put("jti", UUID.randomUUID().toString());
        }
    
    //Serialization looks like following:
    
    public String serializeTokens() throws IOException{
            StringWriter out = new StringWriter();
               JSONValue.writeJSONString(this.container, out);
               String jsonText = out.toString();
               System.out.print(jsonText);
               return jsonText;
        }
    

    From above method buildSignedJWT I get JsonWebSignature Obect and use it to build input for typical signature calculation which looks like following:

    String encodedHeaderString=Base64URL.base64UrlEncode(jsonWebSignature.getHeader().trim());
            System.out.println("Encoded Header="+encodedHeaderString);
    String encodedPayLoadString=Base64URL.base64UrlEncode(payLoaddata.trim());
            System.out.println("Encoded PayLoad="+encodedPayLoadString);
    
    StringBuffer buffer=new StringBuffer();
            buffer.append(encodedHeaderString.trim()).append('.').append(encodedPayLoadString.trim());
            String signatureString=jwtSigner.signVerify(buffer.toString());
    
            buffer.append('.').append(Base64URL.base64UrlEncode(signatureString));
    

    base64URLEncode method looks like following.

    public static String base64UrlEncode(String input) throws UnsupportedEncodingException {
            String result = null;
            Base64 encoder = new Base64(true);
           // encoder.encodeBase64URLSafe(input.getBytes());
            byte[] decodedBytes = Base64.encodeBase64URLSafe(input.getBytes());
            result = new String(decodedBytes,"UTF-8");
            return result;
        }
    

    My signing method looks like following:

    public String signVerify(String data) throws UnrecoverableKeyException, KeyStoreException, NoSuchAlgorithmException, UnsupportedEncodingException{
            // Do a test sign and verify
                    byte[] content = Codecs.utf8Encode(data);
    
                    System.out.println("Input Data="+ data);
                    RsaSigner signer = new RsaSigner(this.keyStoreReader.getRsaPrivateKey());
                    final byte[] signed = signer.sign(content);
                    //return signed;
    
                    // First extract the public key from the private key data
                    RsaVerifier verifier = new RsaVerifier(this.keyStoreReader.getRsaPublicKey());
                    verifier.verify(content, signed);
                    return new String(signed,"UTF-8");
    
        }
    

    RsaSigner is org.springframework.security.jwt.crypto.sign.RsaSigner Let me know if I am missing something. I am using same private key from same keystore.

  3. Brian Campbell repo owner

    I'm sorry but I don't think I understand what you are trying to accomplish well enough to be of much help at this point.

    Why are you using the JsonWebSignature Obect to build input for a signature calculation? The getCompactSerialization() method already calculates the signature and gives the complete compact serialized JWS with the base64url encoded signature as the last dot separated part. I don't understand what you are trying to accomplish by singing it again?

  4. Ragneli Nepal reporter

    if input, private key and algorithm is same signature should be same no matter what package I use

    I cam across jose4j library and just wanted to check that aspect.

    I am not signing it again. I get plain text serialized string for Header and payload using JsonWebSignature . Do Base64url transformation with "." in between and feed it to a method that signs it with different method ( not jose4j).

    If you think result would be different if I do not use JsonWebSignature, fine with me. I can take that approach

  5. Brian Campbell repo owner

    Yes, the same key and input should produce the same signature (for the RSA algorithm in question anyway - it's not true of ECDSA, for example). So it should work. But there are a lot of things going on and I can't tell where the issue is.

    Perhaps if you put together a little unit test that could be run in jose4j that shows both calculations and the comparison (that fails), it might be more straightforward to try and trouble shoot it?

  6. Ragneli Nepal reporter

    May be I am not able to explain but I am doing what you meant I guess. e.g

    in my last run compact serialization shows me the output as shown below.

    Now from JsonWebSignature, I call Header using getHeader() method. I get following output: {"kid":"5","alg":"RS256"} Transforming to base64ulr using org.apache.commons.codec.binary.Base64, following is received:

    eyJraWQiOiI1IiwiYWxnIjoiUlMyNTYifQ

    This is same as output from compact serialization.

    Now I take payload from JsonWebSignature which looks following in plain text:

    {"iss":"dni","exp":"1375137832341","nbf":"1375126852341","iat":"1375127032341","dest":"urn:dest.org","prn":"cio","jti":"820ba242-1108-4cd0-80d4-e7cec9168b9a"}

    on base64url transformation it looks following:

    eyJpc3MiOiJkbmkiLCJleHAiOiIxMzc1MTM3ODMyMzQxIiwibmJmIjoiMTM3NTEyNjg1MjM0MSIsImlhdCI6IjEzNzUxMjcwMzIzNDEiLCJkZXN0IjoidXJuOmRlc3Qub3JnIiwicHJuIjoiY2lvIiwianRpIjoiODIwYmEyNDItMTEwOC00Y2QwLTgwZDQtZTdjZWM5MTY4YjlhIn0

    Now After I put . in between above encoded string, I feed it to Signer procedure, I get following:

    However base64url version of signature that I get out of it is 77-977-977-9KnAv77-9Ru-_vQMV77-977-977-977-9E3HFoATvv70Gemfvv71W77-9HRly77-977-9U8K4RWNr77-977-977-977-9z71hJO-_ve-_vRBmWe-_ve-_vWTvv73vv70rWkLvv73vv70u77-9Xu-_vQBcOe-_ve-_vS4Ja--_vW0b77-977-9KRI7L--_vXAs77-9ZABKbO-_vTN177-9fO-_vWsi77-9CUcZaBfvv73vv70CI--_ve-_ve-_vWt6Mu-_vWg_77-977-9We-_vUDvv71mc1t677-9OD0zLQNId--_vVfvv73vv73vv73vv71zFkDvv73vv73vv70ccFIVR1c1BGLvv73vv73vv73vv70lBe-_vQrvv70oCO-_ve-_vUbvv70RN--_ve-_ve-_ve-_ve-_vW3vv70177-9BO-_ve-_vTPvv73vv73vv704De-_vQBu77-9EUHvv73vv71877-9ej0dEzNPEe-_vQPvv70V77-977-9EO-_vV0zE2vvv71sAe-_vXrvv70nGu-_ve-_ve-_vXfvv73vv71o77-9IxzZghIjY--_ve-_vXQV77-977-977-9

    where as compatctserialization gives:

    mo6LKnAvoEacAxWM8ovd-xNxxaAE0QZ6Z-2lVvYdGXKZpFPCuEVja_ar8uHPvWEkuJEQZlm322Tz3ytaQqHwLoFeuABcOZDNLglrx20b9OMpEjsv5XAsomQASmyZM3W6fNhrIv8JRxloF47jAiOQ-7at1Gt6MuRoP5qvWaJA_mZzW3qXOD0zLQNId7BXiZmIjXMWQJ2PgBxwUhVHVzUEYsr26sslBemFCvQoCImWRo0RN56nsI3-bfo1ogSe8jOM4JM4DZ8AbtkRQfPllHzEej0dEzNPEeMDqhWbjhDvXTMTa_dsAd56gyca3PrEd5-gaOYjHNmCEiNj0ed0Ff6w_A ### Output from Compact Serialization ###

    eyJraWQiOiI1IiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJkbmkiLCJleHAiOiIxMzc1MTM3ODMyMzQxIiwibmJmIjoiMTM3NTEyNjg1MjM0MSIsImlhdCI6IjEzNzUxMjcwMzIzNDEiLCJkZXN0IjoidXJuOmRlc3Qub3JnIiwicHJuIjoiY2lvIiwianRpIjoiODIwYmEyNDItMTEwOC00Y2QwLTgwZDQtZTdjZWM5MTY4YjlhIn0.mo6LKnAvoEacAxWM8ovd-xNxxaAE0QZ6Z-2lVvYdGXKZpFPCuEVja_ar8uHPvWEkuJEQZlm322Tz3ytaQqHwLoFeuABcOZDNLglrx20b9OMpEjsv5XAsomQASmyZM3W6fNhrIv8JRxloF47jAiOQ-7at1Gt6MuRoP5qvWaJA_mZzW3qXOD0zLQNId7BXiZmIjXMWQJ2PgBxwUhVHVzUEYsr26sslBemFCvQoCImWRo0RN56nsI3-bfo1ogSe8jOM4JM4DZ8AbtkRQfPllHzEej0dEzNPEeMDqhWbjhDvXTMTa_dsAd56gyca3PrEd5-gaOYjHNmCEiNj0ed0Ff6w_A

  7. Brian Campbell repo owner

    I think I understand the issue but I was suggesting that if I had code that I could easily execute in my own environment that demonstrated the issue, it might be possible to troubleshot/debug it. A unit test (with the pom xml snippet of any necessary dependencies) that could run in the jose4j build, for example, might make that easy.

    Without something like that, I'm at a loss.

  8. Brian Campbell

    I'd like to close this, unless you've got something more concrete that I can reproduce and troubleshoot with.

  9. Log in to comment