Skip to content

PasswordUtil.encode() misinterprets {algo} plaintext as ciphertext#35242

Open
una-tapa wants to merge 1 commit into
OpenLiberty:integrationfrom
una-tapa:fix-TS022437211-passwordutil-curly-brace-encoding
Open

PasswordUtil.encode() misinterprets {algo} plaintext as ciphertext#35242
una-tapa wants to merge 1 commit into
OpenLiberty:integrationfrom
una-tapa:fix-TS022437211-passwordutil-curly-brace-encoding

Conversation

@una-tapa

@una-tapa una-tapa commented Jul 6, 2026

Copy link
Copy Markdown
Member

Overview

Passwords starting with a {something} pattern (e.g. vault/PIM-generated passphrases like '{abc}def' or '{redacted}***{/redacted}') were being misinterpreted as already-encoded values by PasswordUtil.encode().

Root cause:

In encode(String, String, Map), getCryptoAlgorithm() returns a non-null token for any string matching the {.*} pattern at the start. The code then unconditionally attempted to decode the string before re-encoding, without first checking whether the extracted token is actually a valid crypto algorithm (xor, aes, hash, or custom).

This caused two failure modes:

  1. NullPointerException: passwordDecode() returned null when the bogus algorithm caused decipher to fail, and decoded_string.trim() at line 274 threw NPE. Seen with '{redacted}***{/redacted}' inputs.
  2. Silent data loss: for XOR, the internal decode returned an empty string, producing '{xor}' with no ciphertext payload. Confirmed by Keith Jabcuga's recreation program

Fix:

Add isValidCryptoAlgorithm() guards to both the throw-on-already-encoded branch and the decode-then-re-encode branch. A {something} pattern in the input is now only acted upon when 'something' is a known algorithm. Literal plaintext passwords with curly-brace patterns fall through and are encoded directly as plaintext, which is the correct behaviour.

Existing behaviour is preserved:

  • Already-encoded passwords still throw InvalidPasswordEncodingException.
  • Passwords encoded with a different valid algorithm are still decoded and re-encoded as before.

Tests added in PasswordUtilTest:

  • testEncodePasswordStartingWithCurlyBracePattern
  • testEncodeWithKeyPasswordStartingWithCurlyBracePattern

Fixes #35243

Passwords starting with a {something} pattern (e.g. vault/PIM-generated
passphrases like '{abc}def' or '{redacted}***{/redacted}') were being
misinterpreted as already-encoded values by PasswordUtil.encode().

Root cause:
In encode(String, String, Map), getCryptoAlgorithm() returns a non-null
token for any string matching the {.*} pattern at the start. The code
then unconditionally attempted to decode the string before re-encoding,
without first checking whether the extracted token is actually a valid
crypto algorithm (xor, aes, hash, or custom).

This caused two failure modes:
1. NullPointerException: passwordDecode() returned null when the bogus
   algorithm caused decipher to fail, and decoded_string.trim() at
   line 274 threw NPE. Seen with '{redacted}***{/redacted}' inputs.
2. Silent data loss: for XOR, the internal decode returned an empty
   string, producing '{xor}' with no ciphertext payload. Confirmed by
   Keith Jabcuga's recreation program

Fix:
Add isValidCryptoAlgorithm() guards to both the throw-on-already-encoded
branch and the decode-then-re-encode branch. A {something} pattern in
the input is now only acted upon when 'something' is a known algorithm.
Literal plaintext passwords with curly-brace patterns fall through and
are encoded directly as plaintext, which is the correct behaviour.

Existing behaviour is preserved:
- Already-encoded passwords still throw InvalidPasswordEncodingException.
- Passwords encoded with a different valid algorithm are still decoded
  and re-encoded as before.

Tests added in PasswordUtilTest:
- testEncodePasswordStartingWithCurlyBracePattern
- testEncodeWithKeyPasswordStartingWithCurlyBracePattern
@una-tapa

una-tapa commented Jul 6, 2026

Copy link
Copy Markdown
Member Author

!build
(view Open Liberty Personal Build - ⚠️ completed with warnings.)

Note: Target locations of links might be accessible only to IBM employees.

@LibbyBot

LibbyBot commented Jul 6, 2026

Copy link
Copy Markdown
Member

Code analysis and actions

DO NOT DELETE THIS COMMENT.
  • 1 product code files were changed.
  • Please describe in a separate comment how you tested your changes.

@una-tapa

una-tapa commented Jul 7, 2026

Copy link
Copy Markdown
Member Author

Build finished with one warning in javaBatch GUI FAT. Not related to the encryption/decryption.

com.ibm.ws.ui.tool.javaBatch_fat.gui 61 1 16m 18s Ubuntu / Java 21 outputjunitbuild log

Also the locally created jar files passed the recreation program created by our support team (Keith)

=== Example 1: Encoding with XOR and Custom Key ===
Plain Password: mySecretPassword123
XOR Encoded: {xor}MiYMOjwtOisPPiwsKDAtO25tbA==
XOR Decoded: mySecretPassword123

=== Example 2: Encoding with XOR and Custom Key ===
Plain Password: {mySecretPassword123}
XOR Encoded: {xor}SjANPj.... ← non-empty now ✅
XOR Decoded: {mySecretPassword123} ← round-trips correctly ✅

@una-tapa una-tapa requested a review from Zech-Hein July 7, 2026 17:02
@una-tapa una-tapa self-assigned this Jul 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PasswordUtil.encode() misinterprets {algo} plaintext passwords as pre-encoded ciphertext

2 participants