暗号化:
AES 対称暗号化と復号化の使用
7 桁: 32 桁のシーケンス (4 桁) キー カテゴリ ( 2 桁) ) 有効期間 (1 桁)
暗号化キーは 11 桁です
4 桁: 最初の 3 桁は、まず乱数 (0 ~ 2500) を取得し、次に 11 を掛けて、A 3 に変換します。 -桁の 16 進数、最後の桁は (マシンのバージョン番号)、
最後の 3 桁と 1 桁で 4 桁の数値が生成されます
予期される 15 桁のキー
11 桁と 4 桁
その後、キーはスクランブルされて混乱します
混乱戦略: まずアクティベーション コードの奇数桁と偶数桁をそれぞれ取得し、次に奇数桁と偶数桁を結合して難読化されたアクティベーション コードを取得します
奇数桁と偶数桁
復号化:
(1) 難読化を解除します (難読化されたアクティベーション コードを再編成して復元します)
(2) キーの最後の 4 桁を確認します。成功しました。続行 ワンステップ操作。検証が失敗した場合、キーは無効です。
(3) 最初の 11 キーは、検証が成功した場合にのみ復号化できます。検証が失敗した場合、キーは無効です。
(4) ) 復号化が成功した場合は、それが有効なキーであることを示し、キー情報を取得し、その情報に基づいてクライアント上で対応する操作を実行します。復号化は失敗し、キーが無効であることを示します
(5)復号化が成功したかどうかを確認するには、サーバーにリクエストを送信し、サーバーに通知して、対応する操作と記録を実行します。
その中で、キー カテゴリ (2 桁) を使用して、どのデバイスまたはプラットフォームが復号化されているかを示すことができます。アクティベーション コードはアクティベーションに使用されます (たとえば、01 は特定のプラットフォームを表し、02 は特定のアプリを表します)。期間 (1 桁) アクティベーション コードの有効期間を示すために使用されます (たとえば、0 は永久、1 は 7 日間、2 は 7 日間を意味します) 30 日などを意味します)
注: 最初の 7 桁は 11 桁に暗号化され、アクティベーション コードを生成できる番号であることを示します。最後の 4 桁は乱数 * 11 ~ 32 の 10 進数と難読化です。戦略はアクティベーション コードを暗号化するためのもので、アクティベーション コードが有効かどうかを確認するために使用されます。
import java.util.Random; /** * Created by tao. * Date: 2021/6/28 16:43 * 描述: */ public class CDKeyUtil { //机器版本号 /** * 激活码生成方法 * * @param category 密钥类别(固定两位数字) * @param deadline 使用期限(固定一位字符) * @return 返回的激活码 */ public static String createCDkey(String category, String deadline, String machineVersion) throws Exception { String CDKey = ""; //1. 获取前四位 String sequence = getSequence(); //2. 生成前七位 String plaintext = sequence + category + deadline; //3.对明文进行加密 CDKey = CDKeyEncryptUtils.AESencrypt(plaintext).substring(0, 11); //4.获取后四位 String rulesSequence = CDKeyUtil.getRulesSequence(machineVersion); //5.混淆操作 CDKey = CDKey + rulesSequence; CDKey = confusion(CDKey); //6.得到激活码 return CDKey; } /** * 激活码解码方法 * * @param CDKey 激活码 * @return 返回激活码明文 */ public static String deCDkey(String CDKey, String machineVersion) throws Exception { //1. 解除混淆 String deConfusion = deConfusion(CDKey); //2. 提取后四位序列(第1位版本号,后三位校验其规则) String sequence = deConfusion.substring(deConfusion.length() - 4); //3. 获取后三位序列并且转为10进制,和版本号 String randomInt = sequence.substring(1); String version = sequence.substring(0, 1); int to10 = Integer.parseInt(change32To10(randomInt)); //4. 根据既定规则校验激活码是否正确 if (to10 % 11 == 0 && version.equals(machineVersion)) { //1. 如果后四位序列校验正确,则对激活码进行解密操作 String secretKey = deConfusion.substring(0, 11); String code = ""; try { code = CDKeyEncryptUtils.AESdecrypt(secretKey); } catch (Exception e) { e.printStackTrace(); return "激活码错误"; } return code; } else { return "激活码错误"; } } /** * 获得激活码前四位序列方法 * * @return 返回激活码前四位序列 */ public static String getSequence() { String sequence = ""; //1. 获取随机数 int randomInt = getRandomInt(); //2. 转32进制 String to32 = change10To32(randomInt + ""); //3. 补全四位 int len = to32.length(); if (len < 4) { for (int i = 0; i < 4 - len; i++) { to32 = "0" + to32; } } sequence = to32; return sequence; } /** * 获得激活码后四位规则序列方法 * * @param machineVersion 机器版本号 * @return 返回激活码后四位规则序列 */ public static String getRulesSequence(String machineVersion) { String rulesSequence; //1. 按照规则获取前三位 /*int randomInt = new Random().nextInt(8); String randomStr = randomInt + "" + (randomInt + 1) + (randomInt + 2);*/ //1. 按照规则获取前三位 int randomInt = new Random().nextInt(2500); String randomStr = (randomInt * 11) + ""; //2. 转32进制 String to32 = change10To32(randomStr); //3. 补全三位 int len = to32.length(); if (len < 3) { for (int i = 0; i < 3 - len; i++) { to32 = "0" + to32; } } //4.拼接第四位 rulesSequence = machineVersion + to32; return rulesSequence; } /** * 激活码混淆方法 * 奇数位+偶数位 * * @return 返回激活码混淆后的序列 */ public static String confusion(String CDKey) { String deCDKey = ""; //1.获取奇数位字串 String odd = ""; for (int i = 0; i < CDKey.length(); i = i + 2) { odd = odd + CDKey.charAt(i); } //2.获取偶数位字串 String even = ""; for (int i = 1; i < CDKey.length(); i = i + 2) { even = even + CDKey.charAt(i); } //3.拼接 deCDKey = odd + even; return deCDKey; } /** * 激活码解除混淆方法 * * @return 返回激活码解除混淆后的序列 */ public static String deConfusion(String deCDKey) { String CDKey = ""; //1. 拆分 int oddCount = (deCDKey.length() / 2) + (deCDKey.length() % 2); String odd = deCDKey.substring(0, oddCount); String even = deCDKey.substring(oddCount); //2. 复原激活码 if (odd.length() == even.length()) { for (int i = 0; i < odd.length(); i++) { CDKey = CDKey + odd.charAt(i) + even.charAt(i); } } else { for (int i = 0; i < even.length(); i++) { CDKey = CDKey + odd.charAt(i) + even.charAt(i); } CDKey = CDKey + odd.charAt(odd.length() - 1); } return CDKey; } /** * 10进制转32进制的方法 * num 要转换的数 from源数的进制 to要转换成的进制 * * @param num 10进制(字符串) * @return 转换结果的32进制字符串 */ public static String change10To32(String num) { int from = 10; int to = 32; return new java.math.BigInteger(num, from).toString(to); } /** * 32进制转10进制的方法 * num 要转换的数 from源数的进制 to要转换成的进制 * * @param num 10进制(字符串) * @return 转换结果的10进制字符串 */ public static String change32To10(String num) { int f = 32; int t = 10; return new java.math.BigInteger(num, f).toString(t); } /** * 生成[min, max]之间的随机整数 * min 最小整数(固定0) * max 最大整数(固定1000000) * * @return 返回min———max之间的随机数 * @author tao */ public static int getRandomInt() { int min = 0; int max = 1000000; return new Random().nextInt(max) % (max - min + 1) + min; } /* * 枚举日期,返回天数 */ public static int duetimeEnum(String code) { switch (code) { case "0": return 36500; case "1": return 7; case "2": return 30; case "3": return 90; case "4": return 180; case "5": return 365; default: return 30; } } }
import org.apache.commons.codec.binary.Base64; import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; /** * Created by tao. * Date: 2021/6/28 16:37 * 描述: */ public class CDKeyEncryptUtils { //--------------AES--------------- private static final String KEY = "12055296"; // 密匙,必须16位 private static final String OFFSET = "12055296"; // 偏移量 private static final String ENCODING = "UTF-8"; // 编码 private static final String ALGORITHM = "DES"; //算法 private static final String CIPHER_ALGORITHM = "DES/CBC/PKCS5Padding"; // 默认的加密算法,CBC模式 public static String AESencrypt(String data) throws Exception { //指定算法、获取Cipher对象(DES/CBC/PKCS5Padding:算法为,工作模式,填充模式) Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); //根据自定义的加密密匙和算法模式初始化密钥规范 SecretKeySpec skeySpec = new SecretKeySpec(KEY.getBytes("ASCII"), ALGORITHM); //CBC模式偏移量IV IvParameterSpec iv = new IvParameterSpec(OFFSET.getBytes()); //初始化加密模式 cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv); //单部分加密结束,重置Cipher byte[] encrypted = cipher.doFinal(data.getBytes(ENCODING)); //加密后再使用BASE64做转码 return new Base64().encodeToString(encrypted); } /** * AES解密 * * @param data * @return String * @author tao * @date 2021-6-15 16:46:07 */ public static String AESdecrypt(String data) throws Exception { //指定算法、获取Cipher对象(DES/CBC/PKCS5Padding:算法为,工作模式,填充模式) Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); //根据自定义的加密密匙和算法模式初始化密钥规范 SecretKeySpec skeySpec = new SecretKeySpec(KEY.getBytes("ASCII"), ALGORITHM); //CBC模式偏移量IV IvParameterSpec iv = new IvParameterSpec(OFFSET.getBytes()); //初始化解密模式 cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv); //先用base64解码 byte[] buffer = new Base64().decode(data); //单部分加密结束,重置Cipher byte[] encrypted = cipher.doFinal(buffer); return new String(encrypted, ENCODING); } }
public static void main(String[] args) throws Exception { for (int i = 0; i < 10; i++) { String CDKey = CDKeyUtil.createCDkey("01", "0", "1"); System.out.println("激活码:" + CDKey); String deCDkey = CDKeyUtil.deCDkey(CDKey, "1"); System.out.println("激活码解密:" + deCDkey); } }
以上がJava を使用してアクティベーション コードとキーを生成する方法。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。