|
/** |
|
* Offline Activator [Version 1.0.0 Beta] |
|
* |
|
* @author Bipin Jitiya |
|
* @version 1.0 |
|
* @since 2024-04-24 |
|
*/ |
|
|
|
import javax.crypto.Cipher; |
|
import javax.crypto.spec.SecretKeySpec; |
|
import java.io.ByteArrayOutputStream; |
|
import java.math.BigInteger; |
|
import java.security.KeyFactory; |
|
import java.security.NoSuchAlgorithmException; |
|
import java.security.Signature; |
|
import java.security.interfaces.RSAPrivateKey; |
|
import java.security.spec.InvalidKeySpecException; |
|
import java.security.spec.PKCS8EncodedKeySpec; |
|
import java.util.ArrayList; |
|
import java.util.Base64; |
|
import java.util.List; |
|
import java.util.Random; |
|
import java.util.Scanner; |
|
|
|
public class Activator { |
|
private static final String privateKey2048 = "REPLACE_WITH_PRIVATE_KEY_2048"; |
|
private static final String privateKey1024 = "REPLACE_WITH_PRIVATE_KEY_1024"; |
|
private static final byte[] encryptionKey = "REPLACE_WITH_ENCRYPTION_KEY".getBytes(); |
|
private static final boolean VERBOSE_ENABLED = true; // Set to false to disable verbose logging |
|
|
|
public static void main(String[] args) { |
|
printBanner(); |
|
|
|
Scanner scanner = new Scanner(System.in); |
|
String licenseName; |
|
|
|
// Step 1: Ask for license name |
|
System.out.print("\033[34mEnter license name: \033[0m"); |
|
licenseName = scanner.nextLine(); |
|
|
|
// Step 2: Generate license string |
|
String license = generateLicense(licenseName); |
|
verboseLog("Printing the generated license string..."); |
|
System.out.println("\033[1;92mLICENSE KEY\033[0m"); |
|
System.out.println(license); |
|
|
|
// Step 3: Ask for activation request |
|
System.out.println("\033[34mEnter activation request:\033[0m"); |
|
String activationRequest = scanner.nextLine(); |
|
|
|
// Step 4: Print activation response |
|
String activationResponse = generateActivation(activationRequest); |
|
verboseLog("Printing the generated activation response..."); |
|
System.out.println("\033[1;92mACTIVATION RESPONSE\033[0m"); |
|
System.out.println(activationResponse); |
|
} |
|
|
|
public static String generateLicense(String licenseName) { |
|
verboseLog("Generating a license string using the entered license name..."); |
|
ArrayList<String> al = new ArrayList<>(); |
|
al.add(getRandomString()); |
|
al.add("license"); |
|
al.add(licenseName); |
|
al.add("4102415999000"); //Time stamp (Format: Milliseconds), license expires at Thu Dec 31 2099 15:59:59 GMT+0000 |
|
al.add("1"); |
|
al.add("full"); |
|
verboseLog("Adding random string, type, license name, expiration date, user count, and license level to the data..."); |
|
verboseLog("Data prepared: "+al); |
|
verboseLog("Signing the data using SHA256 and SHA1 algorithms with respective private keys..."); |
|
al.add(generateSignature(privateKey2048, stringsToByteArray(al), "SHA256withRSA")); |
|
al.add(generateSignature(privateKey1024, stringsToByteArray(al), "SHA1withRSA")); |
|
return prepareArray(al); |
|
} |
|
|
|
public static String generateActivation(String activationRequest) { |
|
verboseLog("Decoding the activation request to extract parameters..."); |
|
byte[] rawBytes = decrypt(Base64.getDecoder().decode(activationRequest)); |
|
ArrayList<String> al = new ArrayList<>(); |
|
int from = 0; |
|
for (int i = 0; i < rawBytes.length; ++i) { |
|
if (rawBytes[i] == 0) { |
|
al.add(new String(rawBytes, from, i - from)); |
|
from = i + 1; |
|
} |
|
} |
|
al.add(new String(rawBytes, from, rawBytes.length - from)); |
|
|
|
if (al.size() != 5) { |
|
return "Error decoding activation request :-("; |
|
} else { |
|
verboseLog("Parameters extracted: " + al); |
|
verboseLog("Constructing an ArrayList to store activation data..."); |
|
ArrayList<String> activationList = new ArrayList<>(); |
|
activationList.add("41414141"); // ¯\_(ツ)_/¯ |
|
activationList.add(al.get(0)); |
|
activationList.add("activation"); |
|
activationList.add(al.get(1)); |
|
activationList.add("True"); |
|
activationList.add(""); |
|
activationList.add(al.get(2)); |
|
activationList.add(al.get(3)); |
|
verboseLog("Final activation request parameters: " + activationList); |
|
verboseLog("Signing the data using SHA256 and SHA1 algorithms with respective private keys..."); |
|
activationList.add(generateSignature(privateKey2048, stringsToByteArray(activationList), "SHA256withRSA")); |
|
activationList.add(generateSignature(privateKey1024, stringsToByteArray(activationList), "SHA1withRSA")); |
|
return prepareArray(activationList); |
|
} |
|
} |
|
|
|
private static byte[] stringsToByteArray(List<String> list) { |
|
try { |
|
ByteArrayOutputStream byteArray = new ByteArrayOutputStream(); |
|
for (String s : list) { |
|
byteArray.write(s.getBytes()); |
|
byteArray.write(0); |
|
} |
|
return byteArray.toByteArray(); |
|
} catch (Exception e) { |
|
e.printStackTrace(); |
|
throw new RuntimeException(e); |
|
} |
|
} |
|
|
|
private static String generateSignature(String pri, byte[] data, String method) { |
|
try { |
|
Signature sign = Signature.getInstance(method); |
|
sign.initSign(generateRSAPrivateKeyFromHex(pri)); |
|
sign.update(data); |
|
byte[] signature = sign.sign(); |
|
return Base64.getEncoder().encodeToString(signature); |
|
} catch (Exception e) { |
|
e.printStackTrace(); |
|
return null; |
|
} |
|
} |
|
|
|
public static RSAPrivateKey generateRSAPrivateKeyFromHex(String hexStr) { |
|
BigInteger hex = new BigInteger(hexStr, 16); |
|
byte[] priData = hex.toByteArray(); |
|
try { |
|
KeyFactory keyFactory = KeyFactory.getInstance("RSA"); |
|
PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(priData); |
|
return (RSAPrivateKey) keyFactory.generatePrivate(pkcs8EncodedKeySpec); |
|
} catch (InvalidKeySpecException | NoSuchAlgorithmException e) { |
|
e.printStackTrace(); |
|
return null; |
|
} |
|
} |
|
|
|
private static String getRandomString() { |
|
verboseLog("Generating random alphanumeric string of length 32..."); |
|
String CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"; |
|
StringBuilder str = new StringBuilder(); |
|
Random rnd = new Random(); |
|
while (str.length() < 32) { |
|
int index = (int) (rnd.nextFloat() * CHARS.length()); |
|
str.append(CHARS.charAt(index)); |
|
} |
|
return str.toString(); |
|
} |
|
|
|
private static String prepareArray(ArrayList<String> list) { |
|
try { |
|
ByteArrayOutputStream byteArray = new ByteArrayOutputStream(); |
|
for (int i = 0; i < list.size() - 1; ++i) { |
|
byteArray.write(list.get(i).getBytes()); |
|
byteArray.write(0); |
|
} |
|
byteArray.write(list.get(list.size() - 1).getBytes()); |
|
verboseLog("Encrypting the signed data using DES algorithm..."); |
|
verboseLog("Encoding the encrypted data into Base64 format..."); |
|
return Base64.getEncoder().encodeToString(encrypt(byteArray.toByteArray())); |
|
} catch (Exception e) { |
|
e.printStackTrace(); |
|
throw new RuntimeException(e); |
|
} |
|
} |
|
|
|
private static byte[] encrypt(byte[] arrayOfByte) { |
|
try { |
|
SecretKeySpec localSecretKeySpec = new SecretKeySpec(encryptionKey, "DES"); |
|
Cipher localCipher = Cipher.getInstance("DES"); |
|
localCipher.init(Cipher.ENCRYPT_MODE, localSecretKeySpec); |
|
return localCipher.doFinal(arrayOfByte); |
|
} catch (Exception e) { |
|
e.printStackTrace(); |
|
throw new RuntimeException(e); |
|
} |
|
} |
|
|
|
private static byte[] decrypt(byte[] arrayOfByte) { |
|
verboseLog("Decrypting the data using DES algorithm..."); |
|
try { |
|
SecretKeySpec localSecretKeySpec = new SecretKeySpec(encryptionKey, "DES"); |
|
Cipher localCipher = Cipher.getInstance("DES"); |
|
localCipher.init(Cipher.DECRYPT_MODE, localSecretKeySpec); |
|
return localCipher.doFinal(arrayOfByte); |
|
} catch (Exception e) { |
|
e.printStackTrace(); |
|
throw new RuntimeException(e); |
|
} |
|
} |
|
|
|
private static void verboseLog(String message) { |
|
if (VERBOSE_ENABLED) System.out.println("\u001B[36mVERBOSE: " + message + "\u001B[0m"); |
|
} |
|
|
|
private static void printBanner() { |
|
System.out.println("\033[1;33mOffline Activator [Version 1.0.0 Beta] by Bipin Jiitya (@win3zz)"); |
|
System.out.println("Java Version: " + System.getProperty("java.version") + "\033[0m"); |
|
System.out.println("\n\033[1;31mDisclaimer: The Offline Activator is intended solely for academic and research purposes. \n" + |
|
"Any misuse or unauthorized use of this tool for unethical activities is strictly prohibited. \n" + |
|
"Researchers are responsible for adhering to ethical guidelines and legal regulations governing research activities.\033[0m\n"); |
|
} |
|
} |