Skip to content

Instantly share code, notes, and snippets.

@hbouhadji
Created October 24, 2025 13:48
Show Gist options
  • Save hbouhadji/99735b386b29e8dc57a9b506f84d5453 to your computer and use it in GitHub Desktop.
Save hbouhadji/99735b386b29e8dc57a9b506f84d5453 to your computer and use it in GitHub Desktop.
import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.Base64;
import java.util.Map;
public class DecryptLoginInfo {
private static final byte[][] DECRYPTION_MATRIX = {
new byte[] { 1, 4, (byte)-1, (byte)-31, (byte)-9, 20, (byte)-1, 6 },
new byte[] { 0, (byte)-2, 0, (byte)-7, 2, 4, (byte)-1, 1 },
new byte[] { 0, (byte)-6, 1, (byte)-8, 2, 5, (byte)-3, 4 },
new byte[] { 0, (byte)-11, 2, (byte)-32, (byte)-1, 20, (byte)-6, 12 },
new byte[] { 0, 5, (byte)-1, 19, 1, (byte)-12, 3, (byte)-6 },
new byte[] { 0, 4, (byte)-1, (byte)-6, (byte)-3, 4, 1, 0 },
new byte[] { 0, 9, (byte)-1, 24, (byte)-2, (byte)-15, 5, (byte)-8 },
new byte[] { 0, 0, 0, (byte)-8, (byte)-1, 5, 0, 1 },
};
private static int byteToInt(byte[] data) {
return (data[0] & 0xFF)
| ((data[1] & 0xFF) << 8)
| ((data[2] & 0xFF) << 16)
| ((data[3] & 0xFF) << 24);
}
private static void transformBlock(byte[] src, int srcOffset, byte[] dst, int dstOffset, byte[][] matrix) {
for (int col = 0; col < 8; col++) {
int acc = 0;
for (int row = 0; row < 8; row++) {
int s = src[srcOffset + row];
int m = matrix[row][col];
acc = (byte) (acc + s * m);
}
dst[dstOffset + col] = (byte) acc;
}
}
private static void transform(byte[] src, byte[] dst, int length, byte[][] matrix) {
if (length % 8 != 0) {
throw new IllegalArgumentException("length must be a multiple of 8");
}
for (int offset = 0; offset < length; offset += 8) {
transformBlock(src, offset, dst, offset, matrix);
}
}
public static void main(String[] args) throws Exception {
if (args.length == 0) {
System.err.println("Usage: java DecryptLoginInfo <path-to-loginInfo.dat>");
System.exit(1);
}
Path path = Paths.get(args[0]);
byte[] fileBytes = Files.readAllBytes(path);
if (fileBytes.length < 4) {
throw new IllegalArgumentException("File too short");
}
int length = byteToInt(Arrays.copyOfRange(fileBytes, 0, 4));
int paddedLength = (length + 7) & ~7;
if (4 + paddedLength > fileBytes.length) {
throw new IllegalArgumentException("File truncated: expected " + paddedLength + " encrypted bytes");
}
byte[] encrypted = Arrays.copyOfRange(fileBytes, 4, 4 + paddedLength);
byte[] decryptedPadded = new byte[paddedLength];
transform(encrypted, decryptedPadded, paddedLength, DECRYPTION_MATRIX);
byte[] decrypted = Arrays.copyOf(decryptedPadded, length);
String base64 = new String(decrypted, StandardCharsets.UTF_8);
String normalized = base64.replace("\r", "").replace("\n", "");
byte[] serialized = Base64.getDecoder().decode(normalized);
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(serialized));
Object obj = ois.readObject();
ois.close();
if (!(obj instanceof Map)) {
throw new IllegalStateException("Expected a Map but got " + obj.getClass());
}
Map<?, ?> map = (Map<?, ?>) obj;
if (map.isEmpty()) {
System.out.println("No entries found.");
} else {
for (Map.Entry<?, ?> entry : map.entrySet()) {
System.out.println(entry.getKey() + " -> " + entry.getValue());
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment