mirror of
https://github.com/DJDoubleD/refreezer.git
synced 2026-01-15 16:32:54 -03:00
Improve decryption performance
- Generate only cypher once per file - Make Decryptor instance per thread
This commit is contained in:
@@ -9,13 +9,32 @@ import java.security.MessageDigest;
|
||||
|
||||
import javax.crypto.Cipher;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import javax.crypto.spec.IvParameterSpec;
|
||||
|
||||
public class DeezerDecryptor {
|
||||
private final Cipher cipher;
|
||||
|
||||
public static void decryptFile(String trackId, String inputFilename, String outputFilename) throws IOException {
|
||||
/**
|
||||
* Constructor initializes the key and cipher for the given track ID.
|
||||
* @param trackId Track ID used to generate decryption key
|
||||
* @throws Exception If there is an issue initializing the cipher
|
||||
*/
|
||||
public DeezerDecryptor(String trackId) throws Exception {
|
||||
this.cipher = Cipher.getInstance("Blowfish/CBC/NoPadding");
|
||||
byte[] IV = {00, 01, 02, 03, 04, 05, 06, 07};
|
||||
SecretKeySpec Skey = new SecretKeySpec(getKey(trackId), "Blowfish");
|
||||
cipher.init(Cipher.DECRYPT_MODE, Skey, new IvParameterSpec(IV));
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts a file by reading it in chunks and decrypting every 3rd chunk of exactly 2048 bytes.
|
||||
* @param inputFilename The input file to decrypt
|
||||
* @param outputFilename The output file to write the decrypted data
|
||||
* @throws IOException If an I/O error occurs
|
||||
*/
|
||||
public void decryptFile(String inputFilename, String outputFilename) throws IOException {
|
||||
try (FileInputStream fis = new FileInputStream(inputFilename);
|
||||
FileOutputStream fos = new FileOutputStream(outputFilename)) {
|
||||
byte[] key = getKey(trackId);
|
||||
byte[] buffer = new byte[2048];
|
||||
int bytesRead;
|
||||
int chunkCounter = 0;
|
||||
@@ -23,7 +42,7 @@ public class DeezerDecryptor {
|
||||
while ((bytesRead = fis.read(buffer)) != -1) {
|
||||
// Only every 3rd chunk of exactly 2048 bytes should be decrypted
|
||||
if (bytesRead == 2048 && (chunkCounter % 3) == 0) {
|
||||
buffer = decryptChunk(key, buffer);
|
||||
buffer = decryptChunk(buffer);
|
||||
}
|
||||
fos.write(buffer, 0, bytesRead);
|
||||
chunkCounter++;
|
||||
@@ -33,6 +52,11 @@ public class DeezerDecryptor {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a byte array to a hexadecimal string.
|
||||
* @param bytes Byte array to convert
|
||||
* @return Hexadecimal string representation of the byte array
|
||||
*/
|
||||
public static String bytesToHex(byte[] bytes) {
|
||||
final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
|
||||
char[] hexChars = new char[bytes.length * 2];
|
||||
@@ -47,7 +71,7 @@ public class DeezerDecryptor {
|
||||
/**
|
||||
* Generates the Track decryption key based on the provided track ID and a secret.
|
||||
* @param id Track ID used to generate decryption key
|
||||
* @return Decryption key for Track
|
||||
* @return Decryption key for Track
|
||||
*/
|
||||
static byte[] getKey(String id) {
|
||||
final String secret = "g4el58wc0zvf9na1";
|
||||
@@ -57,11 +81,11 @@ public class DeezerDecryptor {
|
||||
byte[] md5id = md5.digest();
|
||||
String idmd5 = bytesToHex(md5id).toLowerCase();
|
||||
String key = "";
|
||||
for(int i=0; i<16; i++) {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
int s0 = idmd5.charAt(i);
|
||||
int s1 = idmd5.charAt(i+16);
|
||||
int s1 = idmd5.charAt(i + 16);
|
||||
int s2 = secret.charAt(i);
|
||||
key += (char)(s0^s1^s2);
|
||||
key += (char) (s0 ^ s1 ^ s2);
|
||||
}
|
||||
return key.getBytes();
|
||||
} catch (Exception e) {
|
||||
@@ -70,25 +94,37 @@ public class DeezerDecryptor {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts a 2048-byte chunk of data using the pre-initialized Blowfish cipher.
|
||||
* @param data 2048-byte chunk of data to decrypt
|
||||
* @return Decrypted 2048-byte chunk
|
||||
*/
|
||||
private byte[] decryptChunk(byte[] data) {
|
||||
try {
|
||||
return cipher.doFinal(data);
|
||||
} catch (Exception e) {
|
||||
Log.e("D", e.toString());
|
||||
return new byte[0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decrypts a 2048-byte chunk of data using the Blowfish algorithm in CBC mode with no padding.
|
||||
* The decryption key and the initial vector (IV) are used to decrypt the data.
|
||||
* @param key Track key
|
||||
* @param data 2048-byte chunk of data to decrypt
|
||||
* @return Decrypted 2048-byte chunk
|
||||
*
|
||||
*/
|
||||
static byte[] decryptChunk(byte[] key, byte[] data) {
|
||||
public static byte[] decryptChunk(byte[] key, byte[] data) {
|
||||
try {
|
||||
byte[] IV = {00, 01, 02, 03, 04, 05, 06, 07};
|
||||
SecretKeySpec Skey = new SecretKeySpec(key, "Blowfish");
|
||||
Cipher cipher = Cipher.getInstance("Blowfish/CBC/NoPadding");
|
||||
cipher.init(Cipher.DECRYPT_MODE, Skey, new javax.crypto.spec.IvParameterSpec(IV));
|
||||
cipher.init(Cipher.DECRYPT_MODE, Skey, new IvParameterSpec(IV));
|
||||
return cipher.doFinal(data);
|
||||
}catch (Exception e) {
|
||||
} catch (Exception e) {
|
||||
Log.e("D", e.toString());
|
||||
return new byte[0];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -447,7 +447,8 @@ public class DownloadService extends Service {
|
||||
if (qualityInfo.encrypted) {
|
||||
try {
|
||||
File decFile = new File(tmpFile.getPath() + ".DEC");
|
||||
DeezerDecryptor.decryptFile(download.streamTrackId, tmpFile.getPath(), decFile.getPath());
|
||||
DeezerDecryptor decryptor = new DeezerDecryptor(download.streamTrackId);
|
||||
decryptor.decryptFile(tmpFile.getPath(), decFile.getPath());
|
||||
tmpFile.delete();
|
||||
tmpFile = decFile;
|
||||
} catch (Exception e) {
|
||||
|
||||
Reference in New Issue
Block a user