mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-07-17 21:38:10 +00:00
Added: Harman AIR 51 unpacker for binarydata with custom key
This commit is contained in:
@@ -47,9 +47,22 @@ public class HarmanBinaryDataEncrypt {
|
||||
/**
|
||||
* Encrypts data.
|
||||
* @param data Data to encrypt
|
||||
* @param key Key
|
||||
* @return Encrypted data
|
||||
*/
|
||||
public static byte[] encrypt(byte[] data) {
|
||||
public static byte[] encrypt(byte[] data, String key) {
|
||||
|
||||
byte[] customKey = null;
|
||||
|
||||
if (key != null) {
|
||||
customKey = new byte[16];
|
||||
int keyLen = key.length();
|
||||
|
||||
for(int i = 0; i < 16; ++i) {
|
||||
customKey[i] = (byte)key.charAt(i % keyLen);
|
||||
}
|
||||
}
|
||||
|
||||
byte[] result;
|
||||
try {
|
||||
SecureRandom random = new SecureRandom();
|
||||
@@ -69,7 +82,7 @@ public class HarmanBinaryDataEncrypt {
|
||||
|
||||
byte[] ivBytes = getIv(hashBytes, random1, random2);
|
||||
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
|
||||
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
|
||||
SecretKeySpec keySpec = new SecretKeySpec(customKey != null ? customKey : keyBytes, "AES");
|
||||
byte[] dataPadded = new byte[(int) encryptedDataLen];
|
||||
random.nextBytes(dataPadded);
|
||||
System.arraycopy(data, 0, dataPadded, 0, data.length);
|
||||
@@ -153,12 +166,25 @@ public class HarmanBinaryDataEncrypt {
|
||||
/**
|
||||
* Decrypts data.
|
||||
* @param data Encrypted data
|
||||
* @param key
|
||||
* @return Decrypted data
|
||||
*/
|
||||
public static byte[] decrypt(byte[] data) {
|
||||
public static byte[] decrypt(byte[] data, String key) {
|
||||
if (data.length < 32) {
|
||||
return null;
|
||||
}
|
||||
|
||||
byte[] customKey = null;
|
||||
|
||||
if (key != null) {
|
||||
customKey = new byte[16];
|
||||
int keyLen = key.length();
|
||||
|
||||
for(int i = 0; i < 16; ++i) {
|
||||
customKey[i] = (byte)key.charAt(i % keyLen);
|
||||
}
|
||||
}
|
||||
|
||||
long encryptedLen = data.length;
|
||||
long encryptedLenXorHash = unpack(data, 0);
|
||||
long decryptedLenXorRandom1 = unpack(data, 4);
|
||||
@@ -181,7 +207,7 @@ public class HarmanBinaryDataEncrypt {
|
||||
byte[] ivBytes = getIv(hashBytes, random1, random2);
|
||||
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
|
||||
|
||||
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
|
||||
SecretKeySpec keySpec = new SecretKeySpec(customKey != null ? customKey : keyBytes, "AES");
|
||||
|
||||
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
|
||||
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
|
||||
@@ -203,8 +229,8 @@ public class HarmanBinaryDataEncrypt {
|
||||
*/
|
||||
public static void main(String[] args) throws IOException {
|
||||
byte[] data = new byte[]{'A', 'B', 'C'};
|
||||
byte[] encrypted = encrypt(data);
|
||||
byte[] decrypted = decrypt(encrypted);
|
||||
byte[] encrypted = encrypt(data, null);
|
||||
byte[] decrypted = decrypt(encrypted, null);
|
||||
if (!Arrays.equals(data, decrypted)) {
|
||||
throw new RuntimeException("Cannot encrypt/decrypt");
|
||||
}
|
||||
|
||||
@@ -47,9 +47,9 @@ public class HarmanAirPacker implements Packer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean decrypt(InputStream is, OutputStream os) throws IOException {
|
||||
public boolean decrypt(InputStream is, OutputStream os, String key) throws IOException {
|
||||
byte[] encryptedData = Helper.readStream(is);
|
||||
byte[] decryptedData = HarmanBinaryDataEncrypt.decrypt(encryptedData);
|
||||
byte[] decryptedData = HarmanBinaryDataEncrypt.decrypt(encryptedData, null);
|
||||
if (decryptedData == null) {
|
||||
return false;
|
||||
}
|
||||
@@ -58,9 +58,9 @@ public class HarmanAirPacker implements Packer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean encrypt(InputStream is, OutputStream os) throws IOException {
|
||||
public boolean encrypt(InputStream is, OutputStream os, String key) throws IOException {
|
||||
byte[] data = Helper.readStream(is);
|
||||
byte[] encryptedData = HarmanBinaryDataEncrypt.encrypt(data);
|
||||
byte[] encryptedData = HarmanBinaryDataEncrypt.encrypt(data, null);
|
||||
if (encryptedData == null) {
|
||||
return false;
|
||||
}
|
||||
@@ -77,4 +77,9 @@ public class HarmanAirPacker implements Packer {
|
||||
public String getIdentifier() {
|
||||
return "harmanair";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean usesKey() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2024 JPEXS, All rights reserved.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 3.0 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library.
|
||||
*/
|
||||
package com.jpexs.decompiler.flash.packers;
|
||||
|
||||
import com.jpexs.decompiler.flash.harman.HarmanBinaryDataEncrypt;
|
||||
import com.jpexs.decompiler.flash.tags.DefineBinaryDataTag;
|
||||
import com.jpexs.helpers.Helper;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* Harman AIR SDK packer.
|
||||
*
|
||||
* @author JPEXS
|
||||
*/
|
||||
public class HarmanAirPackerWithKey implements Packer {
|
||||
|
||||
@Override
|
||||
public Boolean suitableForBinaryData(DefineBinaryDataTag dataTag) {
|
||||
if (dataTag.binaryData.getLength() < 32) {
|
||||
return false;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean suitableForData(byte[] data) {
|
||||
if (data.length < 32) {
|
||||
return false;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean decrypt(InputStream is, OutputStream os, String key) throws IOException {
|
||||
byte[] encryptedData = Helper.readStream(is);
|
||||
byte[] decryptedData = HarmanBinaryDataEncrypt.decrypt(encryptedData, key);
|
||||
if (decryptedData == null) {
|
||||
return false;
|
||||
}
|
||||
os.write(decryptedData);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean encrypt(InputStream is, OutputStream os, String key) throws IOException {
|
||||
byte[] data = Helper.readStream(is);
|
||||
byte[] encryptedData = HarmanBinaryDataEncrypt.encrypt(data, key);
|
||||
if (encryptedData == null) {
|
||||
return false;
|
||||
}
|
||||
os.write(encryptedData);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Harman AIR SDK with custom key";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIdentifier() {
|
||||
return "harmanair_key";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean usesKey() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,7 @@ public class MochiCryptPacker16Bit implements Packer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean decrypt(InputStream is, OutputStream os) throws IOException {
|
||||
public boolean decrypt(InputStream is, OutputStream os, String key) throws IOException {
|
||||
byte[] payload = Helper.readStream(is);
|
||||
if (!handleXor(payload)) {
|
||||
return false;
|
||||
@@ -103,7 +103,7 @@ public class MochiCryptPacker16Bit implements Packer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean encrypt(InputStream is, OutputStream os) throws IOException {
|
||||
public boolean encrypt(InputStream is, OutputStream os, String key) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
DeflaterOutputStream def = new DeflaterOutputStream(baos);
|
||||
Helper.copyStreamEx(is, def);
|
||||
@@ -133,4 +133,10 @@ public class MochiCryptPacker16Bit implements Packer {
|
||||
public String getIdentifier() {
|
||||
return "mochicrypt16";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean usesKey() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ public class MochiCryptPacker32Bit implements Packer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean decrypt(InputStream is, OutputStream os) throws IOException {
|
||||
public boolean decrypt(InputStream is, OutputStream os, String key) throws IOException {
|
||||
byte[] payload = Helper.readStream(is);
|
||||
if (!handleXor(payload)) {
|
||||
return false;
|
||||
@@ -103,7 +103,7 @@ public class MochiCryptPacker32Bit implements Packer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean encrypt(InputStream is, OutputStream os) throws IOException {
|
||||
public boolean encrypt(InputStream is, OutputStream os, String key) throws IOException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
DeflaterOutputStream def = new DeflaterOutputStream(baos);
|
||||
Helper.copyStreamEx(is, def);
|
||||
@@ -133,4 +133,9 @@ public class MochiCryptPacker32Bit implements Packer {
|
||||
public String getIdentifier() {
|
||||
return "mochicrypt32";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean usesKey() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,21 +53,23 @@ public interface Packer {
|
||||
*
|
||||
* @param is Data to unpack
|
||||
* @param os Stream to write unpacked data to
|
||||
* @param key Key
|
||||
* @return True if it was unpacked correctly, False if it is not suitable
|
||||
* for unpacking or an error happened.
|
||||
* @throws IOException On I/O error
|
||||
*/
|
||||
public boolean decrypt(InputStream is, OutputStream os) throws IOException;
|
||||
public boolean decrypt(InputStream is, OutputStream os, String key) throws IOException;
|
||||
|
||||
/**
|
||||
* Pack the data
|
||||
*
|
||||
* @param is Data to pack
|
||||
* @param os Stream to write packed data to
|
||||
* @param key Key
|
||||
* @return True if packed successfully, False if error happened.
|
||||
* @throws IOException On I/O error
|
||||
*/
|
||||
public boolean encrypt(InputStream is, OutputStream os) throws IOException;
|
||||
public boolean encrypt(InputStream is, OutputStream os, String key) throws IOException;
|
||||
|
||||
/**
|
||||
* Human readable name of this packer
|
||||
@@ -82,4 +84,10 @@ public interface Packer {
|
||||
* @return Identifier of this packer
|
||||
*/
|
||||
public String getIdentifier();
|
||||
|
||||
/**
|
||||
* Checks whether the packer uses encryption key.
|
||||
* @return True if key is used
|
||||
*/
|
||||
public boolean usesKey();
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.jpexs.decompiler.flash.configuration.Configuration;
|
||||
import com.jpexs.decompiler.flash.configuration.CustomConfigurationKeys;
|
||||
import com.jpexs.decompiler.flash.configuration.SwfSpecificCustomConfiguration;
|
||||
import com.jpexs.decompiler.flash.packers.HarmanAirPacker;
|
||||
import com.jpexs.decompiler.flash.packers.HarmanAirPackerWithKey;
|
||||
import com.jpexs.decompiler.flash.packers.MochiCryptPacker16Bit;
|
||||
import com.jpexs.decompiler.flash.packers.MochiCryptPacker32Bit;
|
||||
import com.jpexs.decompiler.flash.packers.Packer;
|
||||
@@ -68,6 +69,9 @@ public class DefineBinaryDataTag extends CharacterTag implements BinaryDataInter
|
||||
|
||||
@Internal
|
||||
public Packer usedPacker;
|
||||
|
||||
@Internal
|
||||
public String packerKey;
|
||||
|
||||
@Internal
|
||||
private PackedBinaryData sub;
|
||||
@@ -75,7 +79,8 @@ public class DefineBinaryDataTag extends CharacterTag implements BinaryDataInter
|
||||
private static final Packer[] PACKERS = {
|
||||
new MochiCryptPacker16Bit(),
|
||||
new MochiCryptPacker32Bit(),
|
||||
new HarmanAirPacker()
|
||||
new HarmanAirPacker(),
|
||||
new HarmanAirPackerWithKey()
|
||||
};
|
||||
|
||||
public static Packer[] getAvailablePackers() {
|
||||
@@ -103,10 +108,10 @@ public class DefineBinaryDataTag extends CharacterTag implements BinaryDataInter
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean unpack(Packer packer) {
|
||||
public boolean unpack(Packer packer, String key) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try {
|
||||
if (!packer.decrypt(new ByteArrayInputStream(binaryData.getRangeData()), baos)) {
|
||||
if (!packer.decrypt(new ByteArrayInputStream(binaryData.getRangeData()), baos, key)) {
|
||||
return false;
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
@@ -114,6 +119,7 @@ public class DefineBinaryDataTag extends CharacterTag implements BinaryDataInter
|
||||
}
|
||||
sub = new PackedBinaryData(swf, this, new ByteArrayRange(baos.toByteArray()));
|
||||
usedPacker = packer;
|
||||
packerKey = key;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -135,7 +141,7 @@ public class DefineBinaryDataTag extends CharacterTag implements BinaryDataInter
|
||||
String packerAdd = "";
|
||||
BinaryDataInterface binaryData = this;
|
||||
if (usedPacker != null) {
|
||||
unpack(usedPacker);
|
||||
unpack(usedPacker, packerKey);
|
||||
if (sub != null) {
|
||||
is = new ByteArrayInputStream(sub.getDataBytes().getRangeData());
|
||||
binaryData = sub;
|
||||
@@ -233,7 +239,7 @@ public class DefineBinaryDataTag extends CharacterTag implements BinaryDataInter
|
||||
sub.pack();
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try {
|
||||
if (!usedPacker.encrypt(new ByteArrayInputStream(sub.getDataBytes().getRangeData()), baos)) {
|
||||
if (!usedPacker.encrypt(new ByteArrayInputStream(sub.getDataBytes().getRangeData()), baos, packerKey)) {
|
||||
return false;
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
@@ -282,4 +288,9 @@ public class DefineBinaryDataTag extends CharacterTag implements BinaryDataInter
|
||||
public String getClassExportFileName(String className) {
|
||||
return className;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPackerKey() {
|
||||
return packerKey;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,9 +43,10 @@ public interface BinaryDataInterface extends Exportable {
|
||||
/**
|
||||
* Unpacks the data.
|
||||
* @param packer Packer
|
||||
* @param key Key
|
||||
* @return True if the data was unpacked
|
||||
*/
|
||||
public boolean unpack(Packer packer);
|
||||
public boolean unpack(Packer packer, String key);
|
||||
|
||||
/**
|
||||
* Detects the packer.
|
||||
@@ -57,6 +58,12 @@ public interface BinaryDataInterface extends Exportable {
|
||||
* @return Used packer
|
||||
*/
|
||||
public Packer getUsedPacker();
|
||||
|
||||
/**
|
||||
* Gets the used packer key.
|
||||
* @return Packer key
|
||||
*/
|
||||
public String getPackerKey();
|
||||
|
||||
/**
|
||||
* Sets the data bytes.
|
||||
|
||||
@@ -43,6 +43,7 @@ public class PackedBinaryData implements TreeItem, BinaryDataInterface {
|
||||
private PackedBinaryData sub;
|
||||
private Packer usedPacker;
|
||||
private SWF innerSwf;
|
||||
private String packerKey;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@@ -57,10 +58,10 @@ public class PackedBinaryData implements TreeItem, BinaryDataInterface {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean unpack(Packer packer) {
|
||||
public boolean unpack(Packer packer, String key) {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try {
|
||||
if (!packer.decrypt(new ByteArrayInputStream(data.getRangeData()), baos)) {
|
||||
if (!packer.decrypt(new ByteArrayInputStream(data.getRangeData()), baos, key)) {
|
||||
return false;
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
@@ -68,6 +69,7 @@ public class PackedBinaryData implements TreeItem, BinaryDataInterface {
|
||||
}
|
||||
sub = new PackedBinaryData(swf, this, new ByteArrayRange(baos.toByteArray()));
|
||||
usedPacker = packer;
|
||||
packerKey = key;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -159,7 +161,7 @@ public class PackedBinaryData implements TreeItem, BinaryDataInterface {
|
||||
}
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
try {
|
||||
if (!usedPacker.encrypt(new ByteArrayInputStream(sub.getDataBytes().getRangeData()), baos)) {
|
||||
if (!usedPacker.encrypt(new ByteArrayInputStream(sub.getDataBytes().getRangeData()), baos, packerKey)) {
|
||||
return false;
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
@@ -254,4 +256,9 @@ public class PackedBinaryData implements TreeItem, BinaryDataInterface {
|
||||
parts.add(0, binaryData.getClassExportFileName(className));
|
||||
return String.join("_", parts);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPackerKey() {
|
||||
return packerKey;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user