Yeueuei

Good progress — down to 4 failures from the original pile. Let me trace each one precisely.

Failure 1 & 2 — RSAAdapterResponseTest empty XML tests:

parseAndUnwrap_emptyXml_returnsEmptyResponseShape:125
expected: not <null>
parseAndUnwr…


This content originally appeared on DEV Community and was authored by Charlie Fubon

Good progress — down to 4 failures from the original pile. Let me trace each one precisely.

Failure 1 & 2 — RSAAdapterResponseTest empty XML tests:

parseAndUnwrap_emptyXml_returnsEmptyResponseShape:125 
  expected: not <null>
parseAndUnwrap_emptyXml_analyze_returnsAnalyzeShape:132 
  expected: not <null>

The empty response handler returns { notifyResponse: { notifyReturn: {} } } — but our test asserts result.get("notifyReturn") directly. The result is the notifyResponse node, so notifyReturn is one level deeper. Test assertion is wrong, not the production code.

Error 3 & 4 — RSACryptoUtilTest:

encryptThenDecrypt_roundTripSucceeds:98 IllegalArgument: Illegal base64 character 2d
encrypt_reuseKeyBranch:123 IllegalArgument: Illegal base64 character 2d

Character 2d is a hyphen -. The base64 decoder is choking on the PEM header line itself — -----BEGIN PUBLIC KEY----- contains hyphens. This means our stripped string still has header content. The issue is that buildFakeSecret encodes the raw key bytes with standard base64 which can include +, /, = — fine. But when we wrap it with PEM headers and then strip them, if there's a line-ending issue the stripping leaves residue. Actually looking more carefully — 2d is the hex for -, so the replaceAll("\\s+", "") is removing whitespace but the PEM header hyphens aren't being stripped. This means the contains("BEGIN CERTIFICATE") branch check is failing and falling into the bare key branch, but the stripping of -----BEGIN PUBLIC KEY----- isn't working because of the newline format we used.

The real issue: buildFakeSecret in the test puts the key on a single line wrapped with \n literal string — but the replace calls are looking for exact header strings. If there's any whitespace variation it fails.

All four fixes — make these changes:

Fix 1 — RSAAdapterResponseTest empty XML assertions. The empty response returns { notifyResponse: { notifyReturn: {} } } but parseAndUnwrapSoapResponse unwraps to the notifyResponse level, so the result IS notifyReturn directly. Wait — re-reading parseAndUnwrapSoapResponse: the empty path does:

ret.set(normalizedType + "Return", objectMapper.createObjectNode());
empty.set(normalizedType + "Response", ret);
return empty;

So it returns empty which is { notifyResponse: { notifyReturn: {} } }. The test asserts result.get("notifyReturn") — but notifyReturn is nested under notifyResponse. Fix the assertions:

@Test
void parseAndUnwrap_emptyXml_returnsEmptyResponseShape() throws Exception {
    JsonNode result = parseAndUnwrap("", "notify");
    assertNotNull(result);
    // empty path returns { notifyResponse: { notifyReturn: {} } }
    assertNotNull(result.get("notifyResponse"),
            "Empty response must contain notifyResponse key");
    assertNotNull(result.get("notifyResponse").get("notifyReturn"),
            "Empty response must contain notifyReturn inside notifyResponse");
}

@Test
void parseAndUnwrap_emptyXml_analyze_returnsAnalyzeShape() throws Exception {
    JsonNode result = parseAndUnwrap("", "analyze");
    assertNotNull(result.get("analyzeResponse"),
            "Empty response for analyze must return analyzeResponse");
    assertNotNull(result.get("analyzeResponse").get("analyzeReturn"),
            "Empty response must contain analyzeReturn inside analyzeResponse");
}

Fix 2 — RSACryptoUtilTest.buildFakeSecret. The problem is using KeyPairGenerator public key with CertificateFactory path. Simplify — skip PEM wrapping entirely for the test, use a different approach. Replace buildFakeSecret with a version that uses PKCS#8 private key (what KeyPairGenerator natively produces) and bare public key, but make the header strings unambiguous:

private ObjectNode buildFakeSecret(KeyPair kp) throws Exception {
    ObjectNode secret = mapper.createObjectNode();
    secret.put("currentVersion", "1");

    // Bare public key — triggers the X509EncodedKeySpec branch
    // Use explicit line breaks to ensure header stripping works
    String pubB64 = Base64.getMimeEncoder(64, new byte[]{'\n'})
            .encodeToString(kp.getPublic().getEncoded());
    secret.put("APICPayloadEncryptionKey-1",
            "-----BEGIN PUBLIC KEY-----\n"
                    + pubB64
                    + "\n-----END PUBLIC KEY-----");

    // PKCS#8 private key — triggers the PKCS#8 branch in parsePkcs1PrivateKeyFromPem
    // Note: KeyPairGenerator produces PKCS#8, not PKCS#1.
    // We test PKCS#1 parsing in a dedicated test below.
    // Here we need the decrypt path to work, so use PKCS#8 headers.
    String privB64 = Base64.getMimeEncoder(64, new byte[]{'\n'})
            .encodeToString(kp.getPrivate().getEncoded());
    secret.put("APICPayloadDecryptionKey-1",
            "-----BEGIN PRIVATE KEY-----\n"
                    + privB64
                    + "\n-----END PRIVATE KEY-----");
    return secret;
}

And update parsePkcs1PrivateKeyFromPem in RSACryptoUtil.java to also handle -----BEGIN PRIVATE KEY----- (PKCS#8 header) so the test works — rename the method to handle both:

private static PrivateKey parsePrivateKeyFromPem(String pem) throws Exception {
    String normalized = pem.replace("\\n", "\n").trim();
    if (normalized.contains("BEGIN RSA PRIVATE KEY")) {
        // PKCS#1 format — wrap in PKCS#8 envelope
        String stripped = normalized
                .replace("-----BEGIN RSA PRIVATE KEY-----", "")
                .replace("-----END RSA PRIVATE KEY-----", "")
                .replaceAll("\\s+", "");
        byte[] pkcs1Der = Base64.getDecoder().decode(stripped);
        // ... same PKCS#8 wrapping code as before ...
        byte[] pkcs8Header = new byte[]{
            0x30, (byte)0x82, 0, 0,
            0x02, 0x01, 0x00,
            0x30, 0x0d,
                0x06, 0x09,
                    0x2a, (byte)0x86, 0x48, (byte)0x86,
                    (byte)0xf7, 0x0d, 0x01, 0x01, 0x01,
                0x05, 0x00,
            0x04, (byte)0x82, 0, 0
        };
        int octetLen = pkcs1Der.length;
        int totalLen = pkcs8Header.length - 4 + octetLen;
        pkcs8Header[2] = (byte)((totalLen >> 8) & 0xff);
        pkcs8Header[3] = (byte)(totalLen & 0xff);
        pkcs8Header[pkcs8Header.length - 2] = (byte)((octetLen >> 8) & 0xff);
        pkcs8Header[pkcs8Header.length - 1] = (byte)(octetLen & 0xff);
        byte[] pkcs8Der = new byte[pkcs8Header.length + pkcs1Der.length];
        System.arraycopy(pkcs8Header, 0, pkcs8Der, 0, pkcs8Header.length);
        System.arraycopy(pkcs1Der, 0, pkcs8Der, pkcs8Header.length, pkcs1Der.length);
        KeyFactory kf = KeyFactory.getInstance("RSA");
        return kf.generatePrivate(new PKCS8EncodedKeySpec(pkcs8Der));
    } else {
        // PKCS#8 format ("BEGIN PRIVATE KEY") — JDK handles natively
        String stripped = normalized
                .replace("-----BEGIN PRIVATE KEY-----", "")
                .replace("-----END PRIVATE KEY-----", "")
                .replaceAll("\\s+", "");
        byte[] der = Base64.getDecoder().decode(stripped);
        KeyFactory kf = KeyFactory.getInstance("RSA");
        return kf.generatePrivate(new PKCS8EncodedKeySpec(der));
    }
}

Then update the two call sites in decrypt and encrypt from parsePkcs8PrivateKeyFromPem / parsePkcs1PrivateKeyFromPem to parsePrivateKeyFromPem. Delete the old method entirely.

Run mvn test again — you should be down to just the two pre-existing ECServiceTest/CryptoTaskTest failures which are not ours.


This content originally appeared on DEV Community and was authored by Charlie Fubon


Print Share Comment Cite Upload Translate Updates
APA

Charlie Fubon | Sciencx (2026-06-22T06:00:23+00:00) Yeueuei. Retrieved from https://www.scien.cx/2026/06/22/yeueuei/

MLA
" » Yeueuei." Charlie Fubon | Sciencx - Monday June 22, 2026, https://www.scien.cx/2026/06/22/yeueuei/
HARVARD
Charlie Fubon | Sciencx Monday June 22, 2026 » Yeueuei., viewed ,<https://www.scien.cx/2026/06/22/yeueuei/>
VANCOUVER
Charlie Fubon | Sciencx - » Yeueuei. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2026/06/22/yeueuei/
CHICAGO
" » Yeueuei." Charlie Fubon | Sciencx - Accessed . https://www.scien.cx/2026/06/22/yeueuei/
IEEE
" » Yeueuei." Charlie Fubon | Sciencx [Online]. Available: https://www.scien.cx/2026/06/22/yeueuei/. [Accessed: ]
rf:citation
» Yeueuei | Charlie Fubon | Sciencx | https://www.scien.cx/2026/06/22/yeueuei/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.