/* ================================================================== * Created [2009-4-27 下午11:32:55] by Jon.King * ================================================================== * TSS * ================================================================== * mailTo:jinpujun@hotmail.com * Copyright (c) Jon.King, 2009-2012 * ================================================================== */ package com.jinhe.tss.core.common.license; import java.io.File; import java.security.KeyFactory; import java.security.Signature; import java.security.spec.X509EncodedKeySpec; import java.util.ArrayList; import java.util.Date; import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import com.jinhe.tss.core.util.FileHelper; import com.jinhe.tss.core.util.EasyUtils; /** * <p> LicenseManager.java </p> * * 1、应用程序可以创建以及验证绑定给用户、系统等实体的license。 * 2、licenses可以是永久性的或者临时性的(在某个特定时期内有效) * 3、共享应用程序可以配置试用期licenses * 4、licenses的验证由JAVA Security API提供的数字签名机制来实现。通过生成公钥/私钥对来分别对licenses进行签名和校验。 * 5、license安装模块需要用特殊机制对其进行保护,以防被反编译轻易破解。可以使用java代码编译混淆器、自定义类装载器来实现。 * */ public final class LicenseManager { private final Log log = LogFactory.getLog(getClass()); private static LicenseManager instance = new LicenseManager(); private LicenseManager(){ } public static synchronized LicenseManager getInstance() { return instance; } private List<License> licenses; public void loadLicenses() { if(licenses != null) return; licenses = new ArrayList<License>(); String files[] = new File(LicenseFactory.LICENSE_DIR).list(); for(int i = 0; i < files.length; i++){ String filename = files[i]; File file = new File(LicenseFactory.LICENSE_DIR, filename); if(file.isDirectory() || !filename.startsWith("cpu") || !filename.endsWith(".license")) continue; try { License license = License.fromConfigFile(filename); Date expiresDate = license.getExpiresDate(); if(expiresDate != null && expiresDate.getTime() < System.currentTimeMillis()) { log.error("license文件 \"" + file.getName() + "\" 已经过期."); continue; } if(!validate(license)) { log.error("license文件 \"" + file.getName() + "\" 不合法."); continue; } licenses.add(license); } catch(Exception e) { log.error(e); } } if(licenses.isEmpty()){ log.error("找不到合法的许可文件(license)."); } return; } /** * 重新载入licenses */ public void reloadLicenses() { if(licenses != null) licenses.clear(); licenses = null; loadLicenses(); } /** * 验证产品和版本号是否和license中信息匹配 * @param product * @param version * @return */ public boolean validateLicense(String product, String version) { loadLicenses(); if(!licenses.isEmpty()) { int needsVersion = Integer.parseInt(version.substring(0, 1)); for(int i = 0; i < licenses.size(); i++) { License license = (License)licenses.get(i); int hasVersion = Integer.parseInt(license.getVersion().substring(0, 1)); if(license.getProduct().equals(product) && hasVersion >= needsVersion) return true; } } return false; } /** * 获取license的类型。 * * @param product * @param version * @return */ public String getLicenseType(String product, String version) { loadLicenses(); if(!licenses.isEmpty()) { int needsVersion = Integer.parseInt(version.substring(0, 1)); for(int i = 0; i < licenses.size(); i++) { License license = (License)licenses.get(i); int hasVersion = Integer.parseInt(license.getVersion().substring(0, 1)); if(license.getProduct().equals(product) && hasVersion >= needsVersion) return license.getLicenseType().name; } } return null; } /** * 验证license是否合法。 * 首先验证Mac地址是否有改变,有的话则非法。(防止用户自由拷贝软件)。 * 然后根据公钥验证签名是否合法。 * * @param license * @return * @throws Exception */ boolean validate(License license) throws Exception { String macAddress = license.getMacAddress(); if(macAddress != null && macAddress.length() > 0) { String curMacAddress = MacAddressUtil.getMacAddress(); if(!macAddress.equals(curMacAddress)) return false; } String publicKey = FileHelper.readFile(new File(LicenseFactory.PUBLIC_KEY_FILE)).trim(); X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(EasyUtils.decodeHex(publicKey)); KeyFactory keyFactory = KeyFactory.getInstance("DSA"); java.security.PublicKey pubKey = keyFactory.generatePublic(pubKeySpec); Signature sig = Signature.getInstance("DSA"); sig.initVerify(pubKey); sig.update(license.getFingerprint()); return sig.verify(EasyUtils.decodeHex(license.getLicenseSignature())); } }