mirror of
https://github.com/TheEntropyShard/JDarkroom.git
synced 2025-02-24 05:11:24 +03:00
Initial commit
This commit is contained in:
commit
16a36b0fb7
22 changed files with 566 additions and 0 deletions
137
src/me/theentropyshard/jdarkroom/DecodingData.java
Normal file
137
src/me/theentropyshard/jdarkroom/DecodingData.java
Normal file
|
@ -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<Integer, String> SAVE_INDEX_TABLE = Collections.unmodifiableMap(
|
||||
new HashMap<Integer, String>() {{
|
||||
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<String, Byte> CODE_INDEX_TABLE = Collections.unmodifiableMap(
|
||||
new HashMap<String, Byte>() {{
|
||||
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);
|
||||
}}
|
||||
);
|
||||
}
|
150
src/me/theentropyshard/jdarkroom/JDarkroom.java
Normal file
150
src/me/theentropyshard/jdarkroom/JDarkroom.java
Normal file
|
@ -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;
|
||||
}
|
||||
}
|
12
src/me/theentropyshard/jdarkroom/Main.java
Normal file
12
src/me/theentropyshard/jdarkroom/Main.java
Normal file
|
@ -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();
|
||||
}
|
||||
}
|
114
src/me/theentropyshard/jdarkroom/View.java
Normal file
114
src/me/theentropyshard/jdarkroom/View.java
Normal file
|
@ -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<File> droppedFiles = (List<File>) 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);
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue