Skip to content

Instantly share code, notes, and snippets.

@win3zz
Created April 24, 2024 09:09
Show Gist options
  • Save win3zz/06438ca068f20ed06ae74cd374858cbb to your computer and use it in GitHub Desktop.
Save win3zz/06438ca068f20ed06ae74cd374858cbb to your computer and use it in GitHub Desktop.
Activator

Activator - Java program

Important

IT DOES NOT FACILITATE THE CIRCUMVENTION OF LEGITIMATE LICENSING MECHANISMS. TO PREVENT MISUSE, I HAVE REMOVED ENCRYPTION KEY AND PRIVATE KEYS USED IN THE ACTIVATION PROCESS.

Commercial and enterprise-level software companies employ licensing techniques to control access and prevent unauthorized use. How Do They Do It? I analyzed one such software product and developed this Activator. It is a research tool - a simple Java program - created to demonstrate the activation process of java software licenses in an offline environment. It is intended for academic and research purposes only and should not be used for any unauthorized activities.

The Java program has been tested on Ubuntu 20.04.6 LTS with Java Version 17.0.10.

Note

Before hosting it on GitHub, I reviewed GitHub's terms of service and policies, ensuring compliance with all guidelines.

How to Use:

2024-04-24_14-04

If everything goes well, you'll see the following or similar message in the target software:

Your license is successfully installed and activated.

Disclaimer:

The Activator is intended solely for academic and research purposes. Any unauthorized activities, including circumventing software licensing mechanisms, are strictly prohibited. Use at your own risk. By accessing or using this tool, you agree to abide by these terms.

/**
* 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");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment