Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

why I modify genernated jwt a word, but verifier still success #211

Closed
justkuai opened this issue Feb 27, 2017 · 2 comments
Closed

why I modify genernated jwt a word, but verifier still success #211

justkuai opened this issue Feb 27, 2017 · 2 comments

Comments

@justkuai
Copy link

justkuai commented Feb 27, 2017

`

    String key = "hello";

    String compactJws = Jwts.builder()
            .setSubject("Joe")
            .signWith(SignatureAlgorithm.HS512, key)
            .compact();

    String fakeCompactJws = compactJws.substring(0, compactJws.length() - 1) + "1"; // modify last the word to 1

    System.out.println("real jwt: " + compactJws);
    System.out.println("fake jwt: " + fakeCompactJws);

    System.out.println(Jwts.parser().setSigningKey(key).parseClaimsJws(fakeCompactJws).getBody().getSubject()); // why  'joe',  i'm modify a word 

`

@sainaen
Copy link
Contributor

sainaen commented Feb 28, 2017

TL;DR: This is just how Base64 encoding/decoding works. Even after your modification, actual bytes of the signature are not changed and so it is still valid.

Also, I should note, that the key in signWith(SignatureAlgorithm.HS512, key) should be a base64 encoded string for this method to work correctly. hello works as a base64 encoded string, but you might want to be careful about not using any string that is not valid base64 string.


Details for the curious reader:

The last quadruplet¹ of this particular signature is Pw==, where w is used in decoding of the last byte like this:

out[63] = (byte) (decodeMap['P'] << 2) | (decodeMap['w'] >> 4));

and the padding (two ='s) is ignored. From this, you can see that whatever value decodeMap['w'] has, only its highest 4 bits are used.

Now, decodeMap here is a mapping table defined in the RFC 4648.
According to this table, the w character encodes the value 48. If you shift it by 4 bits to the right, as it done by decoder, you'll get the value 3. But the character 1 that encodes the value 53, when shifted by 4 bits to the right also becomes 3. In fact all values from 48 to 63 (encoded as letters from w to z, digits, + and /), when shifted become the value 3.

This means, that the base64 encoded string Pw== represents the byte value 0x3F, the same byte can be encoded as Px==, or P1==, P9==! Though, actually, I think it would be a violation of RFC to encode this way, because it explicitly requires adding of zeros to complete the last 6-bit group, but any of these strings should be decoded correctly.

¹ — 4 characters that represent four 6-bit groups encoding 3 bytes.

@lhazlewood
Copy link
Contributor

Closing this as there does not appear to be actionable work for the JJWT project. If you have questions (as opposed to known actionable work), please use StackOverflow.com and use the jjwt tag. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants