1. 程式人生 > >關於網站java license單機授權認證的見解

關於網站java license單機授權認證的見解

echo ket 檢查 數組 ber 進制數 如何 tle mir

  在給客戶公司開發網站往往需要進行一個授權認證機制防止知識產權被侵犯。我就講講在最近一個項目中用到的授權機制,一直想整理一下做個總結但都沒有一個合適的時間段,今天我就詳細說說我怎麽實現的歡迎大家指正漏洞哦。

一、背景:單機實現認證過程,也就是通過讀取一個文件(xxx.lic)來判斷是否認證過。產品類似桌面應用需要安裝包,客戶要想使用該產品裝完產品後第一次打開時是需要完成一個授權認證的(需要讀取上面說的xxx.lic文件)。該文件的產生是由開發者公司提供,可設置使用期限。

二、所用到的技術:RSA非對稱加密和MD5算法。

三、說明:RSA算法只用到其中的數字簽名為了防止文件被惡意篡改,主要的認證信息還是用到的MD5加密。因為是單機授權沒有必要使用RSA的加密算法,只是為了保證一個授權文件只能在一臺電腦上使用一個MD5就夠了(MD5中也可以加入自己的算法)。

  主要是獲取電腦的cpu序列號,mac 地址 硬盤序列號 等信息作為唯一標識進行認證 可設置授權的開始時間和結束時間來驗證是否過期。

下面直接上代碼吧,歡迎指正。

1、首先是加密解密類 RSATester.java

package com.softetone.xxx.client.util.license;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.Properties;

import com.alibaba.fastjson.JSONObject;
/**
* @className: RSATester
* @description: RSA 加密 解密 類
* @author: yjb
* @createTime: 2017-12-01 下午10:03:44
*/
public class RSATester {
static String publicKey;
static String privateKey;
static {
try {
Map<String, Object> keyMap = RSAUtils.genKeyPair();
publicKey = RSAUtils.getPublicKey(keyMap);
privateKey = RSAUtils.getPrivateKey(keyMap);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws Exception {
test();
// licenseCheck();
// getConfig("");
}
/**
* 公鑰加密——私鑰解密
*
* @throws Exception
*/
static void test() throws Exception {
System.err.println("公鑰加密——私鑰解密");
Date endtime = null;
String str1 = "";
String str2 = "";
String str22 = "";
String str2type = "";
String str3 = "";
Boolean status = true;
// 明文
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
while (true) {
System.out.println("請輸入授權類型 1 or 2 : 1、客戶端 2、服務端");
str3 = SystemTool.ReadTest();
if ("1".equals(str3) || "2".equals(str3)) {
break;
} else {
System.out.println("您輸入的授權類型有誤,請重新輸入!!!");
continue;
}
}
// System.out.println("請輸入授權過期日期:格式如:2017-12-01 12:30:30");
while (status) {
System.out.println("請選擇授權過期日期:1、一個月 2、三個月 3、六個月 4、一年 5、三年 6、自定義日期");
str2type = SystemTool.ReadTest();
str1 = df.format(new Date());
if ("1".equals(str2type)) {
endtime = SystemTool.getSomeDay(new Date(), 30);
break;
} else if ("2".equals(str2type)) {
endtime = SystemTool.getSomeDay(new Date(), 90);
break;
} else if ("3".equals(str2type)) {
endtime = SystemTool.getSomeDay(new Date(), 180);
break;
} else if ("4".equals(str2type)) {
endtime = SystemTool.getSomeDay(new Date(), 365);
break;
} else if ("5".equals(str2type)) {
endtime = SystemTool.getSomeDay(new Date(), 1095);
break;
} else if ("6".equals(str2type)) {
System.out.println("請輸入自定義日期 格式如:2017-12-01 12:30:30");
str22 = SystemTool.ReadTest();
break;
} else {
System.out.println("您輸入的授權過期日期類型有誤,請重新出入!!!");
continue;
}
}
if ("6".equals(str2type)) {
str2 = str22;
} else {
str2 = df.format(endtime);
}
// String machineCode=SystemTool.getMachineCode();//MD5加密的機器碼
System.out.println("請輸入機器碼:");
String machineCode = SystemTool.ReadTest();
JSONObject localJSONObject = new JSONObject();
localJSONObject.put("starttime", str1);
localJSONObject.put("endtime", str2);
localJSONObject.put("lictype", str3);
localJSONObject.put("machinecode", machineCode);
String source = localJSONObject.toString();
System.out.println("\r加密前文字:\r\n" + source);
byte[] data = source.getBytes();
// byte[] encodedData = RSAUtils.encryptByPublicKey(data, publicKey);
byte[] encodedData = RSAUtils.encryptByPrivateKey(data, privateKey);
String encodedDatastr = bytesToString(encodedData);
// System.out.println("加密後文字:\r\n" + new String(encodedData));
// System.out.println("加密後經轉換格式後的數據:\r\n" + encodedDatastr);
// 簽名
// System.err.println("私鑰簽名——公鑰驗證簽名");
String sign = RSAUtils.sign(encodedData, privateKey);
// System.err.println("簽名:\r" + sign);
// 寫入本地的內容 簽名 + 加密後的密文
String content = publicKey+ "$$" + sign + encodedDatastr;
// 生成認證文件
String path = SystemTool.getProjectPath();
File localFile2 = new File(path + "\\xxx.lic");
if (localFile2.exists())
localFile2.delete();
PrintWriter localPrintWriter2 = new PrintWriter(new OutputStreamWriter(new FileOutputStream(localFile2)), true);
localPrintWriter2.println(content);
localPrintWriter2.close();
System.out.println("xxx.lic 生成成功!目錄:" + path);
}

public static String bytesToString(byte[] arr) {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < arr.length; i++) {
if (i == 0) {
sb.append(arr[i]);
} else {
sb.append("|").append(arr[i]);
}
}
return sb.toString();
}

public static byte[] stringToBytes(String str) {

String[] arr = str.split("\\|");

byte[] bytes = new byte[arr.length];
arr[arr.length - 1] = arr[arr.length - 1].trim();
for (int i = 0; i < arr.length; i++) {
bytes[i] = Byte.valueOf(arr[i]);
}
return bytes;
}

/**
* 單機驗證授權 解析授權文件 xxx.lic
*
* @return
* @throws WDKException
*/
public static boolean licenseCheck() {
try {
String path = SystemTool.getProjectPath();
File localFile = new File(path + "\xxx.lic");
if (localFile.exists()) {
byte[] arrayOfByte = new byte[Integer.parseInt(Long.toString(localFile.length()))];
FileInputStream localFileInputStream = new FileInputStream(localFile);
localFileInputStream.read(arrayOfByte);
localFileInputStream.close();
String str = new String(arrayOfByte);
// System.out.println("讀取文件內容:" + str);
String decodedData1 = "";
String sign = "";
String publickey2 = "";
if (str.indexOf("$$") != -1) {
sign = str.substring(str.indexOf("$$") + 2, str.indexOf("=") + 1);// 簽名
publickey2 = str.substring(0, str.indexOf("$$"));// 公鑰

} else {
System.out.println("授權文件已被修改,如需繼續使用本軟件請重新進行授權!!!");
return false;
}
if (str.indexOf("=") != -1) {
decodedData1 = str.substring(str.indexOf("=") + 1, str.length() - 1);// 密文
} else {
System.out.println("授權文件已被修改,如需繼續使用本軟件請重新進行授權!!!");
return false;
}
// System.out.println("解析後的公鑰:" + publickey2);
byte[] data2 = stringToBytes(decodedData1);// 解析後的密文(已加密數據)
// 簽名驗證
System.out.println("開始驗證簽名——————————————————————————————————");
// System.out.println("解析後的簽名:" + sign);
boolean status = RSAUtils.verify(data2, publickey2, sign);
System.err.println("簽名驗證結果:\r" + status);
if (status) {// 簽名通過
// 解密
JSONObject localJSONObject = new JSONObject();
long LIC_Frame_endtime;
System.out.println("開始解密——————————————————————————————————");
byte[] decodedData = RSAUtils.decryptByPublicKey(data2, publickey2);
String target = new String(decodedData); // 明文
// System.out.println("解密後: \r\n" + target);
SimpleDateFormat localSimpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
localJSONObject = (JSONObject) JSONObject.parse(target);
String lictype = localJSONObject.getString("lictype");
String machinecode = localJSONObject.getString("machinecode");
String endtime = localJSONObject.getString("endtime");
String starttime = localJSONObject.getString("starttime");
if (SystemTool.ver_MacineCode(machinecode)) {// 機器驗證通過
if ("1".equals(lictype)) {
if ((null == endtime) || ("".equals(endtime))) {
LIC_Frame_endtime = 0L;
} else {
LIC_Frame_endtime = ((Date) localSimpleDateFormat.parseObject(endtime)).getTime();
boolean bool = RSAUtils.verifyendTime(LIC_Frame_endtime);// 校驗是否過期
System.out.println("授權到期時間:" + endtime);
System.err.println("授權驗證結果:\r" + bool);
if (!bool) {
System.out.println("授權信息已過期,請重新授權!!");
return false;
}
}
} else {
System.out.println("授權文件類型不正確,請重新授權!!!");
return false;
}
} else {
System.out.println("機器碼驗證失敗,請重新授權!!!");
return false;
}
} else {
System.out.println("簽名驗證失敗,請重新授權!!");
return false;
}
} else {
System.out.println(path + "未發現授權文件xxx.lic,請檢查...");
return false;
}
} catch (Exception localException) {
System.out.println("授權文件xxx.lic解析失敗...");
return false;
}
return true;
}

}
2、下面是一個工具類 SystemTool.java

package com.softetone.wrzs.client.util.license;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.URLDecoder;
import java.net.UnknownHostException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.DateTime;

/**
* @className: SystemTool
* @description: 與系統相關的一些常用工具方法. 目前實現的有:獲取MAC地址、IP地址、C硬盤序列號
* @author: yjb
* @createTime: 2017-12-01 下午10:03:44
*/
public class SystemTool {
/**
* 獲取當前操作系統名稱. return 操作系統名稱 例如:windows xp,linux 等.
*/
public static String getOSName() {
return System.getProperty("os.name").toLowerCase();
}
/**
* 生成加過密的機器碼 機器碼組成 :mac物理地址 ,本機cpu 序列號 C硬盤序列號
* @return
* @throws IOException
* @throws NoSuchAlgorithmException
*/
public static String getMachineCode() throws IOException, NoSuchAlgorithmException{
String str4=getMAC();// mac物理地址
String str5=getCpuNumber();//本機cpu 序列號
String str6=getSerialNumber("C");//C硬盤序列號
String MachineCode= str4+str5+str6;
String md5=EncoderByMd5(MachineCode);//md5加密
return md5;
}

/**
* 對機器碼進行MD5加密
* @return
* @throws IOException
* @throws NoSuchAlgorithmException
*/

public static String EncoderByMd5(String str) throws NoSuchAlgorithmException, UnsupportedEncodingException{
//確定計算方法
MessageDigest md5=MessageDigest.getInstance("MD5");
BASE64Encoder base64en = new BASE64Encoder();
//加密後的字符串
String newstr=base64en.encode(md5.digest(str.getBytes("utf-8")));
return newstr;
}
/**
* 驗證機器碼
* @param str 數據源值
* @return
* @throws NoSuchAlgorithmException
* @throws IOException
*/
public static Boolean ver_MacineCode(String str) throws NoSuchAlgorithmException, IOException {
if(str.equals(getMachineCode())){
return true;
}
return false;
}

/**
* mac物理地址
* @return
*/
public static String getMAC() {
String os =getOSName();
String mac = "";
// System.out.println("OS Type:" + os);
if (os.startsWith("windows")) {
// 本地是windows
mac = getWindowsMACAddress();
// System.out.println("MAC Address:" + mac);
} else {
// 本地是非windows系統 一般就是unix
mac = getUnixMACAddress();
// System.out.println(mac);
}
return mac;
}

/**
* 獲取unix網卡的mac地址. 非windows的系統默認調用本方法獲取.如果有特殊系統請繼續擴充新的取mac地址方法.
*
* @return mac地址
*/
public static String getUnixMACAddress() {
String mac = null;
BufferedReader bufferedReader = null;
Process process = null;
try {
process = Runtime.getRuntime().exec("ifconfig eth0");// linux下的命令,一般取eth0作為本地主網卡
// 顯示信息中包含有mac地址信息
bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = null;
int index = -1;
while ((line = bufferedReader.readLine()) != null) {
index = line.toLowerCase().indexOf("hwaddr");// 尋找標示字符串[hwaddr]
if (index >= 0) {// 找到了
mac = line.substring(index + "hwaddr".length() + 1).trim();// 取出mac地址並去除2邊空格
break;
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (bufferedReader != null) {
bufferedReader.close();
}
} catch (IOException e1) {
e1.printStackTrace();
}
bufferedReader = null;
process = null;
}

return mac;
}

/**
* 獲取widnows網卡的mac地址.
* 用模式匹配方式查找MAC地址,與操作系統的語言無關
* @return mac地址
*/
public static String getWindowsMACAddress(){
Pattern macPattern = Pattern.compile(".*((:?[0-9a-f]{2}[-:]){5}[0-9a-f]{2}).*", Pattern.CASE_INSENSITIVE);
String mac = null;
try {
Process pro = Runtime.getRuntime().exec("cmd.exe /c ipconfig/all");

InputStream is = pro.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String message = br.readLine();

int index = -1;
while (message != null) {
Matcher matcher = macPattern.matcher(message);
if (matcher.matches()) {
mac= matcher.group(1).trim();
break;
// macAddressList.add(matcher.group(1).replaceAll("[-:]",
// ""));//去掉MAC中的“-”
}
/* if ((index = message.indexOf("物理地址")) > 0) {
mac = message.substring(index + 36).trim();
break;
}*/
message = br.readLine();
}
br.close();
pro.destroy();
} catch (IOException e) {
System.out.println("Can‘t get mac address!");
return null;
}
return mac;
}



/**
* @return 本機主機名
*/
public static String getHostName() {
InetAddress ia = null;
try {
ia = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (ia == null) {
return "some error..";
} else
return ia.getHostName();
}

/**
* @return 本機IP 地址
*/
public static String getIPAddress() {
InetAddress ia = null;
try {
ia = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (ia == null) {
return "some error..";
} else
return ia.getHostAddress();
}

/**
* @return 本機cpu 序列號
* @throws IOException
*/
public static String getCpuNumber() throws IOException {
Process process = Runtime.getRuntime().exec(new String[] { "wmic", "cpu", "get", "ProcessorId" });
process.getOutputStream().close();
Scanner sc = new Scanner(process.getInputStream());
String property = sc.next();
String serial = sc.next();
//System.out.println(property + ": " + serial);
return serial;
}
/**
* 獲取硬盤序列號
* @param drive
* @return
*/

public static String getSerialNumber(String drive) {
String result = "";
try {
File file = File.createTempFile("realhowto", ".vbs");
file.deleteOnExit();
FileWriter fw = new java.io.FileWriter(file);

String vbs = "Set objFSO = CreateObject(\"Scripting.FileSystemObject\")\n"
+ "Set colDrives = objFSO.Drives\n" + "Set objDrive = colDrives.item(\"" + drive + "\")\n"
+ "Wscript.Echo objDrive.SerialNumber"; // see note
fw.write(vbs);
fw.close();
Process p = Runtime.getRuntime().exec("cscript //NoLogo " + file.getPath());
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while ((line = input.readLine()) != null) {
result += line;
}
input.close();
} catch (Exception e) {
e.printStackTrace();
}
return result.trim();
}
/**
* InputStreamReader和BufferedReader方法
* 優點: 可以獲取鍵盤輸入的字符串
* 缺點: 如何要獲取的是int,float等類型的仍然轉碼
*/

public static String ReadTest(){
System.out.println("Please input Data:");
String name = "";
InputStreamReader is = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(is);
try{
name = br.readLine();

}
catch(IOException e){
e.printStackTrace();
}
return name;
}
/**
* Scanner類中的方法
* 優點: 可以獲取鍵盤輸入的字符串
* 優點: 有現成的獲取int,float等類型數據,非常強大,也非常方便
*/
public static void ScannerTest(){
Scanner sc = new Scanner(System.in);
System.out.println("ScannerTest, Please Enter Name:");
String name = sc.nextLine();
System.out.println("ScannerTest, Please Enter Age:");
int age = sc.nextInt();
System.out.println("ScannerTest, Please Enter Salary:");
float salary = sc.nextFloat();
System.out.println("Your Information is as below:");
System.out.println("Name:" + name +"\n" + "Age:"+age + "\n"+"Salary:"+salary);
}
/**
* @param date
* @param day 想要獲取的日期與傳入日期的差值 比如想要獲取傳入日期前四天的日期 day=-4即可
* @return
*/
public static Date getSomeDay(Date date, int day){
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.add(Calendar.DATE, day);
return calendar.getTime();
}
/**
* 取工程絕對路徑如 e://
* @return
*/
public static String getProjectPath() {
try {
return URLDecoder.decode(System.getProperty("user.dir"), "UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return System.getProperty("user.dir").replace("20%", " ");
}
/**
* 測試用的main方法.
*
* @param argc
* 運行參數.
* @throws Exception
*/
public static void main(String[] argc) throws Exception {
getSomeDay(new Date(),60);
//getWindowsMACAddress();
}
}
3、然後是一個 RSA 的工具類 RSAUtils.java

package com.softetone.wrzs.client.util.license;
import java.io.ByteArrayOutputStream;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.Cipher;

/** *//**
* <p>
* RSA公鑰/私鑰/簽名工具包
* </p>
* <p>
* 羅納德·李維斯特(Ron [R]ivest)、阿迪·薩莫爾(Adi [S]hamir)和倫納德·阿德曼(Leonard [A]dleman)
* </p>
* <p>
* 字符串格式的密鑰在未在特殊說明情況下都為BASE64編碼格式<br/>
* 由於非對稱加密速度極其緩慢,一般文件不使用它來加密而是使用對稱加密,<br/>
* 非對稱加密算法可以用來對對稱加密的密鑰加密,這樣保證密鑰的安全也就保證了數據的安全
* </p>
*
* @author IceWee
* @date 2012-4-26
* @version 1.0
*/
public class RSAUtils {

/** *//**
* 加密算法RSA
*/
public static final String KEY_ALGORITHM = "RSA";

/** *//**
* 簽名算法
*/
public static final String SIGNATURE_ALGORITHM = "MD5withRSA";

/** *//**
* 獲取公鑰的key
*/
private static final String PUBLIC_KEY = "RSAPublicKey";

/** *//**
* 獲取私鑰的key
*/
private static final String PRIVATE_KEY = "RSAPrivateKey";

/** *//**
* RSA最大加密明文大小
*/
private static final int MAX_ENCRYPT_BLOCK = 117;

/** *//**
* RSA最大解密密文大小
*/
private static final int MAX_DECRYPT_BLOCK = 128;

/** *//**
* <p>
* 生成密鑰對(公鑰和私鑰)
* </p>
*
* @return
* @throws Exception
*/
public static Map<String, Object> genKeyPair() throws Exception {
KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
keyPairGen.initialize(1024);
KeyPair keyPair = keyPairGen.generateKeyPair();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
Map<String, Object> keyMap = new HashMap<String, Object>(2);
keyMap.put(PUBLIC_KEY, publicKey);
keyMap.put(PRIVATE_KEY, privateKey);
return keyMap;
}

/** *//**
* <p>
* 用私鑰對信息生成數字簽名
* </p>
*
* @param data 已加密數據
* @param privateKey 私鑰(BASE64編碼)
*
* @return
* @throws Exception
*/
public static String sign(byte[] data, String privateKey) throws Exception {
byte[] keyBytes = Base64Utils.decode(privateKey);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initSign(privateK);
signature.update(data);
return Base64Utils.encode(signature.sign());
}

/**
* <p>
* 校驗數字簽名
* </p>
*
* @param data 已加密數據
* @param publicKey 公鑰(BASE64編碼)
* @param sign 數字簽名
*
* @return
* @throws Exception
*
*/
public static boolean verify(byte[] data, String publicKey, String sign)
throws Exception {
byte[] keyBytes = Base64Utils.decode(publicKey);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
PublicKey publicK = keyFactory.generatePublic(keySpec);
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initVerify(publicK);
signature.update(data);

return signature.verify(Base64Utils.decode(sign));
}

/**
*
* 私鑰解密
*
*
* @param encryptedData 已加密數據
* @param privateKey 私鑰(BASE64編碼)
* @return
* @throws Exception
*/
public static byte[] decryptByPrivateKey(byte[] encryptedData, String privateKey)
throws Exception {
byte[] keyBytes = Base64Utils.decode(privateKey);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, privateK);
int inputLen = encryptedData.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 對數據分段解密
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
} else {
cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_DECRYPT_BLOCK;
}
byte[] decryptedData = out.toByteArray();
out.close();
return decryptedData;
}

/**
*
* 公鑰解密
*
*
* @param encryptedData 已加密數據
* @param publicKey 公鑰(BASE64編碼)
* @return
* @throws Exception
*/
public static byte[] decryptByPublicKey(byte[] encryptedData, String publicKey)
throws Exception {
byte[] keyBytes = Base64Utils.decode(publicKey);
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key publicK = keyFactory.generatePublic(x509KeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, publicK);
int inputLen = encryptedData.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 對數據分段解密
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
} else {
cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_DECRYPT_BLOCK;
}
byte[] decryptedData = out.toByteArray();
out.close();
return decryptedData;
}

/**
*
* 公鑰加密
*
*
* @param data 源數據
* @param publicKey 公鑰(BASE64編碼)
* @return
* @throws Exception
*/
public static byte[] encryptByPublicKey(byte[] data, String publicKey)
throws Exception {
byte[] keyBytes = Base64Utils.decode(publicKey);
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key publicK = keyFactory.generatePublic(x509KeySpec);
// 對數據加密
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, publicK);
int inputLen = data.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 對數據分段加密
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
} else {
cache = cipher.doFinal(data, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_ENCRYPT_BLOCK;
}
byte[] encryptedData = out.toByteArray();
out.close();
return encryptedData;
}

/**
* 私鑰加密
*
*
* @param data 源數據
* @param privateKey 私鑰(BASE64編碼)
* @return
* @throws Exception
*/
public static byte[] encryptByPrivateKey(byte[] data, String privateKey)
throws Exception {
byte[] keyBytes = Base64Utils.decode(privateKey);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key privateK = keyFactory.generatePrivate(pkcs8KeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, privateK);
int inputLen = data.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
int i = 0;
// 對數據分段加密
while (inputLen - offSet > 0) {
if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
} else {
cache = cipher.doFinal(data, offSet, inputLen - offSet);
}
out.write(cache, 0, cache.length);
i++;
offSet = i * MAX_ENCRYPT_BLOCK;
}
byte[] encryptedData = out.toByteArray();
out.close();
return encryptedData;
}

/**
* 獲取私鑰
*
* @param keyMap 密鑰對
* @return
* @throws Exception
*/
public static String getPrivateKey(Map<String, Object> keyMap)
throws Exception {
Key key = (Key) keyMap.get(PRIVATE_KEY);
return Base64Utils.encode(key.getEncoded());
}

/**
*
* 獲取公鑰
*
* @param keyMap 密鑰對
* @return
* @throws Exception
*/
public static String getPublicKey(Map<String, Object> keyMap)
throws Exception {
Key key = (Key) keyMap.get(PUBLIC_KEY);
return Base64Utils.encode(key.getEncoded());
}
/* public static String getMachineCode()
{
Object localObject = null;
if (OSinfo.isWindows()) {
localObject = new hwWindow();
} else if (OSinfo.isLinux()) {
localObject = new hwLinux();
}
String str1 = ((IHadWare)localObject).getCPUSerial();
String str2 = ((IHadWare)localObject).getDriverSerial();
String str3 = ((IHadWare)localObject).getMacSerial();
System.out.println("cpu=" + str1 + " driverserial=" + str2);
String str4 = str1 + str2;
str4 = uMD5.MD5(str4);
return str4;
}*/

/**
* 驗證機器碼
* @param paramString
* @return
* @throws java.text.ParseException
*/
/* public static boolean verifyMachineCode(String paramString)
{
boolean bool = false;
String str = HardWare.getMachineCode();
System.out.println("【本機機器碼】:[" + str + "]");
if (str.equals(paramString)) {
bool = true;
}
return bool;
}*/
public static boolean verifyendTime(Long endtime) throws java.text.ParseException
{
boolean bool = false;
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String str1 = df.format(new Date());
long nowtime = ((Date) df.parseObject(str1)).getTime();
// System.out.println("當前時間:"+nowtime+"授權時間到期時間:" +endtime);
if (nowtime>endtime) {
//System.out.println("【檢驗失敗】授權已過期請重新授權");
return bool;
}
bool = true;
return bool;
}
}
4、RSA加解密 工具包 Base64Utils.java

package com.softetone.wrzs.client.util.license;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

import it.sauronsoftware.base64.Base64;


/** *//**
* <p>
* BASE64編碼解碼工具包
* </p>
* <p>
* 依賴javabase64-1.3.1.jar
* </p>
*
* @author IceWee
* @date 2012-5-19
* @version 1.0
*/
public class Base64Utils {

/** *//**
* 文件讀取緩沖區大小
*/
private static final int CACHE_SIZE = 1024;

/** *//**
* <p>
* BASE64字符串解碼為二進制數據
* </p>
*
* @param base64
* @return
* @throws Exception
*/
public static byte[] decode(String base64) throws Exception {
return Base64.decode(base64.getBytes());
}

/** *//**
* <p>
* 二進制數據編碼為BASE64字符串
* </p>
*
* @param bytes
* @return
* @throws Exception
*/
public static String encode(byte[] bytes) throws Exception {
return new String(Base64.encode(bytes));
}

/** *//**
* <p>
* 將文件編碼為BASE64字符串
* </p>
* <p>
* 大文件慎用,可能會導致內存溢出
* </p>
*
* @param filePath 文件絕對路徑
* @return
* @throws Exception
*/
public static String encodeFile(String filePath) throws Exception {
byte[] bytes = fileToByte(filePath);
return encode(bytes);
}

/** *//**
* <p>
* BASE64字符串轉回文件
* </p>
*
* @param filePath 文件絕對路徑
* @param base64 編碼字符串
* @throws Exception
*/
public static void decodeToFile(String filePath, String base64) throws Exception {
byte[] bytes = decode(base64);
byteArrayToFile(bytes, filePath);
}

/** *//**
* <p>
* 文件轉換為二進制數組
* </p>
*
* @param filePath 文件路徑
* @return
* @throws Exception
*/
public static byte[] fileToByte(String filePath) throws Exception {
byte[] data = new byte[0];
File file = new File(filePath);
if (file.exists()) {
FileInputStream in = new FileInputStream(file);
ByteArrayOutputStream out = new ByteArrayOutputStream(2048);
byte[] cache = new byte[CACHE_SIZE];
int nRead = 0;
while ((nRead = in.read(cache)) != -1) {
out.write(cache, 0, nRead);
out.flush();
}
out.close();
in.close();
data = out.toByteArray();
}
return data;
}

/** *//**
* <p>
* 二進制數據寫文件
* </p>
*
* @param bytes 二進制數據
* @param filePath 文件生成目錄
*/
public static void byteArrayToFile(byte[] bytes, String filePath) throws Exception {
InputStream in = new ByteArrayInputStream(bytes);
File destFile = new File(filePath);
if (!destFile.getParentFile().exists()) {
destFile.getParentFile().mkdirs();
}
destFile.createNewFile();
OutputStream out = new FileOutputStream(destFile);
byte[] cache = new byte[CACHE_SIZE];
int nRead = 0;
while ((nRead = in.read(cache)) != -1) {
out.write(cache, 0, nRead);
out.flush();
}
out.close();
in.close();
}


}
以上就是完整的代碼。如有問題或不理解的請直接回復或者私聊我要源碼。

  

關於網站java license單機授權認證的見解