使用java生成激活码和密钥的方法(Java激活码)

网友投稿 636 2022-07-30


目录解密与加密设计思路解密与加密工具类激活码生成测试

解密与加密设计思路

加密:采用AES对称加密、解密7位数: 32进制序列(4位) + 密钥类别(2位)+ 有效时长(1位)加密后密钥为11位4位数:前三位,先获取一个(0到2500)的随机数,然后再乘11,接着转换为三位的32进制数,然后最后一位是(机器版本号),最后 3位+1位 生成4位数预想15位密钥11位+4位接着密钥打乱顺序混淆

混淆策略:先分别获取激活码的奇数位和偶数位,然后将奇数位和偶数位拼接获得混淆后的激活码奇数位+偶数位

解密:(1) 解除混淆(将混淆后的激活码进行重组复原)(2) 校验密钥后四位;校验成功继续下一步操作,校验失败密钥无效(3) 只有校验成功才能对前十一位密钥进行解密;校验失败密钥无效(4) 解密成功,说明是有效密钥,获取密钥信息,根据信息对客户端进行相应操作;解密失败,说明密钥无效(5) 无论解密成功与否给服务端发请求,通知服务端,然后进行相应的操作和记录

其中:密钥类别(2位)可以用来表示该激活码用来激活哪些设备或者哪些平台(如01表示某个平台,02表示某个app),时长(1位)用来表示该激活码的有效时长(如0表示永久、1表示7天、2表示30天等)注意:前7位数加密后为11位,表示该激活码可以生成的个数;后4位数为随机数 * 11转32进制和混淆策略是为了激活码的加密性,用来校验该激活码是否有效

因此,该激活码的加密主要体现在三个地方:

混淆策略32禁止转18进制后能否被11整除AES对称加密、解密

解密与加密工具类

CDKeyUtil.java

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 = CDKeyhttp:// + 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进http://制的方法

* 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;

}

}

}

其中用到AES加密和解密:CDKeyEncryptUtils.java

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);

}

}

其中AES的key为12055296,设置为8位,则机密后的密文则为11位,加密算法为 “DES”

激活码生成测试

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);

}

}

执行结果:


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:超详细讲解SpringBoot参数校验实例(springboot参数校验框架)
下一篇:Java你不了解的大数型BigInteger与BigDecimal类(java biginteger比较大小)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~