java version 1.8
import java.io.ByteArrayInputStream;
import java.security.KeyFactory;
import java.security.Signature;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.interfaces.RSAPublicKey;
import java.util.Base64;
/**
*
* @author user
*/
public class Test {
public static void main(String[] args) throws Exception {
String publicKeyB64 = "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";
String data = "eyJhbGciOiJSUzI1NiIsImtpZCI6IjU2MzU4ODUyMzRCOTI1MkRERTAwNTc2NkQ5RDlGMjc2NTY1RjYzRTIiLCJ4NXQiOiJWaldJVWpTNUpTM2VBRmRtMmRueWRsWmZZLUkiLCJ0eXAiOiJKV1QifQ.eyJhcHBjdHhzZW5kZXIiOiIwMDAwMDAwMi0wMDAwLTBmZjEtY2UwMC0wMDAwMDAwMDAwMDBAOGU5MDAzNTgtOWJjMC00YmQyLTlmMzQtNDU5OTY3ODk5MDVkIiwiaXNicm93c2VyaG9zdGVkYXBwIjoiVHJ1ZSIsImFwcGN0eCI6IntcIm1zZXhjaHVpZFwiOlwiYTVkYWY0YzItZTdiYS00NDE5LTljYmUtYjQ4NWE2ZTNiNGQ1XCIsXCJ2ZXJzaW9uXCI6XCJFeElkVG9rLlYxXCIsXCJhbXVybFwiOlwiaHR0cHM6Ly9vdXRsb29rLm9mZmljZTM2NS5jb206NDQzL2F1dG9kaXNjb3Zlci9tZXRhZGF0YS9qc29uLzFcIn0iLCJuYmYiOjE1OTMwMjA4MzAsImV4cCI6MTU5MzA0OTYzMCwiaXNzIjoiMDAwMDAwMDItMDAwMC0wZmYxLWNlMDAtMDAwMDAwMDAwMDAwQDhlOTAwMzU4LTliYzAtNGJkMi05ZjM0LTQ1OTk2Nzg5OTA1ZCIsImF1ZCI6Imh0dHBzOi8vbWFpbGFwcC5mb3JjZS5jb20vY2xpZW50cy9tYWlsYXBwL2FjdGl2YXRpb24ifQ";
String signature = "oifeWN-wnci-WCS6XPLC-74ynG9rmXdePVfMMxX9WsAXOK5tvRpNmNsPqu9bllufAIUhgpNIYtHEB39-_o2pzpugyfkohLJfPovEQa-1X8zzudjxY3j5tRyISzVuwL9l6zROhJIdOvXsoarzcuQ38j492H7ol7auTvfDI4Mwu4Ri_e2rbiFYWsYU36Htj39DEiOvpQ12z7Onu-Yrj1inICTDtJsOdv9HWrO2nZ5IwRdl45Tt0Ks3ZrBeStleNVCXQdU_xKvYtbO02fUfgkFrIzEUZYHgXbK8sE2m0phmeU7Wp-KdW4jVVl9yLQtB98_FJJfw9tI4Oys2NBBY2sLyhQ";
RSAPublicKey secret = null;
try {
secret = null;
CertificateFactory cf = CertificateFactory.getInstance("X.509");
Certificate cert = cf.generateCertificate(new ByteArrayInputStream(Base64.getMimeDecoder().decode(publicKeyB64)));
secret = (RSAPublicKey) cert.getPublicKey();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
KeyFactory kf = KeyFactory.getInstance("RSA");
Signature privateSignature = Signature.getInstance("SHA256withRSA");
privateSignature.initVerify(secret);
privateSignature.update(data.getBytes("UTF-8"));
System.out.println(privateSignature.verify(Base64.getMimeDecoder().decode(signature.getBytes())));
}
}
Getting the following exception:
Exception in thread "main" java.security.SignatureException: Signature length not correct: got 248 but was expecting 256
at sun.security.rsa.RSASignature.engineVerify(RSASignature.java:211)
at java.security.Signature$Delegate.engineVerify(Signature.java:1394)
at java.security.Signature.verify(Signature.java:771)
at com.ciphercloud.plugin.salesforce.rewriters.Test.main(Test.java:35)
One more question:
Earlier, I used the Base64.getDecoder().decode(signature.getBytes()))
but it's throwing an error, so I changed to Base64.getMimeDecoder().decode(signature.getBytes()))
. May I know why it faild with Base64.getDecoder().decode()
?
The problem here is the wrong decoding.
Neither Mime (Base64.getMimeDecoder().decode()
) nor Base64 (Base64.getDecoder().decode()
) are correct.
JWT uses Base64url encoding, not Base64. The difference are the -
and _
characters, which are used in base64url to replace the +
and /
of the Base64 standard. Also the padding =
is omitted in Base64url encoding.
The correct way to decode the JWT header, payload and signature is to use the Base64url decoder:
Base64.getUrlDecoder().withoutPadding().decode()