在给客户公司开发网站往往需要进行一个授权认证机制防止知识产权被侵犯。我就讲讲在最近一个项目中用到的授权机制,一直想整理一下做个总结但都没有一个合适的时间段,今天我就详细说说我怎么实现的欢迎大家指正漏洞哦。
一、背景:单机实现认证过程,也就是通过读取一个文件(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();
}
}
以上就是完整的代码。如有问题或不理解的请直接回复或者私聊我要源码。