javaEE防盗版-License开发
开发的软件产品在交付使用的时候,往往会授权一段时间的试用期,这个时候license就派上用场了。不同于在代码中直接加上时间约束,需要重新授权的时候使用license可以避免修改源码,改动部署,授权方直接生成一个新的license发送给使用方替换掉原来的license文件即可。下面将讲述使用truelicense来实现license的生成和使用。Truelicense是一个开源的证书管理引擎,详细介绍见https://truelicense.java.net/
license于加密技术一起使用效果更好。
接下来介绍一下license授权机制的原理:
1、生成密钥对,方法有很多。
2、授权者保留私钥,使用私钥对包含授权信息(如使用截止日期,MAC地址等)的license进行数字签名。
3、公钥给使用者(放在验证的代码中使用),用于验证license是否符合使用条件。
1、首先要用KeyTool工具来生成私匙库:(-alias别名 –validity 3650表示10年有效)
keytool -genkey -alias privatekey -keystore privateKeys.store -validity 3650

这里口令使用了noryar123

这里的口令是:noryar456
这个时候,会在打开命令行的地方创建出一个文件,privateKeys.store
2、然后把私匙库内的证书导出到一个文件当中:
keytool -export -alias privatekey -file certfile.cer -keystore privateKeys.store

口令:noryar123
3、然后再把这个证书文件导入到公匙库:
keytool -import -alias publiccert -file certfile.cer -keystore publicCerts.store

这里的口令,用了:noryar123
最后生成文件privateKeys.store、publicCerts.store拷贝出来备用。
文件位置在用户目录下
C:UsersAdministrator
从上面我们可以看到,密钥一共有两种:1. 密钥库,这个需要配置到服务器中。2. 密钥,这个需要保护好,是创建私钥的时候用的
licenseMakeConf.properties
测试方法
认证核心方法
测试
以上就是license开发的常规手段。对于web项目来说,只需要提供license认证模块的开发即可。对于开发者来说,可以将license生成单独开发一个小程序。以后就可以通过这个程序来给不同的企业生成license。
1、生成密钥对,方法有很多。
2、授权者保留私钥,使用私钥对包含授权信息(如使用截止日期,MAC地址等)的license进行数字签名。
3、公钥给使用者(放在验证的代码中使用),用于验证license是否符合使用条件。
1. 生成密钥对
以下命令在dos命令行执行,注意当前执行目录,最后生成的密钥对即在该目录下:1、首先要用KeyTool工具来生成私匙库:(-alias别名 –validity 3650表示10年有效)
keytool -genkey -alias privatekey -keystore privateKeys.store -validity 3650
这里口令使用了noryar123
这里的口令是:noryar456
这个时候,会在打开命令行的地方创建出一个文件,privateKeys.store
2、然后把私匙库内的证书导出到一个文件当中:
keytool -export -alias privatekey -file certfile.cer -keystore privateKeys.store
口令:noryar123
3、然后再把这个证书文件导入到公匙库:
keytool -import -alias publiccert -file certfile.cer -keystore publicCerts.store
这里的口令,用了:noryar123
最后生成文件privateKeys.store、publicCerts.store拷贝出来备用。
文件位置在用户目录下
C:UsersAdministrator
从上面我们可以看到,密钥一共有两种:1. 密钥库,这个需要配置到服务器中。2. 密钥,这个需要保护好,是创建私钥的时候用的
2. Maven
<!-- https://mvnrepository.com/artifact/de.schlichtherle.truelicense/truelicense-core --> <dependency> <groupId>de.schlichtherle.truelicense</groupId> <artifactId>truelicense-core</artifactId> <version>1.33</version> </dependency> <!-- https://mvnrepository.com/artifact/de.schlichtherle.truelicense/truelicense-xml --> <dependency> <groupId>de.schlichtherle.truelicense</groupId> <artifactId>truelicense-xml</artifactId> <version>1.33</version> </dependency> <!-- https://mvnrepository.com/artifact/commons-codec/commons-codec --> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.10</version> </dependency> <!-- https://mvnrepository.com/artifact/de.schlichtherle.truelicense/truelicense-swing --> <dependency> <groupId>de.schlichtherle.truelicense</groupId> <artifactId>truelicense-swing</artifactId> <version>1.33</version> </dependency>
3. 生成证书 (该部分代码由授权者独立保管执行)
package com.noryar.license; import de.schlichtherle.license.LicenseManager; import de.schlichtherle.license.LicenseParam; /** * 单例模式下的证书管理器 * @author Leon Lee. */ public class LicenseManagerHolder { private static LicenseManager licenseManager; private LicenseManagerHolder(){} public static synchronized LicenseManager getLicenseManager(LicenseParam param) { if(licenseManager==null) { licenseManager=new LicenseManager(param); } return licenseManager; } }
package com.noryar.license; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Properties; import java.util.prefs.Preferences; import javax.security.auth.x500.X500Principal; import de.schlichtherle.license.CipherParam; import de.schlichtherle.license.DefaultCipherParam; import de.schlichtherle.license.DefaultKeyStoreParam; import de.schlichtherle.license.DefaultLicenseParam; import de.schlichtherle.license.KeyStoreParam; import de.schlichtherle.license.LicenseContent; import de.schlichtherle.license.LicenseManager; import de.schlichtherle.license.LicenseParam; /** * 生成证书 * @author Leon Lee. */ public class LicenseMake { private String licPath; private String issued ; private String notBefore ; private String notAfter ; private String consumerType; private int consumerAmount ; private String info ; /** * 私钥的别名 */ private String priAlias ; /** * 该密码生成密钥对的密码 */ private String privateKeyPwd ; /** * 使用keytool生成密钥对时设置的密钥库的访问密码 */ private String keyStorePwd ; private String subject ; private String priPath ; // X500Princal是一个证书文件的固有格式,详见API private final static X500Principal DEFAULTHOLDERANDISSUER = new X500Principal("CN=noryar, OU=noryar, O=noryar, L=china, ST=dalian, C=china"); public LicenseMake(){} public LicenseMake(String confPath) { initParam(confPath); } /** * 读取属性文件 * @param propertiesPath 属性文件路径 */ public void initParam(String confPath) { // 获取参数 Properties prop = new Properties(); InputStream in = getClass().getResourceAsStream(confPath); try { prop.load(in); } catch (IOException e) { e.printStackTrace(); } //common param priAlias = prop.getProperty("private.key.alias"); privateKeyPwd = prop.getProperty("private.key.pwd"); keyStorePwd= prop.getProperty("key.store.pwd"); subject = prop.getProperty("subject"); priPath = prop.getProperty("priPath"); licPath = prop.getProperty("licPath"); // license content issued = prop.getProperty("issuedTime"); notBefore = prop.getProperty("notBefore"); notAfter = prop.getProperty("notAfter"); consumerType = prop.getProperty("consumerType"); consumerAmount = Integer.valueOf(prop.getProperty("consumerAmount")); info = prop.getProperty("info"); } /** * 初始化证书的相关参数 * @return */ private LicenseParam initLicenseParams() { Class<LicenseMake> clazz=LicenseMake.class; Preferences pre = Preferences.userNodeForPackage(clazz); // 设置对证书内容加密的对称密码 CipherParam cipherParam = new DefaultCipherParam(keyStorePwd); // 参数1,2从哪个Class.getResource()获得密钥库; //参数3密钥库的别名; //参数4密钥库存储密码; //参数5密钥库密码 KeyStoreParam privateStoreParam = new DefaultKeyStoreParam(clazz, priPath, priAlias, keyStorePwd, privateKeyPwd); // 返回生成证书时需要的参数 LicenseParam licenseParam = new DefaultLicenseParam(subject,pre, privateStoreParam, cipherParam); return licenseParam; } /** * 通过外部配置文件构建证书的的相关信息 * @return * @throws ParseException */ public LicenseContent buildLicenseContent() throws ParseException { LicenseContent content=new LicenseContent(); SimpleDateFormat formate=new SimpleDateFormat("yyyy-MM-dd"); content.setConsumerAmount(consumerAmount); content.setConsumerType(consumerType); content.setHolder(DEFAULTHOLDERANDISSUER); content.setIssuer(DEFAULTHOLDERANDISSUER); content.setIssued(formate.parse(issued)); content.setNotBefore(formate.parse(notBefore)); content.setNotAfter(formate.parse(notAfter)); content.setInfo(info); content.setExtra(new Object()); return content; } /** * 生成证书,在证书发布者端执行 * @throws Exception */ public void create() throws Exception { LicenseManager licenseManager=LicenseManagerHolder.getLicenseManager(initLicenseParams()); LicenseContent content=buildLicenseContent(); licenseManager.store(content, new File(licPath)); System.out.println("证书发布成功"); } }
licenseMakeConf.properties
##########common parameters########### #私钥的别名 private.key.alias=privatekey #privateKeyPwd(该密码生成密钥对的密码,需要妥善保管,不能让使用者知道) private.key.pwd=noryar456 #keyStorePwd(该密码是在使用keytool生成密钥对时设置的密钥库的访问密码) key.store.pwd=noryar123 #项目的唯一识别码 subject=noryar #生成证书的地址 licPath=license.lic #密钥库的地址 priPath=privateKeys.store ##########license content########### #发布日期 issuedTime=2016-07-25 #有效开始日期 notBefore=2016-07-25 #有效截止日期 notAfter=2016-08-30 #consumerType consumerType=user #ConsumerAmount consumerAmount=1 #info info=this is a license
测试方法
public static void main(String[] args) throws Exception { LicenseMake clicense=new LicenseMake("/licenseMakeConf.properties"); clicense.create(); }以上就可以创建出一个license文件了。然后开发者将license文件传递给购买方。购买方在系统中上传该文件进行验证即可。
4. 验证证书
package com.noryar.license; import de.schlichtherle.license.LicenseManager; import de.schlichtherle.license.LicenseParam; /** * 单例模式下的证书管理器 * @author Leon Lee */ public class LicenseManagerHolder { private static LicenseManager licenseManager; private LicenseManagerHolder(){} public static synchronized LicenseManager getLicenseManager(LicenseParam param) { if(licenseManager==null) { licenseManager=new LicenseManager(param); } return licenseManager; } }
认证核心方法
package com.noryar.license; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.Properties; import java.util.prefs.Preferences; import de.schlichtherle.license.CipherParam; import de.schlichtherle.license.DefaultCipherParam; import de.schlichtherle.license.DefaultKeyStoreParam; import de.schlichtherle.license.DefaultLicenseParam; import de.schlichtherle.license.KeyStoreParam; import de.schlichtherle.license.LicenseContentException; import de.schlichtherle.license.LicenseManager; import de.schlichtherle.license.LicenseParam; public class LicenseVertify { /** * 公钥别名 */ private String pubAlias; /** * 该密码是在使用keytool生成密钥对时设置的密钥库的访问密码 */ private String keyStorePwd; /** * 系统的统一识别码 */ private String onlykey; /** * 证书路径 */ private String licName; /** * 公钥库路径 */ private String pubPath; private String confPath="/licenseVertifyConf.properties"; public LicenseVertify(String onlykey) { setConf(confPath,onlykey); } public LicenseVertify(String confPath,String onlykey) { setConf(confPath,onlykey); } /** * 通过外部配置文件获取配置信息 * @param confPath 配置文件路径 * @param onlykey 系统的统一识别码 */ public void setConf(String confPath,String onlykey) { // 获取参数 Properties prop = new Properties(); InputStream in = getClass().getResourceAsStream(confPath); try { prop.load(in); } catch (IOException e) { e.printStackTrace(); } this.onlykey=onlykey; pubAlias = prop.getProperty("public.alias"); keyStorePwd = prop.getProperty("key.store.pwd"); licName = prop.getProperty("license.name"); pubPath = prop.getProperty("public.store.path"); } /** * 初始化证书的相关参数 * @param 系统的统一识别码 * @return */ private LicenseParam initLicenseParams() { Class<LicenseVertify> clazz=LicenseVertify.class; Preferences pre=Preferences.userNodeForPackage(clazz); CipherParam cipherParam=new DefaultCipherParam(storePwd); KeyStoreParam pubStoreParam=new DefaultKeyStoreParam(clazz, pubPath, pubAlias, keyStorePwd, null); LicenseParam licenseParam=new DefaultLicenseParam(onlykey, pre, pubStoreParam, cipherParam); return licenseParam; } private LicenseManager getLicenseManager() { return LicenseManagerHolder.getLicenseManager(initLicenseParams()); } /** * 安装证书证书 * @param 存放证书的路径 * @return */ public void install(String licdir) { try { LicenseManager licenseManager=getLicenseManager(); licenseManager.install(new File(licdir+File.separator+licName)); System.out.println("安装证书成功!"); } catch (Exception e) { System.out.println("安装证书失败!"); e.printStackTrace(); System.exit(0); } } /** * 验证证书的合法性 * @return 0、合法,1、证书过期,2、证书错误 */ public int vertify() { try { LicenseManager licenseManager=getLicenseManager(); licenseManager.verify(); System.out.println("验证证书成功!"); return 0; } catch(LicenseContentException ex) { System.out.println("证书已经过期!"); ex.printStackTrace(); return 1; } catch (Exception e) { System.out.println("验证证书失败!"); e.printStackTrace(); return 2; } } }
测试
public static void main(String[] args) throws Exception { LicenseVertify vlicense=new LicenseVertify("noryar"); // 项目唯一识别码,对应生成配置文件的subject vlicense.install(System.getProperty("user.dir")); vlicense.vertify(); }licenseVertifyConf.properties
##########common parameters########### #公钥别名 public.alias=publiccert #使用keytool生成密钥对时设置的密钥库的访问密码 key.store.pwd= noryar123 #证书路径 license.name=license.lic #公共库路径 public.store.path=publicCerts.store
以上就是license开发的常规手段。对于web项目来说,只需要提供license认证模块的开发即可。对于开发者来说,可以将license生成单独开发一个小程序。以后就可以通过这个程序来给不同的企业生成license。
此外,为了更好的保护代码。license认证模块可以进行混淆加密,解密部分使用C语言来编写,同时针对不同的平台进行编译。增强破解难度。
声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。
- 上一篇: 求两个字符串的交集
- 下一篇: Ruby解析Windows PE文件