mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/jpexs-decompiler.git
synced 2026-06-30 05:06:06 +00:00
135 lines
4.6 KiB
Java
135 lines
4.6 KiB
Java
/*
|
|
* Copyright (C) 2010-2023 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;
|
|
|
|
import java.io.ByteArrayInputStream;
|
|
import java.io.DataInputStream;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.security.InvalidAlgorithmParameterException;
|
|
import java.security.InvalidKeyException;
|
|
import java.security.NoSuchAlgorithmException;
|
|
import java.util.Arrays;
|
|
import javax.crypto.BadPaddingException;
|
|
import javax.crypto.Cipher;
|
|
import javax.crypto.IllegalBlockSizeException;
|
|
import javax.crypto.NoSuchPaddingException;
|
|
import javax.crypto.spec.IvParameterSpec;
|
|
import javax.crypto.spec.SecretKeySpec;
|
|
|
|
/**
|
|
*
|
|
* @author JPEXS
|
|
*
|
|
* Based on swfdecrypt.py by NathaanTFM
|
|
*/
|
|
public class HarmanDecryption {
|
|
|
|
private static final String GLOBAL_KEY = "Adobe AIR SDK (c) 2021 HARMAN Internation Industries Incorporated";
|
|
|
|
private static int sum(byte[] data) {
|
|
int s = 0;
|
|
for (int i = 0; i < data.length; i++) {
|
|
s += data[i] & 0xff;
|
|
}
|
|
return s;
|
|
}
|
|
|
|
private static long getkey(byte[] data) {
|
|
int dsum = sum(data);
|
|
int dmod = dsum % GLOBAL_KEY.length();
|
|
String s = GLOBAL_KEY.substring(dmod) + GLOBAL_KEY.substring(0, dmod);
|
|
s += " EncryptSWF ";
|
|
s += "" + dsum;
|
|
|
|
long ret = 0;
|
|
for (int i = 0; i < s.length(); i++) {
|
|
int code = s.charAt(i);
|
|
ret *= 31;
|
|
ret += code;
|
|
}
|
|
|
|
return ret & 0xffffffffL;
|
|
}
|
|
|
|
private static long unpack(byte[] data, int start) {
|
|
return (data[start] & 0xff)
|
|
+ ((long) (data[start + 1] & 0xff) << 8)
|
|
+ ((long) (data[start + 2] & 0xff) << 16)
|
|
+ ((long) (data[start + 3] & 0xff) << 24);
|
|
}
|
|
|
|
public InputStream decrypt(InputStream is, byte[] header) throws IOException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException {
|
|
header[0] -= 32; // to uppercase
|
|
|
|
long key = getkey(header);
|
|
|
|
//get the length
|
|
DataInputStream dais = new DataInputStream(is);
|
|
|
|
byte[] encryptedLengthBytes = new byte[4];
|
|
dais.readFully(encryptedLengthBytes);
|
|
long encryptedLength = unpack(encryptedLengthBytes, 0);
|
|
int decryptedLength = (int) (encryptedLength ^ key);
|
|
|
|
//padded length
|
|
int paddedLength = (int) (decryptedLength + 0x1F) & ~0x1F;
|
|
|
|
//aes iv
|
|
byte[] aesIV = new byte[16];
|
|
System.arraycopy(header, 0, aesIV, 0, header.length); //header
|
|
System.arraycopy(encryptedLengthBytes, 0, aesIV, 8, 4); //encrypted length
|
|
aesIV[12] = (byte) (key & 0xff);
|
|
aesIV[13] = (byte) ((key >> 8) & 0xff);
|
|
aesIV[14] = (byte) ((key >> 16) & 0xff);
|
|
aesIV[15] = (byte) ((key >> 24) & 0xff);
|
|
|
|
for (int i = 0; i < 16; i++) {
|
|
aesIV[i] ^= GLOBAL_KEY.charAt(i);
|
|
}
|
|
|
|
// aes key
|
|
// this one is stored at the end of the file
|
|
byte[] aesKey = new byte[32];
|
|
byte[] data = new byte[paddedLength];
|
|
dais.readFully(data);
|
|
|
|
byte[] aesKeyData = new byte[32];
|
|
dais.readFully(aesKeyData);
|
|
|
|
for (int i = 0; i < 32; i += 4) {
|
|
long value = unpack(aesKeyData, i);
|
|
if ((i & 4) == 4) {
|
|
value -= key;
|
|
} else {
|
|
value += key;
|
|
}
|
|
aesKey[i] = (byte) (value & 0xff);
|
|
aesKey[i + 1] = (byte) ((value >> 8) & 0xff);
|
|
aesKey[i + 2] = (byte) ((value >> 16) & 0xff);
|
|
aesKey[i + 3] = (byte) ((value >> 24) & 0xff);
|
|
}
|
|
|
|
SecretKeySpec secretKeySpec = new SecretKeySpec(aesKey, "AES");
|
|
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
|
|
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, new IvParameterSpec(aesIV));
|
|
|
|
byte[] decryptedData = cipher.doFinal(data);
|
|
return new ByteArrayInputStream(Arrays.copyOfRange(decryptedData, 0, decryptedLength));
|
|
}
|
|
}
|