Team,
Below is the code, getting padding exception while decrypting .
------- code -----------------
public class Test2 {
private static final String BEGIN_RSA_PRIVATE_KEY = "-----BEGIN RSA PRIVATE KEY-----";
private static final String END_RSA_PRIVATE_KEY = "-----END RSA PRIVATE KEY-----";
private static final String BEGIN_CERT = "-----BEGIN CERTIFICATE-----";
private static final String END_CERT = "-----END CERTIFICATE-----";
public static void main(String[] args) throws Exception{
try {
String encryptedString = getEncryptedPayload("This is a sample text");
getDecryptedPayload(encryptedString, String.class);
} catch (IOException e) {
e.printStackTrace();
}
}
private static String getEncryptedPayload(Object payload) throws CertificateException, JOSEException, IOException {
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
String plainText = payload == null ? "" : payload.toString();
JWEHeader.Builder headerBuilder = new JWEHeader.Builder(JWEAlgorithm.RSA_OAEP_256, EncryptionMethod.A128GCM);
String keyId = "b1eaf5f7-2f6f-4429-96cb-8a2ee312ae42";
headerBuilder.keyID(keyId);
headerBuilder.customParam("iat", System.currentTimeMillis());
JWEObject jweObject = new JWEObject(headerBuilder.build(), new Payload(plainText));
jweObject.encrypt(new RSAEncrypter(getRSAPublicKey()));
//return "{\"encData\":\""+jweObject.serialize()+"\"}";
return jweObject.serialize();
}
private static RSAPublicKey getRSAPublicKey() throws CertificateException, IOException {
String mleServerPublicCertificatePath = "C:/code/server_cert_b1eaf5f7-2f6f-4429-96cb-8a2ee312ae42.pem";
String pemEncodedPublicKey = IOUtils.readFileToString(new File(mleServerPublicCertificatePath), Charset.forName("UTF-8"));
com.nimbusds.jose.util.Base64 base64 = new com.nimbusds.jose.util.Base64( pemEncodedPublicKey.replaceAll(BEGIN_CERT, "").replaceAll(END_CERT, ""));
Certificate cf = CertificateFactory.getInstance("X.509").generateCertificate(new ByteArrayInputStream(base64.decode()));
return (RSAPublicKey) cf.getPublicKey();
}
public static <T> T getDecryptedPayload(Object encryptedPayload, Class<T> returnType) {
String response = encryptedPayload.toString();
T decryptedResponse = null;
try {
JWEObject jweObject = JWEObject.parse(response);
jweObject.decrypt(new RSADecrypter(getRSAPrivateKey("C:/code/key_b1eaf5f7-2f6f-4429-96cb-8a2ee312ae42.pem")));
// in above line, RSAPrivateKey is formed successfully, but there is padding exception
response = jweObject.getPayload().toString();
ObjectMapper mapper = new ObjectMapper();
decryptedResponse = mapper.readValue(response, returnType);
} catch (Exception e) {
e.printStackTrace();
}
return decryptedResponse;
}
private static PrivateKey getRSAPrivateKey(String filePath) throws Exception {
String pemEncodedKey = IOUtils.readFileToString(new File(filePath), Charset.forName("UTF-8"));
com.nimbusds.jose.util.Base64 base64 = new com.nimbusds.jose.util.Base64(pemEncodedKey.replaceAll(BEGIN_RSA_PRIVATE_KEY, "").replaceAll(END_RSA_PRIVATE_KEY, ""));
ASN1Sequence primitive = (ASN1Sequence) ASN1Sequence.fromByteArray(base64.decode());
Enumeration<?> e = primitive.getObjects();
BigInteger v = ((ASN1Integer) e.nextElement()).getValue();
int version = v.intValue();
if (version != 0 && version != 1) {
throw new IllegalArgumentException("wrong version for RSA private key");
}
BigInteger modulus = ((ASN1Integer) e.nextElement()).getValue();
((ASN1Integer) e.nextElement()).getValue();
BigInteger privateExponent = ((ASN1Integer) e.nextElement()).getValue();
((ASN1Integer) e.nextElement()).getValue();
((ASN1Integer) e.nextElement()).getValue();
((ASN1Integer) e.nextElement()).getValue();
((ASN1Integer) e.nextElement()).getValue();
((ASN1Integer) e.nextElement()).getValue();
RSAPrivateKeySpec privateKeySpec = new RSAPrivateKeySpec(modulus, privateExponent);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return (PrivateKey) keyFactory.generatePrivate(privateKeySpec);
}
}
----------------- Exception details ----------
com.nimbusds.jose.JOSEException: Padding error in decryption
at com.nimbusds.jose.crypto.RSA_OAEP_256.decryptCEK(RSA_OAEP_256.java:119)
at com.nimbusds.jose.crypto.RSADecrypter.decrypt(RSADecrypter.java:242)
at com.nimbusds.jose.JWEObject.decrypt(JWEObject.java:415)
at org.example.Test2.getDecryptedPayload(Test2.java:93)
at org.example.Test2.main(Test2.java:50)
Caused by: javax.crypto.BadPaddingException: Padding error in decryption
at java.base/com.sun.crypto.provider.RSACipher.doFinal(RSACipher.java:389)
-----------------
Hi @NareshFiserv, Thank you for reaching out. An agent will get back to you as soon as possible. Until then, if any community member has information that may be helpful, feel free to reply in this thread.
I am using a sample string to encrypt which returns encryptedString, and using the same encryptedString to decrypt. Is this way of testing correct ? Or, is there any specific way to test this encryption / decryption mechanism end to end ?
1.
I have downloaded the privateKey(key_b1eaf5f7-2f6f-4429-96cb-8a2ee312ae42.pem) file and publicKey (server_cert_b1eaf5f7-2f6f-4429-96cb-8a2ee312ae42.pem) file from Vis Developer Platform portal.
2.
I am using a sample string to encrypt which returns encryptedString, and using the same encryptedString to decrypt.
Is this way of testing correct ?
Or, is there any specific way to test this encryption / decryption mechanism end to end ?
Hey @NareshFiserv,
Certainly, here's the revised code without the bold emphasis:
```java
// START
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.RSADecrypter;
import com.nimbusds.jose.crypto.RSAEncrypter;
import org.apache.commons.io.IOUtils;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Sequence;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.RSAPrivateKeySpec;
import java.util.Enumeration;
public class Test2 {
private static final String BEGIN_RSA_PRIVATE_KEY = "-----BEGIN RSA PRIVATE KEY-----";
private static final String END_RSA_PRIVATE_KEY = "-----END RSA PRIVATE KEY-----";
private static final String BEGIN_CERT = "-----BEGIN CERTIFICATE-----";
private static final String END_CERT = "-----END CERTIFICATE-----";
public static void main(String[] args) {
try {
String encryptedString = getEncryptedPayload("This is a sample text");
getDecryptedPayload(encryptedString, String.class);
} catch (Exception e) {
e.printStackTrace();
}
}
private static String getEncryptedPayload(Object payload) throws CertificateException, JOSEException, IOException {
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
String plainText = payload == null ? "" : payload.toString();
JWEHeader.Builder headerBuilder = new JWEHeader.Builder(JWEAlgorithm.RSA_OAEP_256, EncryptionMethod.A128GCM);
String keyId = "b1eaf5f7-2f6f-4429-96cb-8a2ee312ae42";
headerBuilder.keyID(keyId);
headerBuilder.customParam("iat", System.currentTimeMillis());
JWEObject jweObject = new JWEObject(headerBuilder.build(), new Payload(plainText));
jweObject.encrypt(new RSAEncrypter(getRSAPublicKey()));
return jweObject.serialize();
}
private static RSAPublicKey getRSAPublicKey() throws CertificateException, IOException {
String mleServerPublicCertificatePath = "C:/code/server_cert_b1eaf5f7-2f6f-4429-96cb-8a2ee312ae42.pem";
String pemEncodedPublicKey = IOUtils.readFileToString(new File(mleServerPublicCertificatePath), Charset.forName("UTF-8"));
pemEncodedPublicKey = pemEncodedPublicKey.replaceAll(BEGIN_CERT, "").replaceAll(END_CERT, "").replaceAll("\\s", "");
com.nimbusds.jose.util.Base64 base64 = new com.nimbusds.jose.util.Base64(pemEncodedPublicKey);
Certificate cf = CertificateFactory.getInstance("X.509").generateCertificate(new ByteArrayInputStream(base64.decode()));
return (RSAPublicKey) cf.getPublicKey();
}
private static <T> T getDecryptedPayload(Object encryptedPayload, Class<T> returnType) {
String response = encryptedPayload.toString();
T decryptedResponse = null;
try {
JWEObject jweObject = JWEObject.parse(response);
jweObject.decrypt(new RSADecrypter(getRSAPrivateKey("C:/code/key_b1eaf5f7-2f6f-4429-96cb-8a2ee312ae42.pem")));
response = jweObject.getPayload().toString();
ObjectMapper mapper = new ObjectMapper();
decryptedResponse = mapper.readValue(response, returnType);
} catch (Exception e) {
e.printStackTrace();
}
return decryptedResponse;
}
private static PrivateKey getRSAPrivateKey(String filePath) throws Exception {
String pemEncodedKey = IOUtils.readFileToString(new File(filePath), Charset.forName("UTF-8"));
pemEncodedKey = pemEncodedKey.replaceAll(BEGIN_RSA_PRIVATE_KEY, "").replaceAll(END_RSA_PRIVATE_KEY, "").replaceAll("\\s", "");
com.nimbusds.jose.util.Base64 base64 = new com.nimbusds.jose.util.Base64(pemEncodedKey);
ASN1Sequence primitive = (ASN1Sequence) ASN1Sequence.fromByteArray(base64.decode());
Enumeration<?> e = primitive.getObjects();
BigInteger v = ((ASN1Integer) e.nextElement()).getValue();
int version = v.intValue();
if (version != 0 && version != 1) {
throw new IllegalArgumentException("wrong version for RSA private key");
}
BigInteger modulus = ((ASN1Integer) e.nextElement()).getValue();
((ASN1Integer) e.nextElement()).getValue();
BigInteger privateExponent = ((ASN1Integer) e.nextElement()).getValue();
RSAPrivateKeySpec privateKeySpec = new RSAPrivateKeySpec(modulus, privateExponent);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePrivate(privateKeySpec);
}
}
// END
```
Key Points:
1. Remove White Spaces:
Ensure that all whitespaces, including newline characters, are removed when parsing the PEM-encoded keys. This is done using `.replaceAll("\\s", "")`.
2. Encoding and Decoding:
Double-check the encoding and decoding process for any errors.
3. Exception Handling:
Added more comprehensive exception handling to catch and display errors during the encryption/decryption process.
Testing:
- Encrypt a sample string using the `getEncryptedPayload` method.
- Immediately decrypt the encrypted string using the `getDecryptedPayload` method.
Hello ,
I have modified code as suggested by you removed white spaces as well.
1. While using with client cert (
client_cert_b1eaf5f7-2f6f-4429-96cb-8a2ee312ae42.pem
)and private key cert (
key_b1eaf5f7-2f6f-4429-96cb-8a2ee312ae42.pem
), encrypt and decrypt is working as expected.
2. While using with server cert ( server_cert_b1eaf5f7-2f6f-4429-96cb-8a2ee312ae42.pem) and private key cert ( key_b1eaf5f7-2f6f-4429-96cb-8a2ee312ae42.pem ) files, decrypt is failing with Padding exception.
3. Tried changing code with other possibilities, but getting some other exceptions and finally, not able to resolve the issue .
4. Please suggest the working code so that we can perform a full cycle of encrypt / decrypt process using server cert encrypt and private cert decrypt.
package org.example;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.RSADecrypter;
import com.nimbusds.jose.crypto.RSAEncrypter;
import com.nimbusds.jose.util.IOUtils;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.security.KeyFactory;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAPrivateKeySpec;
//import java.util.Base64;
//import org.apache.commons.codec.binary.Base64;
import com.nimbusds.jose.util.Base64;
import java.util.Date;
import java.util.Enumeration;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.asm.TypeReference;
import static org.example.Working.getCardRequest;
public class WorkSimpleText {
private static final String BEGIN_RSA_PRIVATE_KEY = "-----BEGIN RSA PRIVATE KEY-----";
private static final String END_RSA_PRIVATE_KEY = "-----END RSA PRIVATE KEY-----";
//private static final String BEGIN_RSA_PRIVATE_KEY = "-----BEGIN PRIVATE KEY-----";
//private static final String END_RSA_PRIVATE_KEY = "-----END PRIVATE KEY-----";
private static final String BEGIN_CERT = "-----BEGIN CERTIFICATE-----";
private static final String END_CERT = "-----END CERTIFICATE-----";
public static void main(String[] args) throws Exception {
/*String jsonPayload = "{\n" +
" \"amount\": \"124.05\",\n" +
" \"senderAddress\": \"901 Metro Center Blvd\"\n" +
"}";*/
String jsonPayload2 = "this is a simple text";
System.out.println("Sample text to be encrypted => "+jsonPayload2);
String encryptedString = getEncryptedPayload(jsonPayload2);
System.out.println("Sample text in encrypted format => "+encryptedString);
String decrptString = getDecryptedPayload(encryptedString);
System.out.println("decrypted String: => " + decrptString);
/*PayloadDTO decrypted = getDecryptedPayload(encryptedString, PayloadDTO.class);
//PayloadDTO decrypted = getDecryptedPayload(encryptedString, TypeReference<CardRequest>);
System.out.println("Decrypted amount: " + decrypted.getAmount());
System.out.println("Decrypted address: " + decrypted.getSenderAddress());*/
}
private static String getEncryptedPayload(Object payload) throws CertificateException, JOSEException, IOException {
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
String plainText = payload == null ? "" : payload.toString();
//String plainText = payload == null ? "" : mapper.writeValueAsString(payload);
JWEHeader.Builder headerBuilder = new JWEHeader.Builder(JWEAlgorithm.RSA_OAEP_256, EncryptionMethod.A128GCM);
String keyId = "b1eaf5f7-2f6f-4429-96cb-8a2ee312ae42";
headerBuilder.keyID(keyId);
headerBuilder.customParam("iat", System.currentTimeMillis());
JWEObject jweObject = new JWEObject(headerBuilder.build(), new Payload(plainText));
jweObject.encrypt(new RSAEncrypter(getRSAPublicKey()));
return "{\"encData\":\""+jweObject.serialize()+"\"}";
//return jweObject.serialize();
}
private static RSAPublicKey getRSAPublicKey() throws CertificateException, IOException {
//String mleServerPublicCertificatePath = "C:/code/client_cert_b1eaf5f7-2f6f-4429-96cb-8a2ee312ae42.pem"; // with this cert its working
String mleServerPublicCertificatePath = "C:/code/server_cert_b1eaf5f7-2f6f-4429-96cb-8a2ee312ae42.pem";
String pemEncodedPublicKey = IOUtils.readFileToString(new File(mleServerPublicCertificatePath), Charset.forName("UTF-8"));
pemEncodedPublicKey = pemEncodedPublicKey.replaceAll(BEGIN_CERT, "").replaceAll(END_CERT, "").replaceAll("\\s", "");
com.nimbusds.jose.util.Base64 base64 = new com.nimbusds.jose.util.Base64(pemEncodedPublicKey);
Certificate cf = CertificateFactory.getInstance("X.509").generateCertificate(new ByteArrayInputStream(base64.decode()));
return (RSAPublicKey) cf.getPublicKey();
}
//public static <T> T getDecryptedPayload(Object encryptedPayload, Class<T> returnType) {
public static String getDecryptedPayload(Object encryptedPayload) {
try {
String response = encryptedPayload.toString();
ObjectMapper mapper = new ObjectMapper();
// Extract the encData field from the JSON structure
String encryptedData = mapper.readTree(response).get("encData").asText();
JWEObject jweObject = JWEObject.parse(encryptedData);
PrivateKey privateKey = getRSAPrivateKey("C:/code/key_b1eaf5f7-2f6f-4429-96cb-8a2ee312ae42.pem");
jweObject.decrypt(new RSADecrypter(privateKey));
String decryptedJson = jweObject.getPayload().toString();
return decryptedJson;
} catch (Exception e) {
System.err.println("Decryption failed: " + e.getMessage());
e.printStackTrace();
return null;
}
}
private static PrivateKey getRSAPrivateKey(String filePath) throws Exception {
String pemEncodedKey = IOUtils.readFileToString(new File(filePath), Charset.forName("UTF-8"));
//System.out.println("pemEncodedKey: \n" + pemEncodedKey);
//com.nimbusds.jose.util.Base64 base64 = new com.nimbusds.jose.util.Base64(pemEncodedKey.replaceAll(BEGIN_RSA_PRIVATE_KEY, "").replaceAll(END_RSA_PRIVATE_KEY, ""));
pemEncodedKey = pemEncodedKey.replaceAll(BEGIN_RSA_PRIVATE_KEY, "").replaceAll(END_RSA_PRIVATE_KEY, "").replaceAll("\\s", "");
com.nimbusds.jose.util.Base64 base64 = new com.nimbusds.jose.util.Base64(pemEncodedKey);
ASN1Sequence primitive = (ASN1Sequence) ASN1Sequence.fromByteArray(base64.decode());
Enumeration<?> e = primitive.getObjects();
BigInteger v = ((ASN1Integer) e.nextElement()).getValue();
int version = v.intValue();
if (version != 0 && version != 1) {
throw new IllegalArgumentException("wrong version for RSA private key");
}
BigInteger modulus = ((ASN1Integer) e.nextElement()).getValue();
((ASN1Integer) e.nextElement()).getValue(); // public exponent
BigInteger privateExponent = ((ASN1Integer) e.nextElement()).getValue();
while (e.hasMoreElements()) {
e.nextElement();
}
RSAPrivateKeySpec privateKeySpec = new RSAPrivateKeySpec(modulus, privateExponent);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePrivate(privateKeySpec);
}
}