commit 16a36b0fb7b3f0cd6fd7eca387519b5f0b7185ab Author: TheEntropyShard Date: Tue Jan 24 20:56:36 2023 +0300 Initial commit diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..0548357 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..af4628b --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml new file mode 100644 index 0000000..e96534f --- /dev/null +++ b/.idea/uiDesigner.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/JDarkroom.iml b/JDarkroom.iml new file mode 100644 index 0000000..54b8c26 --- /dev/null +++ b/JDarkroom.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/out/production/JDarkroom/me/theentropyshard/jdarkroom/DecodingData$1.class b/out/production/JDarkroom/me/theentropyshard/jdarkroom/DecodingData$1.class new file mode 100644 index 0000000..5e08e8a Binary files /dev/null and b/out/production/JDarkroom/me/theentropyshard/jdarkroom/DecodingData$1.class differ diff --git a/out/production/JDarkroom/me/theentropyshard/jdarkroom/DecodingData$2.class b/out/production/JDarkroom/me/theentropyshard/jdarkroom/DecodingData$2.class new file mode 100644 index 0000000..ca2b30d Binary files /dev/null and b/out/production/JDarkroom/me/theentropyshard/jdarkroom/DecodingData$2.class differ diff --git a/out/production/JDarkroom/me/theentropyshard/jdarkroom/DecodingData.class b/out/production/JDarkroom/me/theentropyshard/jdarkroom/DecodingData.class new file mode 100644 index 0000000..30c3604 Binary files /dev/null and b/out/production/JDarkroom/me/theentropyshard/jdarkroom/DecodingData.class differ diff --git a/out/production/JDarkroom/me/theentropyshard/jdarkroom/JDarkroom.class b/out/production/JDarkroom/me/theentropyshard/jdarkroom/JDarkroom.class new file mode 100644 index 0000000..d1a3313 Binary files /dev/null and b/out/production/JDarkroom/me/theentropyshard/jdarkroom/JDarkroom.class differ diff --git a/out/production/JDarkroom/me/theentropyshard/jdarkroom/Main.class b/out/production/JDarkroom/me/theentropyshard/jdarkroom/Main.class new file mode 100644 index 0000000..73d1253 Binary files /dev/null and b/out/production/JDarkroom/me/theentropyshard/jdarkroom/Main.class differ diff --git a/out/production/JDarkroom/me/theentropyshard/jdarkroom/View$1$1.class b/out/production/JDarkroom/me/theentropyshard/jdarkroom/View$1$1.class new file mode 100644 index 0000000..2d71582 Binary files /dev/null and b/out/production/JDarkroom/me/theentropyshard/jdarkroom/View$1$1.class differ diff --git a/out/production/JDarkroom/me/theentropyshard/jdarkroom/View$1.class b/out/production/JDarkroom/me/theentropyshard/jdarkroom/View$1.class new file mode 100644 index 0000000..a885b76 Binary files /dev/null and b/out/production/JDarkroom/me/theentropyshard/jdarkroom/View$1.class differ diff --git a/out/production/JDarkroom/me/theentropyshard/jdarkroom/View$2$1.class b/out/production/JDarkroom/me/theentropyshard/jdarkroom/View$2$1.class new file mode 100644 index 0000000..8c249e9 Binary files /dev/null and b/out/production/JDarkroom/me/theentropyshard/jdarkroom/View$2$1.class differ diff --git a/out/production/JDarkroom/me/theentropyshard/jdarkroom/View$2$2.class b/out/production/JDarkroom/me/theentropyshard/jdarkroom/View$2$2.class new file mode 100644 index 0000000..8d2daf0 Binary files /dev/null and b/out/production/JDarkroom/me/theentropyshard/jdarkroom/View$2$2.class differ diff --git a/out/production/JDarkroom/me/theentropyshard/jdarkroom/View$2.class b/out/production/JDarkroom/me/theentropyshard/jdarkroom/View$2.class new file mode 100644 index 0000000..a52baac Binary files /dev/null and b/out/production/JDarkroom/me/theentropyshard/jdarkroom/View$2.class differ diff --git a/out/production/JDarkroom/me/theentropyshard/jdarkroom/View$3.class b/out/production/JDarkroom/me/theentropyshard/jdarkroom/View$3.class new file mode 100644 index 0000000..2755581 Binary files /dev/null and b/out/production/JDarkroom/me/theentropyshard/jdarkroom/View$3.class differ diff --git a/out/production/JDarkroom/me/theentropyshard/jdarkroom/View$4.class b/out/production/JDarkroom/me/theentropyshard/jdarkroom/View$4.class new file mode 100644 index 0000000..17fc0f7 Binary files /dev/null and b/out/production/JDarkroom/me/theentropyshard/jdarkroom/View$4.class differ diff --git a/out/production/JDarkroom/me/theentropyshard/jdarkroom/View.class b/out/production/JDarkroom/me/theentropyshard/jdarkroom/View.class new file mode 100644 index 0000000..f92e9c8 Binary files /dev/null and b/out/production/JDarkroom/me/theentropyshard/jdarkroom/View.class differ diff --git a/src/me/theentropyshard/jdarkroom/DecodingData.java b/src/me/theentropyshard/jdarkroom/DecodingData.java new file mode 100644 index 0000000..92a0bb1 --- /dev/null +++ b/src/me/theentropyshard/jdarkroom/DecodingData.java @@ -0,0 +1,137 @@ +package me.theentropyshard.jdarkroom; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public final class DecodingData { + /** + * Offset, where Akuda locker code located + */ + public static final long CODE_OFFSET = 0x00002D58L; + + /** + * Key for decoding Internet Code + */ + public static final byte[] KEY = { + 0x25, 0x1F, 0x1D, 0x17, 0x13, 0x11, 0x0B, 0x07 + }; + + /** + * Table for decoding bytes from save file, english and russian letters + * Huge thing... + */ + public static final Map SAVE_INDEX_TABLE = Collections.unmodifiableMap( + new HashMap() {{ + this.put(1, "A А"); + this.put(2, "B Б"); + this.put(3, "C Ц"); + this.put(4, "D Д"); + this.put(5, "E Е"); + this.put(6, "F Ф"); + this.put(7, "G Г"); + this.put(8, "H Ю"); + this.put(9, "I И"); + this.put(10, "J Й"); + this.put(11, "K К"); + this.put(12, "L Л"); + this.put(13, "M М"); + this.put(14, "N Н"); + this.put(15, "O О"); + this.put(16, "P П"); + this.put(17, "Q Я"); + this.put(18, "R Р"); + this.put(19, "S С"); + this.put(20, "T Т"); + this.put(21, "U У"); + this.put(22, "V В"); + this.put(23, "W Ш"); + this.put(24, "X Х"); + this.put(25, "Y Ч"); + this.put(26, "Z Ж"); + this.put(27, "0 0"); + this.put(28, "1 1"); + this.put(29, "2 2"); + this.put(30, "3 3"); + this.put(31, "4 4"); + this.put(32, "5 5"); + this.put(33, "6 6"); + this.put(34, "7 7"); + this.put(35, "8 8"); + this.put(36, "9 9"); + }} + ); + + /** + * Table for decoding bytes from decoded Internet Code, english and russian letters + * Ok, this is bigger + */ + public static final Map CODE_INDEX_TABLE = Collections.unmodifiableMap( + new HashMap() {{ + this.put("A", (byte) 0); this.put("А", (byte) 0); + this.put("B", (byte) 1); this.put("Б", (byte) 1); + this.put("C", (byte) 2); this.put("Ц", (byte) 2); + this.put("D", (byte) 3); this.put("Д", (byte) 3); + this.put("E", (byte) 4); this.put("Е", (byte) 4); + this.put("F", (byte) 5); this.put("Ф", (byte) 5); + this.put("G", (byte) 6); this.put("Г", (byte) 6); + this.put("H", (byte) 7); this.put("Ю", (byte) 7); + this.put("+", (byte) 8); // this.put("+", (byte) 8); + this.put("J", (byte) 9); this.put("Й", (byte) 9); + this.put("K", (byte) 10); this.put("К", (byte) 10); + this.put("L", (byte) 11); this.put("Л", (byte) 10); + this.put("M", (byte) 12); this.put("М", (byte) 10); + this.put("N", (byte) 13); this.put("Н", (byte) 10); + this.put("\\", (byte) 14); // this.put("\\", (byte) 10); + this.put("P", (byte) 15); this.put("П", (byte) 10); + this.put("Q", (byte) 16); this.put("Я", (byte) 10); + this.put("R", (byte) 17); this.put("Р", (byte) 10); + this.put("S", (byte) 18); this.put("С", (byte) 10); + this.put("T", (byte) 19); this.put("Т", (byte) 10); + this.put("U", (byte) 20); this.put("У", (byte) 10); + this.put("V", (byte) 21); this.put("В", (byte) 10); + this.put("W", (byte) 22); this.put("Ш", (byte) 10); + this.put("X", (byte) 23); this.put("Х", (byte) 10); + this.put("Y", (byte) 24); this.put("Ч", (byte) 10); + this.put("Z", (byte) 25); this.put("Ж", (byte) 10); + this.put("a", (byte) 26); this.put("а", (byte) 10); + this.put("b", (byte) 27); this.put("б", (byte) 10); + this.put("c", (byte) 28); this.put("ц", (byte) 10); + this.put("d", (byte) 29); this.put("д", (byte) 10); + this.put("e", (byte) 30); this.put("е", (byte) 10); + this.put("f", (byte) 31); this.put("ф", (byte) 10); + this.put("g", (byte) 32); this.put("г", (byte) 10); + this.put("h", (byte) 33); this.put("ю", (byte) 10); + this.put("i", (byte) 34); this.put("и", (byte) 10); + this.put("j", (byte) 35); this.put("й", (byte) 10); + this.put("k", (byte) 36); this.put("к", (byte) 10); + this.put("&", (byte) 37); // this.put("&", (byte) 10); + this.put("m", (byte) 38); this.put("м", (byte) 10); + this.put("n", (byte) 39); this.put("н", (byte) 10); + this.put("o", (byte) 40); this.put("о", (byte) 10); + this.put("p", (byte) 41); this.put("п", (byte) 10); + this.put("q", (byte) 42); this.put("я", (byte) 10); + this.put("r", (byte) 43); this.put("р", (byte) 10); + this.put("s", (byte) 44); this.put("с", (byte) 10); + this.put("t", (byte) 45); this.put("т", (byte) 10); + this.put("u", (byte) 46); this.put("у", (byte) 10); + this.put("v", (byte) 47); this.put("в", (byte) 10); + this.put("w", (byte) 48); this.put("ш", (byte) 10); + this.put("x", (byte) 49); this.put("х", (byte) 10); + this.put("y", (byte) 50); this.put("ч", (byte) 10); + this.put("z", (byte) 51); this.put("ж", (byte) 10); + this.put("/", (byte) 52); // this.put("/", (byte) 10); + this.put("1", (byte) 53); // this.put("K", (byte) 10); + this.put("2", (byte) 54); // this.put("K", (byte) 10); + this.put("3", (byte) 55); // this.put("K", (byte) 10); + this.put("4", (byte) 56); // this.put("K", (byte) 10); + this.put("5", (byte) 57); // this.put("K", (byte) 10); + this.put("6", (byte) 58); // this.put("K", (byte) 10); + this.put("7", (byte) 59); // this.put("K", (byte) 10); + this.put("8", (byte) 60); // this.put("K", (byte) 10); + this.put("9", (byte) 61); // this.put("K", (byte) 10); + this.put("?", (byte) 62); // this.put("K", (byte) 10); + this.put("!", (byte) 63); // this.put("K", (byte) 10); + }} + ); +} diff --git a/src/me/theentropyshard/jdarkroom/JDarkroom.java b/src/me/theentropyshard/jdarkroom/JDarkroom.java new file mode 100644 index 0000000..5327cbf --- /dev/null +++ b/src/me/theentropyshard/jdarkroom/JDarkroom.java @@ -0,0 +1,150 @@ +package me.theentropyshard.jdarkroom; + +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; + +public class JDarkroom { + public JDarkroom() { + if(instance != null) { + throw new IllegalStateException("JDarkroom already running!"); + } + instance = this; + + new View(); + } + + public String findInSave(File file) { + if(file == null || file.isDirectory()) { + return null; + } + + StringBuilder russianCode = new StringBuilder(); + StringBuilder englishCode = new StringBuilder(); + try(RandomAccessFile raf = new RandomAccessFile(file, "r")) { + if(raf.length() <= 0) { + return null; + } + + raf.seek(DecodingData.CODE_OFFSET); + + for(int i = 0; i < 16; i++) { + byte b = raf.readByte(); + if(i % 4 == 0) { + String[] letters = DecodingData.SAVE_INDEX_TABLE.get((int) b).split("\\s"); + russianCode.append(letters[1]); + englishCode.append(letters[0]); + } + } + } catch (IOException e) { + e.printStackTrace(); + return null; + } + + return russianCode + " or " + englishCode; + } + + public String decodeInternetCode(String code) { + if(code == null || code.length() != 16) { + return null; + } + + byte[] bytes = new byte[16]; + for(int i = 0; i < 16; i++) { + bytes[i] = DecodingData.CODE_INDEX_TABLE.get(Character.toString(code.charAt(i))); + } + + for(int i = 6; i > 0; i--) { + int byte1 = 2 * i + i / 6; + int bi1 = i % 6; + int byte2 = 15; + int bi2 = i - 1; + + JDarkroom.swapBits(byte1, byte2, bi1, bi2, bytes); + } + + String bin = Integer.toBinaryString(bytes[bytes.length - 1]); + int index = Integer.parseInt(bin.substring(0, 3), 2); + + byte firstRoundKey = DecodingData.KEY[index]; + byte secondRoundKey = DecodingData.KEY[DecodingData.KEY.length - 1 - index]; + + for(int i = 30; i > 0; i--) { + int m = (i * firstRoundKey + 45) % 90; + int n = (i * secondRoundKey + 45) % 90; + int p = m % 6; + int q = n % 6; + + int byte1 = (m - p) / 6; + int bi1 = p; + int byte2 = (n - q) / 6; + int bi2 = q; + + JDarkroom.swapBits(byte1, byte2, bi1, bi2, bytes); + } + + byte thirdRoundKey = DecodingData.KEY[bytes[bytes.length - 1] & 0b111]; + + for(int i = 40; i > 0; i--) { + int m = i * thirdRoundKey % 90; + int n = m % 6; + int byteInd = (m - n) / 6; + int bitInd = n; + + bytes[byteInd] ^= (1 << bitInd); + } + + int intCode = 0; + intCode |= (bytes[8] & (0x1E000000 >> 25)) << 25; + intCode |= (bytes[9] & (0x01000000 >> 19)) << 19; + intCode |= (bytes[9] & (0x00001F00 >> 8)) << 8; + intCode |= (bytes[10] & (0x001F0000 >> 14)) << 14; + intCode |= (bytes[10] & (0x0000000C >> 2)) << 2; + intCode |= (bytes[11] & (0x00000003 << 4)) >> 4; + + int l1 = Integer.parseInt(Integer.toHexString((intCode >> 24) & 0xFF), 10); + int d1 = Integer.parseInt(Integer.toHexString((intCode >> 16) & 0xFF), 16); + int l2 = Integer.parseInt(Integer.toHexString((intCode >> 8) & 0xFF), 16); + int d2 = Integer.parseInt(Integer.toHexString((intCode >> 0) & 0xFF), 16); + + String[] letters1 = DecodingData.SAVE_INDEX_TABLE.get(l1 + 1).split("\\s"); + String[] letters2 = DecodingData.SAVE_INDEX_TABLE.get(l2 + 1).split("\\s"); + + String russianCode = letters1[1] + d1 + letters2[1] + d2; + String englishCode = letters1[0] + d1 + letters2[0] + d2; + + return russianCode + " or " + englishCode; + } + + /** + * Swaps two different bits in two numbers + * + * @param byteInd1 Index of first byte + * @param byteInd2 Index of second byte + * @param bi1 0-based bit from first number, indexed from right + * @param bi2 0-based bit from second number, indexed from right + * @param bytes Byte array + */ + public static void swapBits(int byteInd1, int byteInd2, int bi1, int bi2, byte... bytes) { + int bit1 = (bytes[byteInd1] >> bi1) & 1; + int bit2 = (bytes[byteInd2] >> bi2) & 1; + + if(bit1 == 0) { + bytes[byteInd2] &= ~(1 << bi2); + } else { + bytes[byteInd2] |= 1 << bi2; + } + + if(bit2 == 0) { + bytes[byteInd1] &= ~(1 << bi1); + } else { + bytes[byteInd1] |= 1 << bi1; + } + } + + private static JDarkroom instance; + + public static JDarkroom getInstance() { + return instance; + } +} diff --git a/src/me/theentropyshard/jdarkroom/Main.java b/src/me/theentropyshard/jdarkroom/Main.java new file mode 100644 index 0000000..2026e2f --- /dev/null +++ b/src/me/theentropyshard/jdarkroom/Main.java @@ -0,0 +1,12 @@ +package me.theentropyshard.jdarkroom; + +import javax.swing.*; + +public class Main { + public static void main(String[] args) { + JDialog.setDefaultLookAndFeelDecorated(true); + JFrame.setDefaultLookAndFeelDecorated(true); + + new JDarkroom(); + } +} diff --git a/src/me/theentropyshard/jdarkroom/View.java b/src/me/theentropyshard/jdarkroom/View.java new file mode 100644 index 0000000..f232178 --- /dev/null +++ b/src/me/theentropyshard/jdarkroom/View.java @@ -0,0 +1,114 @@ +package me.theentropyshard.jdarkroom; + +import javax.swing.*; +import java.awt.*; +import java.awt.datatransfer.DataFlavor; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DropTarget; +import java.awt.dnd.DropTargetDropEvent; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import java.io.File; +import java.util.List; + +public final class View extends JPanel { + private static final String YOUR_CODE_IS = "Your code is: "; + private static final float FONT_SIZE = 20.0F; + private final JTextField codeField; + + public View() { + this.setPreferredSize(new Dimension(800, 600)); + + CardLayout cardLayout = new CardLayout(); + this.setLayout(cardLayout); + + JLabel codeLabel = new JLabel(View.YOUR_CODE_IS) {{ + this.setHorizontalAlignment(JLabel.CENTER); + this.setFont(this.getFont().deriveFont(View.FONT_SIZE)); + this.setFocusable(true); + this.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + super.mouseClicked(e); + cardLayout.show(View.this, "DropLabel"); + } + }); + }}; + this.add(codeLabel, "CodeLabel"); + + JLabel dropLabel = new JLabel("Drop save file here, or click to enter Internet Code!", JLabel.CENTER) {{ + this.setDropTarget(new DropTarget() { + @Override + public synchronized void drop(DropTargetDropEvent e) { + try { + e.acceptDrop(DnDConstants.ACTION_COPY); + List droppedFiles = (List) e.getTransferable().getTransferData(DataFlavor.javaFileListFlavor); + String code = JDarkroom.getInstance().findInSave(droppedFiles.get(0)); + if(code == null) { + codeLabel.setText("Incorrect Internet Code entered!"); + codeLabel.setForeground(Color.RED); + codeField.setText(""); + } else { + codeLabel.setForeground(Color.DARK_GRAY); + codeLabel.setText(View.YOUR_CODE_IS + code); + } + cardLayout.show(View.this, "CodeLabel"); + e.dropComplete(true); + } catch (Exception ex) { + ex.printStackTrace(); + } + } + }); + this.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + super.mouseClicked(e); + cardLayout.show(View.this, "InputPanel"); + } + }); + this.setFocusable(true); + this.setFont(this.getFont().deriveFont(View.FONT_SIZE)); + }}; + this.add(dropLabel, "DropLabel"); + + JPanel panel = new JPanel(new GridBagLayout()); + GridBagConstraints c = new GridBagConstraints(); + c.fill = GridBagConstraints.BOTH; + c.anchor = GridBagConstraints.CENTER; + + this.codeField = new JTextField() {{ + this.setPreferredSize(new Dimension(250, 50)); + this.setFont(this.getFont().deriveFont(View.FONT_SIZE)); + }}; + panel.add(this.codeField, c); + + JButton button = new JButton("Enter") {{ + this.setPreferredSize(new Dimension(100, 50)); + this.setFont(this.getFont().deriveFont(View.FONT_SIZE)); + this.addActionListener(e -> { + String code = JDarkroom.getInstance().decodeInternetCode(codeField.getText()); + if(code == null) { + codeLabel.setText("Incorrect Internet Code entered!"); + codeLabel.setForeground(Color.RED); + codeField.setText(""); + } else { + codeLabel.setForeground(Color.DARK_GRAY); + codeLabel.setText(View.YOUR_CODE_IS + code); + } + cardLayout.show(View.this, "CodeLabel"); + }); + }}; + + panel.add(button, c); + this.add(panel, "InputPanel"); + + cardLayout.show(this, "DropLabel"); + + JFrame frame = new JFrame("JDarkroom"); + frame.add(this); + frame.pack(); + frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } +}