As per my knowledge both are same but one is working on one PC while same code says:
javax.crypto.NoSuchPaddingException: OAEPWITHSHA-256ANDMGF1PADDING unavailable with RSA on another machine.
When I am removing dash - from the name (OAEPWITHSHA256ANDMGF1PADDING) it starts running on another machine but leads error to some other line bad padding exception.
What could be the reason?
Sample code for Hint
I am using jdk1.7.0_71 32bit:
private byte[] decryptSecretKeyData(byte[] encryptedSecretKey, byte[] iv, PrivateKey privateKey) throws Exception
{
try {
Provider provider= new sun.security.pkcs11.SunPKCS11(keyStoreFile1);
Security.addProvider(provider);
LOG.info("**************Inside decryptSecretKeyData***********************");
Cipher rsaCipher = Cipher.getInstance("RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING", provider);
// decrypting the session key with rsa no padding.
rsaCipher.init(Cipher.DECRYPT_MODE, privateKey);
/* The reason is RSA OAEP SHA256 is not supported in HSM. */
byte[] decKey = rsaCipher.doFinal(encryptedSecretKey);
OAEPEncoding encode = new OAEPEncoding(new RSAEngine(), new SHA256Digest(), iv);
LOG.info("******************RSAPublicKey rsaPublickey = (*****************************");
java.security.interfaces.RSAPublicKey rsaPublickey = (java.security.interfaces.RSAPublicKey) publicKeyFile;
RSAKeyParameters keyParams = new RSAKeyParameters(false, rsaPublickey.getModulus(), EXPONENT);
encode.init(false, keyParams);
LOG.info("******************encode.processBlock(decKey, 0, decKey.length);************************");
byte decryptedSecKey[] = encode.processBlock(decKey, 0, decKey.length);
return decryptedSecKey;
} catch (InvalidCipherTextException e) {
LOG.info("*******************Failed to decrypt AES secret key using RSA :**********************");
throw new Exception("Failed to decrypt AES secret key using RSA :" + e.toString());
}
}
RSA/ECB/OAEPWITHSHA256ANDMGF1PADDING and RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING are different alias but both refers to the same algorithms, so in this sense there is not difference at all.
The thing is that you're using a PKCS#11 (cryptographic token interface) to cipher your data. According to java PKCS#11 reference:
The Sun PKCS#11 provider, in contrast to most other providers, does not implement cryptographic algorithms itself.
Instead, it acts as a bridge between the Java JCA and JCE APIs and the
native PKCS#11 cryptographic API, translating the calls and
conventions between the two. This means that Java applications calling
standard JCA and JCE APIs can, without modification, take advantage of
algorithms offered by the underlying PKCS#11 implementations, such as,
for example,
Cryptographic Smartcards, Hardware cryptographic accelerators, and
High performance software implementations. Note that Java SE only
facilitates accessing native PKCS#11 implementations, it does not
itself include a native PKCS#11 implementation. However, cryptographic
devices such as Smartcards and hardware accelerators often come with
software that includes a PKCS#11 implementation, which you need to
install and configure according to manufacturer's instructions.
Summarized, if you're using a PKCS#11, the use of the algorithms depends on vendors native implementation (.dll on windows, .so on linux ...) and some times on specific program connector so: check if in the both PCs you're using the same drivers/program version for your PKCS#11 token and the both are correctly installed because probably there is an error in one of them which doesn't allows you to use RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING correctly.
Hope this helps,
Both algorithms are provided by the different security provider. The
RSA/ECB/OAEPWITHSHA256ANDMGF1PADDING
is provided by the Bouncy Castle provider while
RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING
is provided by the SUN JCE provider. In our case, we are able to successfully use Bouncy Castle provider algorithm but if I replace that with SUN JCE algorithm then it gives following error:
Exception in thread "main" javax.crypto.BadPaddingException: lHash mismatch
at sun.security.rsa.RSAPadding.unpadOAEP(RSAPadding.java:425)
at sun.security.rsa.RSAPadding.unpad(RSAPadding.java:274)
at com.sun.crypto.provider.RSACipher.doFinal(RSACipher.java:356)
at com.sun.crypto.provider.RSACipher.engineDoFinal(RSACipher.java:382)
The situation is more complex.
The RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING is nominally provided by SunJCE.
The RSA/NONE/OAEPWITHSHA256ANDMGF1PADDING is provided by BC.
However BC is able to take over and act as a provider of RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING if it is installed before the SunJCE provider (using Security.installProviderAt). Unfortunately, BC does not parametrize this algorithm the same way as SunJCE does it. BC implementation of that algorithm is thus different (!) than one provided by SunJCE, which will be source of padding errors.
SunJCE RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING is using SHA-1 for MGF1 function and SHA-256 for label hash (which is almost always an empty byte array and therefore a static value).
BC RSA/NONE/OAEPWITHSHA256ANDMGF1PADDING is using SHA-256 for MGF1 function and SHA-256 for label hash. BC will also use the same parameters if it is being asked to provide RSA/ECB/OAEPWITHSHA-256ANDMGF1PADDING.
Advice: always explicitly specify security provider to make sure that correct provider is used. Alternatively explicitly specify the OAEP parameters and don't rely on defaults (recommended).
I've reported the issue to BC, so maybe it will get fixed.
Related
We have a client server system where client(Android phone) and server(spring ) both are using java.security.KeyFactory to get an instance of java.security.KeyFactory as shown below:
KeyFactory factory = KeyFactory.getInstance("RSA");
But if we do that, when we use this factory to encrypt data, the server gives a different output and the client gives different output. When we checked providers, it was coming to SunRsaSign for server and was OpenSSLRSA for the client. So we tried to set the same on the client using the following:
KeyFactory factory = KeyFactory.getInstance("RSA", "SunRsaSign");
But we get java.security.NoSuchProviderException error. Similarly when we try to set OpenSSLRSA on server, they also face the same error.
Complete code to encrypt is same on server and client is following:
String pubKey = "<key here>"
byte[] keyData = DatatypeConverter.parseHexBinary(pubKey);
System.out.println("key data" + Arrays.toString(keyData));
KeyFactory factory = KeyFactory.getInstance("RSA");
//System.out.println("provide = " + factory.getProvider());
PublicKey pub = factory.generatePublic(new X509EncodedKeySpec(keyData));
Cipher encryptCipher = Cipher.getInstance("RSA");
encryptCipher.init(Cipher.ENCRYPT_MODE, pub);
byte[] secretMessageBytes = msg.getBytes(StandardCharsets.UTF_8);
System.out.println("secret msg" +Arrays.toString(secretMessageBytes));
byte[] encryptedMessageBytes = encryptCipher.doFinal(secretMessageBytes);
System.out.println("enc data" +Arrays.toString(encryptedMessageBytes));
encryptedMessageBytes generated are different. Can that be a problem? I think it is because of different Providers being used by different platform.
Can somebody pls help me on how to set the provider for KeyFactory or how to remove the decryption error(javax.crypto.BadPaddingException)?
The posted code, used on both the Android and Java/Spring sides, only specifies the algorithm and not the padding when instantiating the cipher:
Cipher.getInstance("RSA")
Without explicit specification of the padding, the default padding of the providers of both sides is used. However, different providers generally define different default paddings (e.g. NoPadding, PKCS1Padding or OAEPPadding). The different paddings cause the decryption to fail, because a prerequisite for successful decryption is that the same padding is used as for encryption.
To avoid such things, the padding should always be specified when instantiating the cipher, especially in a cross-platform environment, e.g.:
Cipher.getInstance("RSA/ECB/PKCS1Padding")
On the left is the algorithm and on the right the padding. Note that the middle part (ECB) has no meaning for RSA (it is an artifact of using the scheme of symmetric encryption specifying the operation mode in the middle, which is not defined for asymmetric encryption).
Fixing the issue with the explicit specification of the padding proves that the padding was indeed the problem.
I can only speculate about the default paddings used in your environment.
I could not test the OpenSSLRSA provider, as it is not available in my environment. On my machine Android (API Level 28, P) applies the AndroidOpenSSL provider (aka Conscrypt). This defaults to NoPadding, while Java's SunJCE provider defaults to PKCS1Padding. Encryption on Android and decryption on Java would result in an exception (or non-removed padding for the other direction).
You can determine the default padding of your environment as follows: Encrypt with the default padding (by specifying only the algorithm) and vary the padding on decryption until decryption is successful and the original plaintext is decrypted.
I've noticed something weird when generating key pairs from AWS Lambda - every time I run the code it generates identical keys. I am aware that Lambda containers are frozen after each invocation and this is probably why the underlying JCE classes are loaded from memory and keep their initial state. The code in question is relatively simple:
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA", "BC");
keyPairGen.initialize(2048);
KeyPair keyPair = keyPairGen.generateKeyPair();
RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
return new RSAKey.Builder(rsaPublicKey).privateKey(rsaPrivateKey)
.keyID(kid).keyUse(KeyUse.SIGNATURE)
I tried both the vanilla provider and Bouncy Castle but the result is the same - identical key pairs when Lambda is "warm". Once the container is terminated and restarted from a "cold" state, I get a new and different set of keys.
I'm also using AWS Cognito and the service is served through both API Gateway and CloudFront.
Any ideas how to "refresh" the underlying JCE classes?
To answer my own question, the culprit was actually CloudFront. Even with API caching turned off in API Gateway, CloudFront still caches the responses for some API requests.
If someone comes across the same problem, the solution is to "bust" the CloudFront cache by appending a query parameter to the request URL:
GET /api/generateKeyPair?timestamp=1507843759370
I'm trying to sign and validate signature in RSA+SHA1 with PKCS1 v2.0 padding.
I haven't found in the documentation (JDK or JCE) which algorithm/padding I have to use.
It seems that I've to use OAEP padding but I didn't succeed:
For validation, I've tried via Cipher in DECRYPT_MODE with the public key sent by the signer:
Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWITHSHA1ANDMGF1PADDING", "SunJCE");
cipher.init(Cipher.DECRYPT_MODE, pub); //exception !
But I got an exception:
java.security.InvalidKeyException: OAEP cannot be used to sign or verify signatures
at com.sun.crypto.provider.RSACipher.init(RSACipher.java:303)
at com.sun.crypto.provider.RSACipher.engineInit(RSACipher.java:207)
...
(For unknown reason, OAEPWITHSHA1ANDMGF1PADDING is only accepted with ENCRYPT_MODE+PUBLIC KEY or DECRYPT_MODE+PRIVATE KEY, the opposite that I want to do....)
For signature, I'm trying to use Signature but I don't know which algorithm to use:
Signature mySig2 = Signature.getInstance("SHA1withRSAandMGF1");
Doesn't work :
java.security.NoSuchAlgorithmException: SHA1withRSAandMGF1 Signature not available
at java.security.Signature.getInstance(Signature.java:229)
...
Can somebody help me?
Hope I'm not too late to respond to this. Very recently I had to face the same issue with RSA encryption. My Signer wants to do the verification to the data that is sent through POST. This is how I managed to work on that in Java.
Step 1 - Add following into your project
bcprov-ext-jdk14-1.45.jar
commons-codec-1.4.jar
Step 2 - Declare your Cipher
private Cipher cipher;
Step 3 - Call below in your class constructor
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
this.cipher = Cipher.getInstance("RSA/NONE/OAEPWithSHA1AndMGF1Padding");
Step 4 - Get your PublicKey from public key text string
public PublicKey getPublic(String pubKey) throws Exception {
byte[] publicBytes = Base64.decodeBase64(pubKey);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePublic(keySpec);
}
Step 5 - Verification method
public boolean verfyRSA(String signature, String data, PublicKey key) throws Exception {
byte[] sign = Base64.decodeBase64(signature);
byte[] dat = Base64.decodeBase64(data);
Signature rsaVerify = Signature.getInstance("SHA1withRSAandMGF1");
rsaVerify.initVerify(key);
rsaVerify.update(dat);
return rsaVerify.verify(sign);
}
Step 6 - Usage
Yourclass yc = new YourClass();
PublicKey publicKey = yc.getPublic("Your PublicKey without leading and trailing -------text------");
boolean b = yc.verfyRSA("POST_Signature", "POST_data", publicKey);
Hope this helps. Mind the getInstance() parameters. These are the ones that do the trick. Cheers
I'm trying to sign and validate signature in RSA+SHA1 with PKCS1 v2.0 padding.
This is a strange requirement.
First of all, RSA is secure even if PKCS#1 v1.5 compatible padding is used. It is however not secure when SHA-1 is used to hash the input/message, for the simple reasons that SHA-1 is not considered secure anymore for that kind of purpose.
Second, although PKCS#1 v2.0 contains a new padding mode for signature generation called PSS or - to be more precise - RSASSA-PSS it also contains the single signature generation mode from 1.5 of the standard called RSASSA-PKCS1-v1_5. So at least in theory your requirements are not clear.
Now PKCS#1 v1.5 padding for encryption is known to be broken against padding oracle attacks. For that reason alone, OAEP encryption introduced in PKCS#1 v2.0 is generally available.
PSS for signature generation has a better security proof, but PKCS#1 v1.5 is still considered secure. This is likely why Oracle / SUN didn't include PSS within Java SE JCA. If you want it you can vote for it here.
I haven't found in the documentation (JDK or JCE) which algorithm/padding I have to use. It seems that I've to use OAEP padding but I didn't succeed.
OAEP stands for Optimal Asymmetric Encryption Padding. Padding for encryption cannot/should not be used for signature generation.
After adding the Bouncy Castle provider the RSA PSS becomes available. You can use your (insecure) scheme with "SHA1withRSA/PSS" or indeed the identical "SHA1withRSAandMGF1". It's likely that Oracle's Java SE will support RSA/PSS once the TLS 1.3 specification is finalized.
I have a master key in an HSM and I want to derive it with a given diversifier.
I am quite new to JCA/JCE, and a bit lost with KeyGenerator, SecretKeyFactory, ... especially since all parameters are strings.
I want to use AES or HmacSha1.
It seems I need to use a SecretKeyFactory, and provide a KeySpecs. But which type of KeySpecs?
(I have seen a post on that topic, but I didn't seem an HSM was used.)
Thanks.
You can derive key using:
password-based derivation (PKCS#5) as described in Deriving a secret from a master key using JCE/JCA or
emulate C_Derive from PKCS#11 using encryption as described in PKCS11 deriveKey() and encrypt() returning different results for 3DES
to use HSM from JCA/JCE APIs, you need to add the corresponding provider to the JCA/JCE APIs and then specify the the provider parameter to request for that specific provider implementation.
For example:
int slot = 0;
Provider provider = new au.com.safenet.crypto.provider.SAFENETProvider(slot);
Security.addProvider(provider);
final String PROVIDER = provider.getName(); // "SAFENET", "SAFENET.1", ...
KeyGenerator keyGen = KeyGenerator.getInstance("DESede", PROVIDER);
Key baseKey = keyGen.generateKey();
Cipher desCipher = Cipher.getInstance("DESede/CBC/PKCS5Padding", PROVIDER);
desCipher.init(Cipher.ENCRYPT_MODE, baseKey);
byte[] derived = desCipher.doFinal("diversification data".getBytes());
Note that if you need to do key derivation very often, you might consider to use your provider's PCKS#11 wrapper for Java (e.g. jcprov from SafeNet) or other APIs so that you can be more explicit about its session management and be more efficient about resource usage.
I am trying to find out which of the Sun cryptographic providers should be used for generating an RSA key pair that will be used encrypting data in Java. I know that there are other providers such as Bouncy Castle, but I would like to use one of the Sun Providers. (algorithm: RSA, key size 2048)
For example, on my machine I currently have the following providers available:
SUN 1.7
SunRsaSign 1.7
SunEC 1.7
SunJSSE 1.7
SunJCE 1.7
SunJGSS 1.7
SunSASL 1.7
XMLDSig 1.0
SunPCSC 1.7
I have previously used the provider SunRsaSign for generating an RSA key pair that was used for signing data. But I am not sure if it is safe or if it makes sense to use a key pair generated by SunRsaSign for encrypting data.
I have noticed that the provider SunJSSE contains: sun.security.rsa.RSAKeyPairGenerator
My main question is: which of the Sun providers should be used for generating an RSA key pair that will be used for encryption (not signing)?
Also, should a key pair generated by SunRsaSign only ever by used for signing data? Because the name of this provider contains the word "Sign" I assumed that it is specifically intended for signing, but now I am not so sure.
Finally, is it safe and does it makes sense to use a key pair generated by SunJSSE for general encryption? if so, what is the difference between an RSA generated by SunJSSE and an RSA key pair generated by SunJSSE?
Of course you can have a look through all registered providers:
Provider[] providers = Security.getProviders();
for (Provider provider : providers) {
Set<Service> services = provider.getServices();
for (Service service : services) {
service.getAlgorithm();
// find algorithm and retrieve service information
}
}
but in this case the solution would be simpler:
KeyPairGenerator kpgen = KeyPairGenerator.getInstance("RSA");
Provider kpgenProv = kpgen.getProvider();
System.out.printf("Provider : %s%nInfo: %s%n", kpgenProv.getName(), kpgenProv.toString());
Result:
Provider : SunRsaSign
Info: SunRsaSign version 1.7
This is probably the only provider for your runtime that will generate RSA key pairs. Note that encryption is part of javax.security, which means that it was originally an optional package/provider (because of import/export control of cryptography).
RSA key creation is not encryption so it is included with SunRsaSign which provides RSA signature generation. As signatures are not used to provide confidentiality they are regarded as less sensitive cryptographic operations.
The documentation indicates that SunJCE does not provide RSA keys, which can be founded on SunRsaSign. Such that, using both are necessary, one to get the keys ans other to get the cipher.
from: https://docs.oracle.com/javase/8/docs/technotes/guides/security/SunProviders.html#SunJCEProvider
The SunRsaSign Provider------------------------------------------------------------
KeyPairGenerator:
RSA 1024 Keysize must range between 512 and 65536 bits, the latter of which is unnecessarily large
The SunJCE Provider----------------------------------------------------------------
KeyPairGenerator
Diffie-Hellman (DH) 1024 Keysize must be a multiple of 64, ranging from 512 to 2048 (inclusive).