From 33a645266fe447a0cd560eef3c697cb7cd5d4070 Mon Sep 17 00:00:00 2001 From: Petschko Date: Sun, 14 Feb 2021 23:03:38 +0100 Subject: [PATCH 1/2] Added support for Keyless-Image restoring --- src/org/petschko/lib/File.java | 66 +++++++++++++++++ .../rpgmakermv/decrypt/Decrypter.java | 70 ++++++++++++------- .../petschko/rpgmakermv/decrypt/Finder.java | 23 ------ src/org/petschko/rpgmakermv/decrypt/GUI.java | 25 ++++++- .../petschko/rpgmakermv/decrypt/GUI_Menu.java | 8 +++ .../rpgmakermv/decrypt/RPGProject.java | 2 +- 6 files changed, 141 insertions(+), 53 deletions(-) diff --git a/src/org/petschko/lib/File.java b/src/org/petschko/lib/File.java index 724ac79..d4ecd7a 100644 --- a/src/org/petschko/lib/File.java +++ b/src/org/petschko/lib/File.java @@ -86,6 +86,8 @@ private void setExtension(@Nullable String extension) { if(extension != null) { if (extension.equals("")) extension = null; + else + extension = extension.toLowerCase(); } this.extension = extension; @@ -514,4 +516,68 @@ public static boolean createDirectory(@NotNull String directoryPath) { public static boolean clearDirectory(@NotNull String directoryPath) { return File.deleteDirectoryOperation(directoryPath, true, false); } + + /** + * Returns the real Extension of the current fake extension + * + * @return - Real File-Extension + */ + public String realExtByFakeExt() { + switch(this.extension) { + case "rpgmvp": + case "png_": + return "png"; + case "rpgmvm": + case "m4a_": + return "m4a"; + case "rpgmvo": + case "ogg_": + return "ogg"; + default: + return "unknown"; + } + } + + /** + * Shows if this file is an Image + * + * @return - true if the file is an image + */ + public boolean isImage() { + switch(this.extension) { + case "rpgmvp": + case "png_": + case "jpg": + case "jpeg": + case "png": + case "gif": + case "bmp": + case "ico": + return true; + default: + return false; + } + } + + /** + * Check if the given Extension is an Encrypted Extension + * + * @return - true if the Extension is an encrypted File-extension else false + */ + public boolean isFileEncryptedExt() { + if(this.extension == null) + return false; + + switch(this.extension) { + case "rpgmvp": + case "rpgmvm": + case "rpgmvo": + case "png_": + case "m4a_": + case "ogg_": + return true; + default: + return false; + } + } } diff --git a/src/org/petschko/rpgmakermv/decrypt/Decrypter.java b/src/org/petschko/rpgmakermv/decrypt/Decrypter.java index d5cff74..bb630b5 100644 --- a/src/org/petschko/rpgmakermv/decrypt/Decrypter.java +++ b/src/org/petschko/rpgmakermv/decrypt/Decrypter.java @@ -20,6 +20,9 @@ * Notes: Decrypter class */ class Decrypter { + static final String pngHeader = "89504E470D0A1A0A0000000D49484452"; + static byte[] pngHeaderBytes = null; + static final int defaultHeaderLen = 16; static final String defaultSignature = "5250474d56000000"; static final String defaultVersion = "000301"; @@ -205,6 +208,20 @@ private void calcRealDecryptionCode() throws NullPointerException { * @throws Exception - Various Exceptions */ void decryptFile(File file) throws Exception { + decryptFile(file, false); + } + + /** + * Decrypts the File (Header) and removes the Encryption-Header + * + * @param file - Encrypted File + * @param restorePictures - Restore Pictures without the Key + * @throws Exception - Various Exceptions + */ + void decryptFile(File file, boolean restorePictures) throws Exception { + if(restorePictures && (! file.isImage() || ! file.isFileEncryptedExt())) + return; + try { if(! file.load()) throw new FileSystemException(file.getFilePath(), "", "Can't load File-Content..."); @@ -215,7 +232,7 @@ void decryptFile(File file) throws Exception { } // Check if all required external stuff is here - if(this.getDecryptCode() == null) + if(this.getDecryptCode() == null && ! restorePictures) throw new NullPointerException("Decryption-Code is not set!"); if(file.getContent() == null) throw new NullPointerException("File-Content is not loaded!"); @@ -233,16 +250,19 @@ void decryptFile(File file) throws Exception { // Remove Fake-Header from rest content = Decrypter.getByteArray(content, this.getHeaderLen()); - // Decrypt Real-Header & First part of the Content + if(content.length > 0) { for(int i = 0; i < this.getHeaderLen(); i++) { - content[i] = (byte) (content[i] ^ (byte) Integer.parseInt(this.getRealDecryptCode()[i], 16)); + if(restorePictures) // Restore Pictures + content[i] = getPNGHeaderByteArray()[i]; + else // Decrypt Real-Header & First part of the Content + content[i] = (byte) (content[i] ^ (byte) Integer.parseInt(this.getRealDecryptCode()[i], 16)); } } // Update File-Content file.setContent(content); - file.changeExtension(Decrypter.realExtByFakeExt(file.getExtension())); + file.changeExtension(file.realExtByFakeExt()); } /** @@ -309,6 +329,26 @@ void detectEncryptionKey(File file, String keyName) throws JSONException, NullPo this.setDecryptCode(key); } + /** + * Returns the PNG-Header Byte Array + * + * @return PNG-Header Byte Array + */ + private byte[] getPNGHeaderByteArray() { + if(pngHeaderBytes != null) + return pngHeaderBytes; + + String[] pngHeaderArr = pngHeader.split("(?<=\\G.{2})"); + byte[] pngHeaderBytesArray = new byte[this.getHeaderLen()]; + + for(int i = 0; i < this.getHeaderLen(); i++) { + pngHeaderBytesArray[i] = (byte) Integer.parseInt(pngHeaderArr[i], 16); + } + pngHeaderBytes = pngHeaderBytesArray; + + return pngHeaderBytes; + } + /** * Get a new Byte-Array with given start pos and length * @@ -351,26 +391,4 @@ private static byte[] getByteArray(byte[] byteArray, int startPos, int length) { private static byte[] getByteArray(byte[] byteArray, int startPos) { return getByteArray(byteArray, startPos, -1); } - - /** - * Returns the real Extension of the current fake extension - * - * @param fakeExt - Fake Extension where you want to get the real Extension - * @return - Real File-Extension - */ - private static String realExtByFakeExt(@NotNull String fakeExt) { - switch(fakeExt.toLowerCase()) { - case "rpgmvp": - case "png_": - return "png"; - case "rpgmvm": - case "m4a_": - return "m4a"; - case "rpgmvo": - case "ogg_": - return "ogg"; - default: - return "unknown"; - } - } } diff --git a/src/org/petschko/rpgmakermv/decrypt/Finder.java b/src/org/petschko/rpgmakermv/decrypt/Finder.java index 8c52a95..b53d5e0 100644 --- a/src/org/petschko/rpgmakermv/decrypt/Finder.java +++ b/src/org/petschko/rpgmakermv/decrypt/Finder.java @@ -55,29 +55,6 @@ static File findSystemFile(@Nullable String projectDir) { return null; } - /** - * Check if the given Extension is an Encrypted Extension - * - * @param extension - File-Extension to check - * @return - true if the Extension is an encrypted File-extension else false - */ - static boolean isFileEncryptedExt(@Nullable String extension) { - if(extension == null) - extension = ""; - - switch(extension.toLowerCase()) { - case "rpgmvp": - case "rpgmvm": - case "rpgmvo": - case "png_": - case "m4a_": - case "ogg_": - return true; - default: - return false; - } - } - /** * Check if Encryption-Key name is may different from given - Tests all know Encryption-Key Names * diff --git a/src/org/petschko/rpgmakermv/decrypt/GUI.java b/src/org/petschko/rpgmakermv/decrypt/GUI.java index 5224232..7d9dbbe 100644 --- a/src/org/petschko/rpgmakermv/decrypt/GUI.java +++ b/src/org/petschko/rpgmakermv/decrypt/GUI.java @@ -214,6 +214,7 @@ private void assignRPGActionListener() { this.mainMenu.openRPGDirExplorer.addActionListener(GUI_ActionListener.openExplorer(this.rpgProject.getPath())); //this.mainMenu.allFiles.addActionListener(this.decrypt(this.rpgProject.getEncryptedFiles())); this.mainMenu.allFiles.addActionListener(new GUI_Decryption(this.rpgProject.getEncryptedFiles())); + this.mainMenu.restoreImages.addActionListener(new GUI_Decryption(this.rpgProject.getEncryptedFiles(), true)); } /** @@ -250,6 +251,7 @@ private void setNewOutputDir(String newOutputDir) { private class GUI_Decryption extends SwingWorker implements ActionListener { private ArrayList files; private ProgressMonitor progressMonitor; + private boolean restoreImages = false; /** * GUI_Decryption constructor @@ -260,6 +262,17 @@ private class GUI_Decryption extends SwingWorker implements ActionLi this.files = files; } + /** + * GUI_Decryption constructor + * + * @param files - Files to Decrypt + * @param restoreImages - Restores Images without key + */ + GUI_Decryption(ArrayList files, boolean restoreImages) { + this.files = files; + this.restoreImages = restoreImages; + } + /** * Computes a result, or throws an exception if unable to do so. * @@ -361,11 +374,12 @@ protected Void doInBackground() throws Exception { this.progressMonitor.setNote("File: " + file.getFilePath()); try { System.out.println("Decrypt: " + file.getFilePath()); - decrypter.decryptFile(file); + decrypter.decryptFile(file, this.restoreImages); } catch(Exception e1) { e1.printStackTrace(); } finally { - rpgProject.saveFile(file, Functions.strToBool(App.preferences.getConfig(Preferences.overwriteFiles, "false"))); + if(! this.restoreImages || file.isImage()) + rpgProject.saveFile(file, Functions.strToBool(App.preferences.getConfig(Preferences.overwriteFiles, "false"))); } // Add Progress to Progress-Monitor i++; @@ -402,7 +416,12 @@ protected void done() { } else { System.out.println("Done."); - InfoWindow infoWindow = new InfoWindow("Decryption complete! =)"); + InfoWindow infoWindow; + if(this.restoreImages) + infoWindow = new InfoWindow("Images are restored! ^-^"); + else + infoWindow = new InfoWindow("Decryption complete! =)"); + infoWindow.show(mainWindow); } } diff --git a/src/org/petschko/rpgmakermv/decrypt/GUI_Menu.java b/src/org/petschko/rpgmakermv/decrypt/GUI_Menu.java index 7eddb58..b4390e3 100644 --- a/src/org/petschko/rpgmakermv/decrypt/GUI_Menu.java +++ b/src/org/petschko/rpgmakermv/decrypt/GUI_Menu.java @@ -39,6 +39,7 @@ class GUI_Menu extends JMenuBar { // Decrypt-Menu-Sub JMenuItem selectedFiles; JMenuItem allFiles; + JMenuItem restoreImages; JMenuItem setEncryptionKey; JMenuItem setEncryptionFile; JMenuItem changeDecrypterSignature; @@ -49,6 +50,7 @@ class GUI_Menu extends JMenuBar { // Info-Menu-Sub JMenuItem help; + JMenuItem updateProgram; JMenuItem reportABug; JMenuItem about; @@ -102,6 +104,7 @@ private void constructDecryptMenu() { // Sub-Items this.selectedFiles = new JMenuItem("Selected Files"); this.allFiles = new JMenuItem("All Files"); + this.restoreImages = new JMenuItem("Restore Images (No Key)"); this.setEncryptionKey = new JMenuItem("Set Encryption-Key..."); this.setEncryptionFile = new JMenuItem("Select Encryption-File..."); this.changeDecrypterSignature = new JMenuItem("Change Decrypter Signature..."); @@ -124,6 +127,7 @@ private void constructInfoMenu() { this.info = new JMenu("Info"); this.help = new JMenuItem("Help"); + this.updateProgram = new JMenuItem("Check for Updates"); this.reportABug = new JMenuItem("Report a Bug..."); this.about = new JMenuItem("About"); } @@ -151,6 +155,7 @@ private void addAllMenus() { this.add(this.decrypt); this.decrypt.add(this.selectedFiles); this.decrypt.add(this.allFiles); + this.decrypt.add(this.restoreImages); this.decrypt.addSeparator(); this.decrypt.add(this.setEncryptionKey); this.decrypt.add(this.setEncryptionFile); @@ -162,6 +167,7 @@ private void addAllMenus() { this.add(this.info); this.info.add(this.help); + this.info.add(this.updateProgram); this.info.add(this.reportABug); this.info.addSeparator(); this.info.add(this.about); @@ -176,6 +182,7 @@ void enableOnRPGProject(boolean enable) { this.openRPGDirExplorer.setEnabled(enable); //this.selectedFiles.setEnabled(enable); this.allFiles.setEnabled(enable); + this.restoreImages.setEnabled(enable); //this.setEncryptionKey.setEnabled(enable); //this.setEncryptionFile.setEnabled(enable); //this.restoreProject.setEnabled(enable); @@ -191,5 +198,6 @@ private void disableUnimplemented() { this.changeDecrypterSignature.setEnabled(false); this.restoreProject.setEnabled(false); this.help.setEnabled(false); + this.updateProgram.setEnabled(false); } } diff --git a/src/org/petschko/rpgmakermv/decrypt/RPGProject.java b/src/org/petschko/rpgmakermv/decrypt/RPGProject.java index aa264d3..1246729 100644 --- a/src/org/petschko/rpgmakermv/decrypt/RPGProject.java +++ b/src/org/petschko/rpgmakermv/decrypt/RPGProject.java @@ -219,7 +219,7 @@ private void findEncryptedFiles() { return; for(File file : this.getFiles()) { - if(Finder.isFileEncryptedExt(file.getExtension())) + if(file.isFileEncryptedExt()) this.getEncryptedFiles().add(file); } } From 8f997f0136e166e219754fbadf4c3886e1f84233 Mon Sep 17 00:00:00 2001 From: Petschko Date: Mon, 15 Feb 2021 00:19:13 +0100 Subject: [PATCH 2/2] Changed version --- src/org/petschko/rpgmakermv/decrypt/Config.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/petschko/rpgmakermv/decrypt/Config.java b/src/org/petschko/rpgmakermv/decrypt/Config.java index 852873a..6e5965d 100644 --- a/src/org/petschko/rpgmakermv/decrypt/Config.java +++ b/src/org/petschko/rpgmakermv/decrypt/Config.java @@ -12,7 +12,7 @@ */ class Config { // Program Info - static final String versionNumber = "0.1.4.0"; + static final String versionNumber = "0.1.5.0"; static final String version = "v" + versionNumber + " Alpha"; static final String programName = "RPG-Maker MV Decrypter"; static final String projectPageURL = "https://github.com/Petschko/Java-RPG-Maker-MV-Decrypter";