使用java生成激活碼和密鑰的方法
解密與加密設(shè)計(jì)思路
加密:
采用AES對(duì)稱加密、解密
7位數(shù): 32進(jìn)制序列(4位) + 密鑰類別(2位)+ 有效時(shí)長(zhǎng)(1位)
加密后密鑰為11位
4位數(shù):前三位,先獲取一個(gè)(0到2500)的隨機(jī)數(shù),然后再乘11,接著轉(zhuǎn)換為三位的32進(jìn)制數(shù),然后最后一位是(機(jī)器版本號(hào)),
最后 3位+1位 生成4位數(shù)
預(yù)想15位密鑰
11位+4位
接著密鑰打亂順序混淆
混淆策略:先分別獲取激活碼的奇數(shù)位和偶數(shù)位,然后將奇數(shù)位和偶數(shù)位拼接獲得混淆后的激活碼
奇數(shù)位+偶數(shù)位
解密:
(1) 解除混淆(將混淆后的激活碼進(jìn)行重組復(fù)原)
(2) 校驗(yàn)密鑰后四位;校驗(yàn)成功繼續(xù)下一步操作,校驗(yàn)失敗密鑰無(wú)效
(3) 只有校驗(yàn)成功才能對(duì)前十一位密鑰進(jìn)行解密;校驗(yàn)失敗密鑰無(wú)效
(4) 解密成功,說(shuō)明是有效密鑰,獲取密鑰信息,根據(jù)信息對(duì)客戶端進(jìn)行相應(yīng)操作;解密失敗,說(shuō)明密鑰無(wú)效
(5) 無(wú)論解密成功與否給服務(wù)端發(fā)請(qǐng)求,通知服務(wù)端,然后進(jìn)行相應(yīng)的操作和記錄
其中:密鑰類別(2位)可以用來(lái)表示該激活碼用來(lái)激活哪些設(shè)備或者哪些平臺(tái)(如01表示某個(gè)平臺(tái),02表示某個(gè)app),時(shí)長(zhǎng)(1位)用來(lái)表示該激活碼的有效時(shí)長(zhǎng)(如0表示永久、1表示7天、2表示30天等)
注意:前7位數(shù)加密后為11位,表示該激活碼可以生成的個(gè)數(shù);后4位數(shù)為隨機(jī)數(shù) * 11轉(zhuǎn)32進(jìn)制和混淆策略是為了激活碼的加密性,用來(lái)校驗(yàn)該激活碼是否有效
因此,該激活碼的加密主要體現(xiàn)在三個(gè)地方:
- 混淆策略
- 32禁止轉(zhuǎn)18進(jìn)制后能否被11整除
- AES對(duì)稱加密、解密
解密與加密工具類
CDKeyUtil.java
import java.util.Random;
/**
* Created by tao.
* Date: 2021/6/28 16:43
* 描述:
*/
public class CDKeyUtil {
//機(jī)器版本號(hào)
/**
* 激活碼生成方法
*
* @param category 密鑰類別(固定兩位數(shù)字)
* @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.對(duì)明文進(jìn)行加密
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位版本號(hào),后三位校驗(yàn)其規(guī)則)
String sequence = deConfusion.substring(deConfusion.length() - 4);
//3. 獲取后三位序列并且轉(zhuǎn)為10進(jìn)制,和版本號(hào)
String randomInt = sequence.substring(1);
String version = sequence.substring(0, 1);
int to10 = Integer.parseInt(change32To10(randomInt));
//4. 根據(jù)既定規(guī)則校驗(yàn)激活碼是否正確
if (to10 % 11 == 0 && version.equals(machineVersion)) {
//1. 如果后四位序列校驗(yàn)正確,則對(duì)激活碼進(jìn)行解密操作
String secretKey = deConfusion.substring(0, 11);
String code = "";
try {
code = CDKeyEncryptUtils.AESdecrypt(secretKey);
} catch (Exception e) {
e.printStackTrace();
return "激活碼錯(cuò)誤";
}
return code;
} else {
return "激活碼錯(cuò)誤";
}
}
/**
* 獲得激活碼前四位序列方法
*
* @return 返回激活碼前四位序列
*/
public static String getSequence() {
String sequence = "";
//1. 獲取隨機(jī)數(shù)
int randomInt = getRandomInt();
//2. 轉(zhuǎn)32進(jìn)制
String to32 = change10To32(randomInt + "");
//3. 補(bǔ)全四位
int len = to32.length();
if (len < 4) {
for (int i = 0; i < 4 - len; i++) {
to32 = "0" + to32;
}
}
sequence = to32;
return sequence;
}
/**
* 獲得激活碼后四位規(guī)則序列方法
*
* @param machineVersion 機(jī)器版本號(hào)
* @return 返回激活碼后四位規(guī)則序列
*/
public static String getRulesSequence(String machineVersion) {
String rulesSequence;
//1. 按照規(guī)則獲取前三位
/*int randomInt = new Random().nextInt(8);
String randomStr = randomInt + "" + (randomInt + 1) + (randomInt + 2);*/
//1. 按照規(guī)則獲取前三位
int randomInt = new Random().nextInt(2500);
String randomStr = (randomInt * 11) + "";
//2. 轉(zhuǎn)32進(jìn)制
String to32 = change10To32(randomStr);
//3. 補(bǔ)全三位
int len = to32.length();
if (len < 3) {
for (int i = 0; i < 3 - len; i++) {
to32 = "0" + to32;
}
}
//4.拼接第四位
rulesSequence = machineVersion + to32;
return rulesSequence;
}
/**
* 激活碼混淆方法
* 奇數(shù)位+偶數(shù)位
*
* @return 返回激活碼混淆后的序列
*/
public static String confusion(String CDKey) {
String deCDKey = "";
//1.獲取奇數(shù)位字串
String odd = "";
for (int i = 0; i < CDKey.length(); i = i + 2) {
odd = odd + CDKey.charAt(i);
}
//2.獲取偶數(shù)位字串
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. 復(fù)原激活碼
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進(jìn)制轉(zhuǎn)32進(jìn)制的方法
* num 要轉(zhuǎn)換的數(shù) from源數(shù)的進(jìn)制 to要轉(zhuǎn)換成的進(jìn)制
*
* @param num 10進(jìn)制(字符串)
* @return 轉(zhuǎn)換結(jié)果的32進(jìn)制字符串
*/
public static String change10To32(String num) {
int from = 10;
int to = 32;
return new java.math.BigInteger(num, from).toString(to);
}
/**
* 32進(jìn)制轉(zhuǎn)10進(jìn)制的方法
* num 要轉(zhuǎn)換的數(shù) from源數(shù)的進(jìn)制 to要轉(zhuǎn)換成的進(jìn)制
*
* @param num 10進(jìn)制(字符串)
* @return 轉(zhuǎn)換結(jié)果的10進(jìn)制字符串
*/
public static String change32To10(String num) {
int f = 32;
int t = 10;
return new java.math.BigInteger(num, f).toString(t);
}
/**
* 生成[min, max]之間的隨機(jī)整數(shù)
* min 最小整數(shù)(固定0)
* max 最大整數(shù)(固定1000000)
*
* @return 返回min———max之間的隨機(jī)數(shù)
* @author tao
*/
public static int getRandomInt() {
int min = 0;
int max = 1000000;
return new Random().nextInt(max) % (max - min + 1) + min;
}
/*
* 枚舉日期,返回天數(shù)
*/
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"; // 默認(rèn)的加密算法,CBC模式
public static String AESencrypt(String data) throws Exception {
//指定算法、獲取Cipher對(duì)象(DES/CBC/PKCS5Padding:算法為,工作模式,填充模式)
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
//根據(jù)自定義的加密密匙和算法模式初始化密鑰規(guī)范
SecretKeySpec skeySpec = new SecretKeySpec(KEY.getBytes("ASCII"), ALGORITHM);
//CBC模式偏移量IV
IvParameterSpec iv = new IvParameterSpec(OFFSET.getBytes());
//初始化加密模式
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
//單部分加密結(jié)束,重置Cipher
byte[] encrypted = cipher.doFinal(data.getBytes(ENCODING));
//加密后再使用BASE64做轉(zhuǎn)碼
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對(duì)象(DES/CBC/PKCS5Padding:算法為,工作模式,填充模式)
Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
//根據(jù)自定義的加密密匙和算法模式初始化密鑰規(guī)范
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);
//單部分加密結(jié)束,重置Cipher
byte[] encrypted = cipher.doFinal(buffer);
return new String(encrypted, ENCODING);
}
}
其中AES的key為12055296,設(shè)置為8位,則機(jī)密后的密文則為11位,加密算法為 “DES”
激活碼生成測(cè)試
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);
}
}
執(zhí)行結(jié)果:

到此這篇關(guān)于使用java生成激活碼和密鑰的方法的文章就介紹到這了,更多相關(guān)java生成激活碼和密鑰內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
如何處理maven倉(cāng)庫(kù)中后綴LastUpdated文件
這篇文章主要介紹了如何處理maven倉(cāng)庫(kù)中后綴LastUpdated文件,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04
淺析Java語(yǔ)言中狀態(tài)模式的優(yōu)點(diǎn)
狀態(tài)模式允許對(duì)象在內(nèi)部狀態(tài)改變時(shí)改變它的行為,對(duì)象看起來(lái)好像修改了它的類。這個(gè)模式將狀態(tài)封裝成獨(dú)立的類,并將動(dòng)作委托到 代表當(dāng)前狀態(tài)的對(duì)象,我們知道行為會(huì)隨著內(nèi)部狀態(tài)而改變2023-02-02
Java核心庫(kù)實(shí)現(xiàn)簡(jiǎn)單的AOP
這篇文章主要介紹了如何用Java核心庫(kù)實(shí)現(xiàn)簡(jiǎn)單的AOP,幫助大家為了更好的理解和學(xué)習(xí)AOP的思想,感興趣的朋友可以了解下2020-08-08
一文詳解Java如何系統(tǒng)地避免空指針問(wèn)題
新手Java開(kāi)發(fā)總是經(jīng)常空指針檢查,甚至某些老手也會(huì)犯這樣的問(wèn)題,所以這篇文章小編就帶大家一起來(lái)看看如何系統(tǒng)地避免空指針問(wèn)題,希望對(duì)大家有所幫助2024-01-01
Spring Cloud Eureka 服務(wù)上下線監(jiān)控的實(shí)現(xiàn)
這篇文章主要介紹了Spring Cloud Eureka 服務(wù)上下線監(jiān)控的實(shí)現(xiàn),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-09-09
IDEA新建Springboot項(xiàng)目(圖文教程)
下面小編就為大家?guī)?lái)一篇IDEA新建Springboot項(xiàng)目(圖文教程)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-07-07

