1

So i am trying to generate JWT token from my key generated using PBKDF2 and the code is like this in android:

public SecretKey generateKey(String passphraseOrPin) throws NoSuchAlgorithmException, InvalidKeySpecException {

        final int iterations = 5000;

        // Generate a 256-bit key
        final int outputKeyLength = 256;
        SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2withHmacSHA256");
        KeySpec keySpec = new PBEKeySpec(getSha256Hash(passphraseOrPin).toCharArray(), salt.getBytes(), iterations, outputKeyLength);
        SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);

        return secretKey;
    }

But whenever i am trying to generate the token:

String jwtString = Jwts.builder().setSubject("sub").signWith(key, SignatureAlgorithm.HS256).compact();

i am getting the error:

Process: com.android.gocontract, PID: 7434
    java.lang.IllegalStateException: Fatal Exception thrown on Scheduler.
        at io.reactivex.android.schedulers.HandlerScheduler$ScheduledRunnable.run(HandlerScheduler.java:111)
        at android.os.Handler.handleCallback(Handler.java:873)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6669)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
     Caused by: io.jsonwebtoken.security.InvalidKeyException: The signing key's algorithm 'PBKDF2WithHmacSHA256' does not equal a valid HmacSHA* algorithm name and cannot be used with HS256.
        at io.jsonwebtoken.SignatureAlgorithm.assertValid(SignatureAlgorithm.java:358)
        at io.jsonwebtoken.SignatureAlgorithm.assertValidSigningKey(SignatureAlgorithm.java:302)
        at io.jsonwebtoken.impl.DefaultJwtBuilder.signWith(DefaultJwtBuilder.java:123)
        at com.android.gocontract.Activity.LoginActivity$2.onNext(LoginActivity.java:192)
        at com.android.gocontract.Activity.LoginActivity$2.onNext(LoginActivity.java:163)
        at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeOnObserver.onNext(ObservableSubscribeOn.java:58)
        at io.reactivex.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.drainNormal(ObservableObserveOn.java:200)
        at io.reactivex.internal.operators.observable.ObservableObserveOn$ObserveOnObserver.run(ObservableObserveOn.java:252)
        at io.reactivex.android.schedulers.HandlerScheduler$ScheduledRunnable.run(HandlerScheduler.java:109)
        at android.os.Handler.handleCallback(Handler.java:873) 
        at android.os.Handler.dispatchMessage(Handler.java:99) 
        at android.os.Looper.loop(Looper.java:193) 
        at android.app.ActivityThread.main(ActivityThread.java:6669) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858) 
2019-09-23 18:38:37.036 7434-7434/com.android.gocontract I/Process: Sending signal. PID: 7434 SIG: 9

the method to generate Sha256:

public String getSha256Hash(String password) {
        try {
            MessageDigest digest = null;
            try {
                digest = MessageDigest.getInstance("SHA-256");
            } catch (NoSuchAlgorithmException e1) {
                e1.printStackTrace();
            }
            digest.reset();
            return bin2hex(digest.digest(password.getBytes()));
        } catch (Exception ignored) {
            return null;
        }
    }

version of jjwt:

 api 'io.jsonwebtoken:jjwt-api:0.10.7'
    runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.10.7'
    runtimeOnly('io.jsonwebtoken:jjwt-orgjson:0.10.7') {
        exclude group: 'org.json', module: 'json' //provided by Android natively
    }
Fay007
  • 2,707
  • 3
  • 28
  • 58
  • There were problems with the case sensitivity in some versions of the library/android. Did you try using PBKDF2WithHmacSHA256 with the uppercase W? (you're using PBKDF2withHmacSHA256). Are you using the most recent version of the library? – Ricardo A. Sep 24 '19 at 13:10
  • what do you mean by the most recent version of library? – Fay007 Sep 24 '19 at 13:31
  • i just tried with the "W", so that's not the case i suppose – Fay007 Sep 24 '19 at 13:34
  • Which version of android and java you're using? – Ricardo A. Sep 24 '19 at 13:38
  • java version "1.8.0_191" and android would be up to date – Fay007 Sep 24 '19 at 13:50
  • PBKDF2withHmacSHA256 is only avaiable in API 26 and after. Are you using the correct api level? – Ricardo A. Sep 24 '19 at 13:58
  • but it's generating secret key, i have actually checked that it's Api 26+, but i am using minSdkVersion 23, could that be a reason?? – Fay007 Sep 24 '19 at 14:01
  • It should work if the API is 26+. You can put a verification just in case. Use PBKDF2WithHmacSHA1 for API 25- – Ricardo A. Sep 24 '19 at 14:13
  • I tested the algorithm here and it's working just fine, so probably is something with your getSha256Hash function or with your salt. – Ricardo A. Sep 24 '19 at 14:26
  • Posted sha256 method and also salt is just a text. – Fay007 Sep 24 '19 at 15:07
  • I couldn't reproduce the error, everything is working fine. The only thing I can think of is outdated version of the jwt library. Which version are you working with? (you can find it in your build.gradle, like 'io.jsonwebtoken:jjwt-api:0.10.7') – Ricardo A. Sep 24 '19 at 18:21
  • we are using the same version i suppose, can you tell me what version of java you are using?? i have updated the jjwt version on the question – Fay007 Sep 25 '19 at 07:42
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/199954/discussion-between-ricardo-a-and-fay007). – Ricardo A. Sep 25 '19 at 11:17

1 Answers1

1

The solution: use another encryption algorithm, or use the lib Spongy Castle.

Useful lib: Nimbus JOSE JWT Spongycastle, if you need help mixing jwt with spongy castle.

Why it's not working for you: it is a particularity of the device you're using. Some devices support the PBKDF2withHmacSHA256 algorithm, while others don't.

How I came to this conclusion: First I thought it could be a simple typo, but I found in the JJWT github that while the issue indeed existed, it was already fixed. Since the verification now uses equalsignorecase the typo wouldn't matter. You can confirm in the code.

Then I thought it could be android or java version. But I discovered that since java 8 release it was already implemented.

I thought it could be the android version, but it works from API 26.

I've also tested the code you're using, and it worked just fine here, so it would not be any of these problems. Then I researched a lot, seen some other questions, people having the same problem with other libs and other algorithms.

Extra: There is a code from k3v that probably can help you (using Spongy Castle):

PKCS5S2ParametersGenerator generator = new PKCS5S2ParametersGenerator(new SHA256Digest());
generator.init(PBEParametersGenerator.PKCS5PasswordToUTF8Bytes(password), salt, iterations); 
KeyParameter key = (KeyParameter)generator.generateDerivedMacParameters(keySizeInBits);
Ricardo A.
  • 685
  • 2
  • 8
  • 35
  • Do i need to add Spongy Castle as library or i can i add it via gradle?? – Fay007 Sep 25 '19 at 12:59
  • Via gradle is fine. – Ricardo A. Sep 25 '19 at 13:02
  • 2
    @Fay007 you need the following : implementation 'com.madgag.spongycastle:core:1.56.0.0' implementation 'com.madgag.spongycastle:prov:1.56.0.0' implementation 'com.madgag.spongycastle:pkix:1.54.0.0' implementation 'com.madgag.spongycastle:pg:1.54.0.0' – Lena Bru Sep 26 '19 at 09:36