java.io.IOException: DER length more than 4 bytes: 111

NareshFiserv
Occasional Visitor

java.io.IOException: DER length more than 4 bytes: 111

Good day!

I am trying to implement Message Level Encryption and testing with the keys and key_id. I am facing this issue, while testing to perform an encryption and decryption using the keys and key_id. This is to test, whether the keys and key_id, along with suggested code is working successfully or not. 

I have downloaded key_id and key files( server_cert_b1eaf5f7-2f6f-4429-96cb-8a2ee312ae42.pem and client_cert_b1eaf5f7-2f6f-4429-96cb-8a2ee312ae42.pem )from the Visa Developer portal. I am able to the encrypt the payload, however facing an issue while decrypting the encryptedResponse. 

-- below is the encrypt logic -----------

// MLE Changes
private static final String BEGIN_CERT = "-----BEGIN CERTIFICATE-----";
private static final String END_CERT = "-----END CERTIFICATE-----";
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 ENC_DATA = "encData";
// MLE Changes

------ Below is the code used for encrypting the payload message -----
private 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 RSAPublicKey getRSAPublicKey() throws CertificateException, IOException {
String mleServerPublicCertificatePath = <path to read file>;

String pemEncodedPublicKey = IOUtils.readFileToString(new File(mleServerPublicCertificatePath), Charset.forName("UTF-8"));
Base64 base64 = new Base64(
pemEncodedPublicKey.replaceAll(BEGIN_CERT, "").replaceAll(END_CERT, ""));
Certificate cf = CertificateFactory.getInstance("X.509")
.generateCertificate(new ByteArrayInputStream(base64.decode()));
return (RSAPublicKey) cf.getPublicKey();
}

 

----------------

--- below is the error I see after debugging while decrypting the response -----

java.io.IOException: DER length more than 4 bytes: 111

--- below is the code ------

------ Below is the code used for decrypting the payload message -----
public <T> T getDecryptedPayload(Object encryptedPayload, Class<T> returnType) {
String response = encryptedPayload.toString();
T decryptedResponse = null;
try {
JWEObject jweObject = JWEObject.parse(response);
//If you have used passphrase while generating the csr make sure you the same while getting the private key. Otherwise decryption will fail.
jweObject.decrypt(new RSADecrypter(getRSAPrivateKey()));
response = jweObject.getPayload().toString();
ObjectMapper mapper = new ObjectMapper();
decryptedResponse = mapper.readValue(response, returnType);
} catch (Exception e) {
e.printStackTrace();
}
return decryptedResponse;
}


private PrivateKey getRSAPrivateKey() throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
//If you have used passphrase while generating the csr make sure you the same while reading the private key. Otherwise decryption will fail.

String mleClientPrivateKeyPath = ondotConfiguration.getConnectorConfigProperty(VisaDPSConstants.MLE_CLIENT_PRIVATE_CERT_PATH, VisaDPSConstants.EMPTY_STR);
String pemEncodedKey = IOUtils.readFileToString(new File(mleClientPrivateKeyPath), Charset.forName("UTF-8"));
Base64 base64 = new Base64(pemEncodedKey.replaceAll(BEGIN_RSA_PRIVATE_KEY, "").replaceAll(END_RSA_PRIVATE_KEY, ""));
ASN1Sequence primitive = (ASN1Sequence) ASN1Sequence.fromByteArray(base64.decode());  -- exception raised at this line , base64 object is formed correctly but not able to form ANSISequence
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);
}

----------------- Encrypted Data -------------

{"encData":"eyJlbmMiOiJBMTI4R0NNIiwiaWF0IjoxNzM1NTUwNzE2MjE0LCJhbGciOiJSU0EtT0FFUC0yNTYiLCJraWQiOiJiMWVhZjVmNy0yZjZmLTQ0MjktOTZjYi04YTJlZTMxMmFlNDIifQ.BW3-jEZAmZDgJncJZI1ND7azACc28yuB2OU6p155Ff6MReUGihr7H3RA5tectwV1TPrLqdhv7ymXpJ3_7LKLew94goiYca_meW5aPVsQkICHdihG2_HeAAsrbdKhoXFie0USx5-7lvas7rtcGc52tep-L5ttJTBgyG0muaoimdplLXwhx3YXB0qgSUoR9w3c3xksVjT9Zu1AEC6k3lMk9kzxu--kZzDJiobQ8w2oQ66shnye6G4afAf3aBePhm6rNt5JF09JGPmrKbpYX2WBIqH1_VGZRjuAvHFV6Klb0uhXKX-VuF8pkiYyj16HRjzX75PEzH-IWYfG3nIIpuuRJA.QJyUxqk4Xnh3wWOx.yYl74ps75j8E3T2LbkwGmSuX2JwEvwRj5huiGxmHPWeOe82PhY_e1mMdmcWpVP1F0FXtxQlnUD4pAhPZ6VfBgkvZUfczM4BpFBewwMzKyMwHa56h6lZmZwXlqWX1vwakrw0eKfMbB5gEqBebKuYdzOkGK57jDWRggGhrgE48h9JTPxB8IjxlXfLlX1CnxoEnL-M5NwPJnQx74agMHDuxZeVTvopnmXum3Zera-xO6ORlxuc3afmoCvOIKuFr__toJ1GoOZM5bg7f5uPhTX-9nmHTKyHCQjzd42Ct6_mToZIcCqoYTD-b-Fkhfm9jsKsrOs_3c9aFMO73P_WXcBoD0LkYZs17sWWqLzVtWM9LtqkY2vjPaAd0kwaGqbKuUqImjdGNAVZoDmeDijs46sL6_WFYKsw9DgV3_kQgAQBaSMZcUxSU3jSrNrACZAhwBgHAsow8n8bQRAnhg2NnZbnE9k1dW_Bql3lRIQ5KNmYJOCuk1cpKHJo.0li7l8nCpIG4G9i0bsQmKA"}

2 REPLIES 2
API_Products
Visa Developer Support Specialist

Re: java.io.IOException: DER length more than 4 bytes: 111

Hey @NareshFiserv,

 

The error `java.io.IOException: DER length more than 4 bytes: 111` typically indicates a problem with parsing the DER-encoded private key.

 

Let's address a few potential issues and solutions:

 

1. Ensure Correct PEM Formatting: Ensure that the PEM file for the private key is correctly formatted. The private key should start with `-----BEGIN RSA PRIVATE KEY-----` and end with `-----END RSA PRIVATE KEY-----`.

2. Check Base64 Decoding:  Verify that the Base64 decoding is performed correctly and that the decoded output is a valid DER-encoded byte array.

3. Use BouncyCastle Library: Sometimes, using a dedicated library for handling cryptographic operations can simplify the process and handle edge cases more gracefully. The BouncyCastle library is a popular choice for Java cryptography.

 

Here is an example using BouncyCastle to load the RSA private key:

 

```java
// START 
import org.bouncycastle.asn1.ASN1Primitive;
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import org.bouncycastle.openssl.PEMParser;
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;

import java.io.FileReader;
import java.io.IOException;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.spec.PKCS8EncodedKeySpec;

public class KeyLoader {

private static final String BEGIN_RSA_PRIVATE_KEY = "-----BEGIN RSA PRIVATE KEY-----";
private static final String END_RSA_PRIVATE_KEY = "-----END RSA PRIVATE KEY-----";

public static PrivateKey getRSAPrivateKey(String filePath) throws IOException {
try (PEMParser pemParser = new PEMParser(new FileReader(filePath))) {
Object object = pemParser.readObject();
PrivateKeyInfo privateKeyInfo = PrivateKeyInfo.getInstance(object);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyInfo.getEncoded());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePrivate(keySpec);
} catch (Exception e) {
throw new IOException("Failed to load RSA private key", e);
}
}

public static void main(String[] args) {
try {
PrivateKey privateKey = getRSAPrivateKey("path/to/your/private_key.pem");
System.out.println("Private Key: " + privateKey);
} catch (IOException e) {
e.printStackTrace();
}
}
}
// END 
```

 

Steps:
1. Add BouncyCastle Library: Ensure you have the BouncyCastle library in your dependencies. If using Maven, add the following to your `pom.xml`:

 

```xml
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.68</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.68</version>
</dependency>
```

 

2. Update Decryption Logic: Use the `getRSAPrivateKey` method in your decryption logic to load the private key.

 

This approach ensures that the private key is correctly parsed and handles common issues with DER encoding.

 




Thanks,

Diana



Was your question answered? Don't forget to click on "Accept as Solution" to help other devs find the answer to the same question.

NareshFiserv
Occasional Visitor

Re: java.io.IOException: DER length more than 4 bytes: 111

Hi Team, 

As suggested in the previous thread by Diana, I have used standalone code to decrypt, in this process, private key file reading and generating PrivateKey object is not successful and getting exception as below.

-------- code --------

public static PrivateKey getRSAPrivateKey(String filePath) throws IOException {
Certificate cert = null;
try (PEMParser pemParser = new PEMParser(new FileReader(filePath))) {
Object object = pemParser.readObject();
if (object instanceof X509CertificateHolder) {
X509CertificateHolder certificateHolder = (X509CertificateHolder) object;
System.out.println("Certificate String---> " + certificateHolder.toString());
cert = certificateHolder.toASN1Structure();
} else {
System.out.println("Unknown object type ---> " + object.getClass().getName());
}
PrivateKeyInfo privateKeyInfo = PrivateKeyInfo.getInstance(object); - exception raised at this line
Caused by: java.lang.IllegalArgumentException: unknown object in getInstance: org.bouncycastle.cert.X509CertificateHolder
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyInfo.getEncoded());
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
return keyFactory.generatePrivate(keySpec);
} catch (Exception e) {
System.out.println(" Exception raised --->"+e.getLocalizedMessage());
throw new IOException("Failed to load RSA private key", e);
}
}

Exception details: 

Caused by: java.lang.IllegalArgumentException: unknown object in getInstance: org.bouncycastle.cert.X509CertificateHolder

I would like to mention couple of points here. 

1.

I have downloaded Server Encryption Certification(Public Key) and Client Encryption Certification (Private Key) through Visa Developer Center -> project ->credentials tab as below

 

cert-image.PNG

 

2. 

When seen the content of private key, it has prefix and suffix as below, 

-----BEGIN CERTIFICATE-----
MIIDqjCCApKgAwIBAgIICM+qrVZn7TowDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVVMxHTAbBgNVBAoMFERldmVsb3BtZW50IFBsYXRmb3JtMSMwIQYDVQQDDBpQYXltZW50IFNhbmRib3ggSXNzdWluZyBDQTAeFw0yNDEyMTgwOTMzNDJaFw0yNTEyMTgwOTMzNDFaMC8xLTArBgNVBAMMJDBiYWU4NDg3LWExNmMtNDk0MS1hNDE3LTA3NTExZjBjMTA0OTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOA2Hz52i+zOjAK9DDDs8XZWuiLQ/nSUW0Y1AdLHhjIHt2Dgdo1/1pe5Ks7eETmydbdp824sRqOAziZ5AxovAF2siN9n+D6S6bcq1Fdzoy0j0CJVh6snAOz5rHSAp+MTBG482oXeY5mivXy8XR3Cpcpno2YkPsfp1++drJ5BAlRT2y0vu3X0LUhCpXO4Bx18W6x9espJfRXfxIzmmZrC6ilIw2VSkEv5EjksuqqlPtn2JhIi/biPk4+9Yyz4oKKIIQvhETEa4y+PY+glD8hTo7HlJTNTHAjn7htWO8bpdvYVdFjlDNzi5M8N6PpPRXCt/XrsFzfDxvXb16qoClNUyZ0CAwEAAaOBpzCBpDAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFL5uQgXmVcbnec1ZhvVRh38WEQA5MC8GA1UdEQQoMCaCJDBiYWU4NDg3LWExNmMtNDk0MS1hNDE3LTA3NTExZjBjMTA0OTATBgNVHSUEDDAKBggrBgEFBQcDAjAdBgNVHQ4EFgQU+Nu3ruBtPqDs1MjVX1xiSeeKq0EwDgYDVR0PAQH/BAQDAgXgMA0GCSqGSIb3DQEBCwUAA4IBAQBKDaspHbinKeJJW98nfdy62wD1a/AuYf9K8pb1kh/E8nSoGthQ46NGFY98kJWxmCtCoBOKPjhwBUQ3zZKCRRt3L84P6UbqPTt37RbBCZsWoDMT3o1IGNOkNXNnV0a3bd829/eexty5Yxrbt2aNcp/Q9ei2hgN4aTkC7EKFLkOohKatambF9xjBL4r9DucbMmGs4cMbTFqsgUHK5KlNIZNhnLwjhJfY6nvn9Iqx6CaoLCRq0AkkGP1CLmNDI2PS2jIR9Ebi/woEIKNUMUyOmlPsxS2BQayBnw44lAPC6OURLkSvnfJU4bbzTf4Wc3bJI+4rZCfnIRJtcpjWcZGYVdG3
-----END CERTIFICATE-----

3.

<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.68</version>
</dependency>

<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.68</version>
</dependency>

 

I hope, there is no issue with private file, 

 

Please suggest further in generating the private key and successful decryption code.