diff --git a/src/main/java/konogonka/AppPreferences.java b/src/main/java/konogonka/AppPreferences.java index 9f467e9..fade087 100644 --- a/src/main/java/konogonka/AppPreferences.java +++ b/src/main/java/konogonka/AppPreferences.java @@ -50,6 +50,9 @@ public class AppPreferences { public String getSystemKey(int number){ return preferences.get("key_area_key_system_0"+number, "");} public void setSystemKey(int number, String key){ preferences.put("key_area_key_system_0"+number, key); } + public String getTitleKek(int number){ return preferences.get("titlekek_"+number, "");} + public void setTitleKek(int number, String key){ preferences.put("titlekek_"+number, key); } + public int getTitleKeysCount(){ // TODO: do the same for other multi-keys and single diff --git a/src/main/java/konogonka/Controllers/NCA/NCAController.java b/src/main/java/konogonka/Controllers/NCA/NCAController.java index b32d981..488edd3 100644 --- a/src/main/java/konogonka/Controllers/NCA/NCAController.java +++ b/src/main/java/konogonka/Controllers/NCA/NCAController.java @@ -76,11 +76,11 @@ public class NCAController implements TabController { this.selectedFile = file; HashMap keysMap = new HashMap<>(); keysMap.put("header_key", AppPreferences.getInstance().getHeaderKey()); - for (int i = 0; i < 8; i++){ + for (int i = 0; i < 8; i++){ // TODO: FIX!!!!!!!!! URGENT! keysMap.put("key_area_key_application_0"+i, AppPreferences.getInstance().getApplicationKey(i)); keysMap.put("key_area_key_ocean_0"+i, AppPreferences.getInstance().getOceanKey(i)); keysMap.put("key_area_key_system_0"+i, AppPreferences.getInstance().getSystemKey(i)); - // TODO: Add titlekeys + keysMap.put("titlekek_0"+i, AppPreferences.getInstance().getTitleKek(i)); } for (int i = 0; i < AppPreferences.getInstance().getTitleKeysCount(); i++){ String[] pair = AppPreferences.getInstance().getTitleKeyPair(i); diff --git a/src/main/java/konogonka/Settings/SettingsController.java b/src/main/java/konogonka/Settings/SettingsController.java index 044aa46..baf05b1 100644 --- a/src/main/java/konogonka/Settings/SettingsController.java +++ b/src/main/java/konogonka/Settings/SettingsController.java @@ -25,6 +25,7 @@ public class SettingsController implements Initializable { ListSelectorKAEKAppController, ListSelectorKAEKOceanController, ListSelectorKAEKSysController, + ListSelectorTitleKeksController, ListSelectorTitleKeysController; @FXML @@ -37,6 +38,7 @@ public class SettingsController implements Initializable { ListSelectorKAEKAppController.initSelector(32, "key_area_key_application_"); ListSelectorKAEKOceanController.initSelector(32, "key_area_key_ocean_"); ListSelectorKAEKSysController.initSelector(32, "key_area_key_system_"); + ListSelectorTitleKeksController.initSelector(32, "titlekek_"); ListSelectorTitleKeysController.initSelector(32, null); // 32 required LinkedHashMap preparedPairsMapInit = new LinkedHashMap<>(); @@ -57,6 +59,14 @@ public class SettingsController implements Initializable { } ListSelectorKAEKOceanController.setList(preparedPairsMapInit); + preparedPairsMapInit.clear(); + cnt = 0; + while (!(kaekApp = AppPreferences.getInstance().getTitleKek(cnt)).isEmpty()){ + preparedPairsMapInit.put("titlekek_"+String.format("%02d", cnt), kaekApp); + cnt++; + } + ListSelectorTitleKeksController.setList(preparedPairsMapInit); + preparedPairsMapInit.clear(); cnt = 0; while (!(kaekApp = AppPreferences.getInstance().getSystemKey(cnt)).isEmpty()){ @@ -129,6 +139,14 @@ public class SettingsController implements Initializable { counter++; } ListSelectorKAEKSysController.setList(kaekSingle); + + kaekSingle.clear(); + counter = 0; + while ((keyParsed = fileMap.get("titlekek_"+String.format("%02d", counter))) != null){ + kaekSingle.put("titlekek_"+String.format("%02d", counter), keyParsed); + counter++; + } + ListSelectorTitleKeksController.setList(kaekSingle); } catch (IOException ioe){ ioe.printStackTrace(); @@ -198,6 +216,12 @@ public class SettingsController implements Initializable { AppPreferences.getInstance().setSystemKey(i, kaekSysKeySet[i].split("\\s=\\s", 2)[1]); } + String[] titleKekSet = ListSelectorTitleKeksController.getList(); + if (titleKekSet != null){ + for (int i = 0; i < titleKekSet.length; i++) + AppPreferences.getInstance().setTitleKek(i, titleKekSet[i].split("\\s=\\s", 2)[1]); + } + String[] titleKeysSet = ListSelectorTitleKeysController.getList(); if (titleKeysSet != null){ AppPreferences.getInstance().setTitleKeysCount(titleKeysSet.length); diff --git a/src/main/java/konogonka/Tools/NCA/NCAProvider.java b/src/main/java/konogonka/Tools/NCA/NCAProvider.java index 3f3f5c9..0b546c1 100644 --- a/src/main/java/konogonka/Tools/NCA/NCAProvider.java +++ b/src/main/java/konogonka/Tools/NCA/NCAProvider.java @@ -1,5 +1,6 @@ package konogonka.Tools.NCA; +import konogonka.LoperConverter; import konogonka.Tools.NCA.NCASectionTableBlock.NCASectionBlock; import konogonka.xtsaes.XTSAESCipher; import org.bouncycastle.crypto.params.KeyParameter; @@ -11,6 +12,7 @@ import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.HashMap; +import static konogonka.LoperConverter.byteArrToHexString; import static konogonka.LoperConverter.getLElong; // TODO: check file size @@ -32,6 +34,8 @@ public class NCAProvider { private byte cryptoType2; // keyblob index. Considering as number within application/ocean/system private byte[] rightsId; + private byte cryptoTypeReal; + private byte[] sha256hash0; private byte[] sha256hash1; private byte[] sha256hash2; @@ -152,32 +156,28 @@ public class NCAProvider { encryptedKey2 = Arrays.copyOfRange(encryptedKeysArea, 0x20, 0x30); encryptedKey3 = Arrays.copyOfRange(encryptedKeysArea, 0x30, 0x40); + // Calculate real Crypto Type + if (cryptoType1 < cryptoType2) + cryptoTypeReal = cryptoType2; + else + cryptoTypeReal = cryptoType1; + + if (cryptoTypeReal > 0) // TODO: CLARIFY WHY THEH FUCK IS IT FAIR???? + cryptoTypeReal -= 1; + //todo: if nca3 proceed - // If no rights ID (ticket?) exists + // Decrypt keys if encrypted if (Arrays.equals(rightsId, new byte[0x10])) { - byte realCryptoType; - if (cryptoType1 < cryptoType2) - realCryptoType = cryptoType2; - else - realCryptoType = cryptoType1; - - if (realCryptoType > 0) // TODO: CLARIFY WHY THEH FUCK IS IT FAIR???? - realCryptoType -= 1; - - String keyAreaKey; switch (keyIndex){ case 0: - keyAreaKey = keys.get("key_area_key_application_0"+realCryptoType); - System.out.println("Using key_area_key_application_0"+realCryptoType); + keyAreaKey = keys.get("key_area_key_application_"+String.format("%02d", cryptoTypeReal)); break; case 1: - keyAreaKey = keys.get("key_area_key_ocean_0"+realCryptoType); - System.out.println("Using key_area_key_ocean_0"+realCryptoType); + keyAreaKey = keys.get("key_area_key_ocean_"+String.format("%02d", cryptoTypeReal)); break; case 2: - keyAreaKey = keys.get("key_area_key_system_0"+realCryptoType); - System.out.println("Using key_area_key_system_0"+realCryptoType); + keyAreaKey = keys.get("key_area_key_system_"+String.format("%02d", cryptoTypeReal)); break; default: keyAreaKey = null; @@ -193,11 +193,6 @@ public class NCAProvider { decryptedKey3 = cipher.doFinal(encryptedKey3); } } - else { - - // TODO - - } tableEntry0 = new NCAHeaderTableEntry(tableBytes); tableEntry1 = new NCAHeaderTableEntry(Arrays.copyOfRange(tableBytes, 0x10, 0x20)); @@ -253,33 +248,39 @@ public class NCAProvider { * @param sectionNumber should be 1-4 * */ public NCAContentPFS0 getNCAContentPFS0(int sectionNumber){ - // TODO: provide titleKey if needed + byte[] key; - switch (sectionNumber){ + // If empty Rights ID + if (Arrays.equals(rightsId, new byte[0x10])) { + key = decryptedKey2; // TODO: Just remember this dumb hach + } + else { + byte[] rightsIDkey = hexStrToByteArray(keys.get(byteArrToHexString(rightsId))); + + try { + SecretKeySpec skSpec = new SecretKeySpec( + hexStrToByteArray(keys.get("titlekek_"+String.format("%02d", cryptoTypeReal)) + ), "AES"); + Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding"); + cipher.init(Cipher.DECRYPT_MODE, skSpec); + key = cipher.doFinal(rightsIDkey); + } + catch (Exception e){ + e.printStackTrace(); + return null; + } + } + switch (sectionNumber) { case 0: - return new NCAContentPFS0(file, offset, sectionBlock0, tableEntry0, decryptedKey2); // TODO: remove decryptedKey2 + return new NCAContentPFS0(file, offset, sectionBlock0, tableEntry0, key); // TODO: remove decryptedKey2 case 1: - return new NCAContentPFS0(file, offset, sectionBlock1, tableEntry1, decryptedKey2); + return new NCAContentPFS0(file, offset, sectionBlock1, tableEntry1, key); case 2: - return new NCAContentPFS0(file, offset, sectionBlock2, tableEntry2, decryptedKey2); + return new NCAContentPFS0(file, offset, sectionBlock2, tableEntry2, key); case 3: - return new NCAContentPFS0(file, offset, sectionBlock3, tableEntry3, decryptedKey2); + return new NCAContentPFS0(file, offset, sectionBlock3, tableEntry3, key); default: return null; } } -} -// 0 OR 2 crypto type -// 0,1,2 kaek index -//settings.keyset.key_area_keys[ctx->crypto_type][ctx->header.kaek_ind] - /* - 0x207 = - 0: key_area_key_application_ 0x206 range:[0-6]; usually used 0 or 2 - 1: key_area_key_ocean [0-6] - 2: key_area_key_system [0-6] - - if(ncahdr_x206 < ncahdr_x220){ret = ncahdr_x220; } else { ret = ncahdr_x206; } return ret; - - ret > 0? ret-- - - */ \ No newline at end of file +} \ No newline at end of file diff --git a/src/main/resources/FXML/Settings/SettingsLayout.fxml b/src/main/resources/FXML/Settings/SettingsLayout.fxml index c375d13..b6826b7 100644 --- a/src/main/resources/FXML/Settings/SettingsLayout.fxml +++ b/src/main/resources/FXML/Settings/SettingsLayout.fxml @@ -48,15 +48,18 @@