According to the Java 12 security specs here the RSASSA-PSS signature scheme should be supported (actually as of Java 11).
However, if I try to use a signature with PS256 algorithm in my JWT using e.g. the nimbus jose+jwt library, then it doesn't work unless I use BouncyCastle.
val signer = RSASSASigner(signKey)
val jwsObject = JWSObject(
JWSHeader.Builder(JWSAlgorithm.PS256) // PS256 gives error; RS256 will work
.keyID(signKeyId)
.build(),
Payload(json)
jwsObject.sign(signer)
This gives an error:
java.security.NoSuchAlgorithmException: SHA256withRSAandMGF1 Signature not available
And indeed JCASupport.isSupported(JWSAlgorithm.PS256) is false
If I include BouncyCastle then it does work:
Security.addProvider(BouncyCastleProviderSingleton.getInstance())
JCASupport.isSupported(JWSAlgorithm.PS256) == true
I would have thought that BouncyCastle is not necessary anymore in Java 12 (I'm actually using Kotlin 1.3 with Java 12 and Spring Boot 2.2 and com.nimbusds 8.4 to be precise).
I would like to be independent from BouncyCastle.
What am I missing?
I'm trying to write a very simple program to encrypt and decrypt a string:
String password = "kdfljxcasd";
String encodeThat = "Hello World + some special chars!^^-";
String salt = KeyGenerators.string().generateKey();
BytesEncryptor encryptor = Encryptors.standard(password, salt);
// breakpoint steping doesn't reach that point - it gets stuck here for some reason...
byte[] encrypted = encryptor.encrypt(encodeThat.getBytes());
byte[] decrypted = encryptor.decrypt(encrypted);
System.out.println("Before encryption: " + encodeThat);
System.out.println("Encrypted: " + encrypted.toString());
System.out.println("After encryption: " + decrypted.toString());
But for some reason I never get an encrypted value. When I call enryptor.encrypt() it never reaches that point.
I'm getting the following exception:
'Unable to initialize due to invalid secret key' java.lang.IllegalArgumentException: Unable to initialize due to invalid secret key
What am I doing wrong?
Ok, after hours of searching I finally found the solution:
Appearently I didn't have the correct policies for unlimited Strength installed.
That's the way I solved it:
Download the policies from: http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html
Unpack that and put local_policy.jar and US_export_policy.jar into ${jdk -path}/jre/lib/security and override the existing files. (ATTENTION: Don't put it in the JRE folder. You have to put it into jdk/jre/... ... - that took me hours :) )
Restart the server and it works!
Hope that helped :)
Since Java 8u151 you can resolve this with a property:
Security.setProperty("crypto.policy", "unlimited");
Try to upgrade to newer java 8 JDK version.
For me I tried 2 versions:
1.8.131 - failed
1.8.201 - success
Ran into this problem and fixed it by switching from JDK 1.8 to Adopt Open JDK 8
I would like to know whether there exists a public/private key specification (preferrably in Java itself, no external libs) that can do both a KeyAgreement and Signature.
Try elliptic curves:
KeyPairGenerator eckpg = KeyPairGenerator.getInstance("EC");
ECGenParameterSpec p256 = new ECGenParameterSpec("secp256r1");
eckpg.initialize(p256);
KeyPair doubleUseKeyPair = eckpg.generateKeyPair();
KeyAgreement ecdh = KeyAgreement.getInstance("ECDH");
ecdh.init(doubleUseKeyPair.getPrivate());
// ...
Signature ecdsa = Signature.getInstance("SHA256withECDSA");
ecdsa.initSign(doubleUseKeyPair.getPrivate());
// ...
System.out.println(eckpg.getProvider());
System.out.println(ecdh.getProvider());
System.out.println(ecdsa.getProvider());
Should return:
SunEC version 1.7
SunEC version 1.7
SunEC version 1.7
This is on Java 7 from Sun/Oracle of course.
Note that using the same key (pair) two different purposes is considered bad key management by most. It may allow for attacks that uses vulnerabilities in either or a combination in both the algorithms and the protocol. Using the same key type / strength is of course fine.
MessageDigest.getInstance("SHA") seems to work and gives me a MessageDigest, but I can't tell what algorithm it's giving me.
Is it SHA-1 or SHA-0 or ..?
I'm not interested in what happens on my machine. I want to know whether it will return sha0 or sha1 for all valid implementations of Java (or it's undefined).
The JCE Specification lists standard names that an implementation is expected to support. "SHA-1" is specified, as are SHA-256, SHA-384, and SHA-512. "SHA", "SHA-0" and SHA-2" are not standard names and therefore may not be supported at all. You cannot guarantee what "SHA" will return, if anything at all, because it is not in the standard.
SHA-0 is obsolete. For use with the Java JCE MessageDigest, SHA == SHA-1 for some JCE providers. By the way, SHA-1 is not considered to be secure with today's computers and technology. SHA-512 is still secure for pretty much anything. SHA-256 is ok for most things, still.
You can list the protocols available in the Java version you are using with this code. (I got it here ):
import java.security.Provider;
import java.security.Security;
public class JceLook {
public static void main(String[] args) {
System.out.println("Algorithms Supported in this JCE.");
System.out.println("====================");
// heading
System.out.println("Provider: type.algorithm -> className" + "\n aliases:" + "\n attributes:\n");
// discover providers
Provider[] providers = Security.getProviders();
for (Provider provider : providers) {
System.out.println("<><><>" + provider + "<><><>\n");
// discover services of each provider
for (Provider.Service service : provider.getServices()) {
System.out.println(service);
}
System.out.println();
}
}
}
It will show information like this for all the various algorithms available. (Note that this is actual output from the program above for some update level of Oracle/Sun Java 6 and it shows that SHA is equivalent to SHA-1 and SHA1. You can pass any of the three strings to MessageDigest and get the same result. But this depends on the Cryptography Provider (the JCE) and might not be the same.)
SUN: MessageDigest.SHA -> sun.security.provider.SHA
aliases: [SHA-1, SHA1]
attributes: {ImplementedIn=Software}
If you load additional providers (e.g. BouncyCastle) it will show those too.
I'm playing around with BouncyCastle 1.46 To my surprise, the catch-block in the snippet below is tripped quite often.
Security.addProvider(new BouncyCastleProvider());
final Set<String> found = new HashSet<String>();
final Set<String> missing = new HashSet<String>();
final DefaultSignatureAlgorithmIdentifierFinder finder = new DefaultSignatureAlgorithmIdentifierFinder();
for (Service service : new BouncyCastleProvider().getServices()) {
if ("Signature".equals(service.getType())) {
final String algorithm = service.getAlgorithm();
try {
finder.find(algorithm);
found.add(algorithm);
} catch (IllegalArgumentException ex) {
missing.add(algorithm);
}
}
}
System.out.println("Found: " + found);
System.out.println("Missing: " + missing);
I appear to be unable to use most of the algorithms through the Finder, even though Services exist that provide those algorithms. What am I doing wrong?
Update I've changed the code a little to illustrate the issue better. What might be of interest is that I am using the JDK1.5 version of BouncyCastle. The code above gives this output:
Found: [RIPEMD256WithRSAEncryption, MD5WithRSAEncryption, MD2WithRSAEncryption, SHA384WithRSAEncryption, SHA224WITHECDSA, SHA384WITHDSA, SHA256WITHDSA, SHA512WithRSAEncryption, SHA512WITHDSA, RIPEMD160WithRSAEncryption, SHA224WithRSAEncryption, SHA256WITHECDSA, RIPEMD128WithRSAEncryption, SHA384WITHECDSA, SHA256WithRSAEncryption, SHA512WITHECDSA, SHA1WithRSAEncryption, SHA224WITHDSA]
Missing: [SHA1WITHECNR, NONEwithECDSA, ECDSA, SHA512withRSA/PSS, RIPEMD160WITHECDSA, RSA, GOST3410, SHA256WITHECNR, MD5withRSA/ISO9796-2, SHA1WITHCVC-ECDSA, SHA384withRSA/PSS, SHA1withRSA/PSS, MD4WithRSAEncryption, RSASSA-PSS, SHA512WITHECNR, SHA256WITHCVC-ECDSA, SHA1withRSA/ISO9796-2, SHA224withRSA/PSS, SHA224WITHCVC-ECDSA, RAWRSASSA-PSS, SHA256withRSA/PSS, NONEWITHDSA, SHA384WITHECNR, RIPEMD160withRSA/ISO9796-2, DSA, ECGOST3410, SHA224WITHECNR, 1.2.840.113549.1.1.10]
I think that DefaultSignatureAlgorithmIdentifierFinder is part of the bcmail API. It returns algorithm identifiers recognized by this API. (Check Cryptographic Message Syntax) On the other hand the bouncy castle provider provides more algorithms. You may check the source of DefaultSignatureAlgorithmIdentifierFinder where the recognized algorithms are hardcoded:
algorithms.put("MD2WITHRSAENCRYPTION", PKCSObjectIdentifiers.md2WithRSAEncryption);
algorithms.put("MD2WITHRSA", PKCSObjectIdentifiers.md2WithRSAEncryption);
algorithms.put("MD5WITHRSAENCRYPTION", PKCSObjectIdentifiers.md5WithRSAEncryption);
algorithms.put("MD5WITHRSA", PKCSObjectIdentifiers.md5WithRSAEncryption);
algorithms.put("SHA1WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha1WithRSAEncryption);
algorithms.put("SHA1WITHRSA", PKCSObjectIdentifiers.sha1WithRSAEncryption);
algorithms.put("SHA224WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha224WithRSAEncryption);
algorithms.put("SHA224WITHRSA", PKCSObjectIdentifiers.sha224WithRSAEncryption);
algorithms.put("SHA256WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha256WithRSAEncryption);
algorithms.put("SHA256WITHRSA", PKCSObjectIdentifiers.sha256WithRSAEncryption);
algorithms.put("SHA384WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha384WithRSAEncryption);
algorithms.put("SHA384WITHRSA", PKCSObjectIdentifiers.sha384WithRSAEncryption);
algorithms.put("SHA512WITHRSAENCRYPTION", PKCSObjectIdentifiers.sha512WithRSAEncryption);
algorithms.put("SHA512WITHRSA", PKCSObjectIdentifiers.sha512WithRSAEncryption);
algorithms.put("SHA1WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
algorithms.put("SHA224WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
algorithms.put("SHA256WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
algorithms.put("SHA384WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
algorithms.put("SHA512WITHRSAANDMGF1", PKCSObjectIdentifiers.id_RSASSA_PSS);
algorithms.put("RIPEMD160WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
algorithms.put("RIPEMD160WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd160);
algorithms.put("RIPEMD128WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
algorithms.put("RIPEMD128WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd128);
algorithms.put("RIPEMD256WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
algorithms.put("RIPEMD256WITHRSA", TeleTrusTObjectIdentifiers.rsaSignatureWithripemd256);
algorithms.put("SHA1WITHDSA", X9ObjectIdentifiers.id_dsa_with_sha1);
algorithms.put("DSAWITHSHA1", X9ObjectIdentifiers.id_dsa_with_sha1);
algorithms.put("SHA224WITHDSA", NISTObjectIdentifiers.dsa_with_sha224);
algorithms.put("SHA256WITHDSA", NISTObjectIdentifiers.dsa_with_sha256);
algorithms.put("SHA384WITHDSA", NISTObjectIdentifiers.dsa_with_sha384);
algorithms.put("SHA512WITHDSA", NISTObjectIdentifiers.dsa_with_sha512);
algorithms.put("SHA1WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1);
algorithms.put("ECDSAWITHSHA1", X9ObjectIdentifiers.ecdsa_with_SHA1);
algorithms.put("SHA224WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224);
algorithms.put("SHA256WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256);
algorithms.put("SHA384WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384);
algorithms.put("SHA512WITHECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512);
algorithms.put("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
algorithms.put("GOST3411WITHGOST3410-94", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94);
algorithms.put("GOST3411WITHECGOST3410", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
algorithms.put("GOST3411WITHECGOST3410-2001", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
algorithms.put("GOST3411WITHGOST3410-2001", CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001);
Cheers!
Did you add BouncyCastle to the security providers? You can do that with this line:
Security.addProvider(new BouncyCastleProvider());
This answer is not directly related to BouncyCastle. But, I thought this would be useful for others:
In my case, I was using SpongyCastle. I got a similar problem:
org.e.h.p: cannot create signer: Provider SC does not provide SHA256WITHRSA
at org.e.h.a.a.a(SourceFile:101)
It turned out that proguard was removing some of the required classes. After adding the following in proguard config file:
-keep class org.spongycastle.** { *; }
the problem was resolved.
You can add Bouncy Castle to security providers on Your java platform in two steps:
1. Copy BC librarys (currently bcpkix-jdk15on-149.jar, bcprov-jdk15on-149.jar) to directory $JAVA_HOME/jre/lib/ext/
2. Register BC provider: edit file $JAVA_HOME/jre/lib/security/java.security and under line
security.provider.1=sun.security.provider.Sun
add Your BC provider
security.provider.2=org.bouncycastle.jce.provider.BouncyCastleProvider
Change numbers of rest providers. The whole block of providers should be similar to:
security.provider.1=sun.security.provider.Sun
security.provider.2=org.bouncycastle.jce.provider.BouncyCastleProvider
security.provider.3=sun.security.rsa.SunRsaSign
security.provider.4=sun.security.ec.SunEC
security.provider.5=com.sun.net.ssl.internal.ssl.Provider
security.provider.6=com.sun.crypto.provider.SunJCE
security.provider.7=sun.security.jgss.SunProvider
security.provider.8=com.sun.security.sasl.Provider
security.provider.9=org.jcp.xml.dsig.internal.dom.XMLDSigRI
security.provider.10=sun.security.smartcardio.SunPCSC