import java.util.*; /** * Unit test for RPCS3 MOAD-0004 defect. * * rpcs3-0004: np_structs_extra.cpp print_SceNpMatching2CreateJoinRoomRequest * logs raw SceNpMatching2SessionPassword bytes via buf_to_hexstring * at WARNING level (CWE-312: Cleartext Storage of Sensitive Information). * * The fix: replace buf_to_hexstring with a redacted placeholder so password * material never enters our log stream. */ public class Rpcs3NpPasswordTest { // Simulates the defective log serializer: formats raw bytes as hex static String logPassword_defective(byte[] passwordData) { StringBuilder sb = new StringBuilder(); for (byte b : passwordData) { sb.append(String.format("%02x", b)); } return sb.toString(); // raw hex of secret bytes in log output } // Simulates the fixed log serializer: redacts the password static String logPassword_fixed(byte[] passwordData) { return "[REDACTED " + passwordData.length + " bytes]"; } // Checks whether a log entry contains any of the secret bytes static boolean logContainsSecret(String logEntry, byte[] secret) { // Build hex representation of secret StringBuilder hex = new StringBuilder(); for (byte b : secret) hex.append(String.format("%02x", b)); return logEntry.contains(hex.toString()); } public static void main(String[] args) { int passed = 0; int failed = 0; // Representative SceNpMatching2SessionPassword: 8 bytes byte[] password = new byte[]{0x4e, 0x50, 0x33, (byte)0xDE, (byte)0xAD, (byte)0xBE, (byte)0xEF, 0x01}; // --- Test 1: defective path exposes raw bytes --- { String logEntry = logPassword_defective(password); boolean exposesSecret = logContainsSecret(logEntry, password); boolean ok = exposesSecret; // defective SHOULD contain the secret (confirming the defect) System.out.println((ok ? "PASS" : "FAIL") + " rpcs3-0004 defect confirmed: raw bytes in log = \"" + logEntry + "\""); if (ok) passed++; else failed++; } // --- Test 2: fixed path does NOT expose raw bytes --- { String logEntry = logPassword_fixed(password); boolean exposesSecret = logContainsSecret(logEntry, password); boolean ok = !exposesSecret; System.out.println((ok ? "PASS" : "FAIL") + " rpcs3-0004 fix: secret absent from log = \"" + logEntry + "\""); if (ok) passed++; else failed++; } // --- Test 3: fixed path still indicates presence of password (not null suppression) --- { String logEntry = logPassword_fixed(password); boolean ok = logEntry.contains("REDACTED") && logEntry.contains("8 bytes"); System.out.println((ok ? "PASS" : "FAIL") + " rpcs3-0004 fix: placeholder present = \"" + logEntry + "\""); if (ok) passed++; else failed++; } // --- Test 4: null/empty password handled gracefully --- { byte[] emptyPassword = new byte[0]; String logEntry = logPassword_fixed(emptyPassword); boolean ok = logEntry.contains("REDACTED") && logEntry.contains("0 bytes"); System.out.println((ok ? "PASS" : "FAIL") + " rpcs3-0004 fix: empty password placeholder = \"" + logEntry + "\""); if (ok) passed++; else failed++; } // --- Test 5: all-zero password still redacted (not treated as absent) --- { byte[] zeroPassword = new byte[8]; // all zeros String logEntry = logPassword_fixed(zeroPassword); boolean exposesSecret = logEntry.contains("00000000"); // would be all zeros hex boolean ok = !exposesSecret && logEntry.contains("REDACTED"); System.out.println((ok ? "PASS" : "FAIL") + " rpcs3-0004 fix: all-zero password redacted = \"" + logEntry + "\""); if (ok) passed++; else failed++; } System.out.printf("%n%d/%d tests passed%n", passed, passed + failed); if (failed > 0) System.exit(1); } }