Reputation: 2927
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
}
Upvotes: 1
Views: 1829
Reputation: 686
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);
Upvotes: 1