使用truelicense实现用于JAVA工程license机制(包括license生成和验证)

来源:互联网 发布:spaceman软件 编辑:程序博客网 时间:2024/05/22 11:48

开发的软件产品在交付使用的时候,往往会授权一段时间的试用期,这个时候license就派上用场了。不同于在代码中直接加上时间约束,需要重新授权的时候使用license可以避免修改源码,改动部署,授权方直接生成一个新的license发送给使用方替换掉原来的license文件即可。下面将讲述使用truelicense来实现license的生成和使用。Truelicense是一个开源的证书管理引擎,详细介绍见https://truelicense.java.net/

一、首先介绍下license授权机制的原理:

1、  生成密钥对,方法有很多。

2、  授权者保留私钥,使用私钥对包含授权信息(如使用截止日期,MAC地址等)的license进行数字签名。

3、  公钥给使用者(放在验证的代码中使用),用于验证license是否符合使用条件。

 

接下来是本例制作license的具体步骤:

二、第一步:使用keytool生成密钥对

以下命令在dos命令行执行,注意当前执行目录,最后生成的密钥对即在该目录下:

1、首先要用KeyTool工具来生成私匙库:(-alias别名 –validity 3650表示10年有效)

keytool -genkey -alias privatekey -keystoreprivateKeys.store -validity 3650

2、然后把私匙库内的公匙导出到一个文件当中:

keytool -export -alias privatekey -file certfile.cer -keystore privateKeys.store

3、然后再把这个证书文件导入到公匙库:

keytool -import -alias publiccert -file certfile.cer -keystore publicCerts.store

最后生成文件privateKeys.store、publicCerts.store拷贝出来备用。

三、第二步:生成证书(该部分代码由授权者独立保管执行)

1、  首先LicenseManagerHolder.java类:

[java] view plain copy
  1. package cn.melina.license;  
  2. import de.schlichtherle.license.LicenseManager;  
  3. import de.schlichtherle.license.LicenseParam;  
  4.   
  5. /** 
  6.  * LicenseManager������ 
  7.  * @author melina 
  8.  */  
  9. public class LicenseManagerHolder {  
  10.       
  11.     private static LicenseManager licenseManager;  
  12.    
  13.     public static synchronized LicenseManager getLicenseManager(LicenseParam licenseParams) {  
  14.         if (licenseManager == null) {  
  15.             licenseManager = new LicenseManager(licenseParams);  
  16.         }  
  17.         return licenseManager;  
  18.     }  
  19. }  

2、  然后是主要生成license的代码CreateLicense.java:

[java] view plain copy
  1. package cn.melina.license;  
  2.   
  3. import java.io.File;  
  4. import java.io.IOException;  
  5. import java.io.InputStream;  
  6. import java.text.DateFormat;  
  7. import java.text.ParseException;  
  8. import java.text.SimpleDateFormat;  
  9. import java.util.Properties;  
  10. import java.util.prefs.Preferences;  
  11. import javax.security.auth.x500.X500Principal;  
  12. import de.schlichtherle.license.CipherParam;  
  13. import de.schlichtherle.license.DefaultCipherParam;  
  14. import de.schlichtherle.license.DefaultKeyStoreParam;  
  15. import de.schlichtherle.license.DefaultLicenseParam;  
  16. import de.schlichtherle.license.KeyStoreParam;  
  17. import de.schlichtherle.license.LicenseContent;  
  18. import de.schlichtherle.license.LicenseParam;  
  19. import de.schlichtherle.license.LicenseManager;  
  20.   
  21. /** 
  22.  * CreateLicense 
  23.  * @author melina 
  24.  */  
  25. public class CreateLicense {  
  26.     //common param  
  27.     private static String PRIVATEALIAS = "";  
  28.     private static String KEYPWD = "";  
  29.     private static String STOREPWD = "";  
  30.     private static String SUBJECT = "";  
  31.     private static String licPath = "";  
  32.     private static String priPath = "";  
  33.     //license content  
  34.     private static String issuedTime = "";  
  35.     private static String notBefore = "";  
  36.     private static String notAfter = "";  
  37.     private static String consumerType = "";  
  38.     private static int consumerAmount = 0;  
  39.     private static String info = "";  
  40.     // 为了方便直接用的API里的例子  
  41.     // X500Princal是一个证书文件的固有格式,详见API  
  42.     private final static X500Principal DEFAULTHOLDERANDISSUER = new X500Principal(  
  43.             "CN=Duke、OU=JavaSoft、O=Sun Microsystems、C=US");  
  44.       
  45.     public void setParam(String propertiesPath) {  
  46.         // 获取参数  
  47.         Properties prop = new Properties();  
  48.         InputStream in = getClass().getResourceAsStream(propertiesPath);  
  49.         try {  
  50.             prop.load(in);  
  51.         } catch (IOException e) {  
  52.             // TODO Auto-generated catch block  
  53.             e.printStackTrace();  
  54.         }  
  55.         PRIVATEALIAS = prop.getProperty("PRIVATEALIAS");  
  56.         KEYPWD = prop.getProperty("KEYPWD");  
  57.         STOREPWD = prop.getProperty("STOREPWD");  
  58.         SUBJECT = prop.getProperty("SUBJECT");  
  59.         KEYPWD = prop.getProperty("KEYPWD");  
  60.         licPath = prop.getProperty("licPath");  
  61.         priPath = prop.getProperty("priPath");  
  62.         //license content  
  63.         issuedTime = prop.getProperty("issuedTime");  
  64.         notBefore = prop.getProperty("notBefore");  
  65.         notAfter = prop.getProperty("notAfter");  
  66.         consumerType = prop.getProperty("consumerType");  
  67.         consumerAmount = Integer.valueOf(prop.getProperty("consumerAmount"));  
  68.         info = prop.getProperty("info");  
  69.           
  70.     }  
  71.   
  72.     public boolean create() {         
  73.         try {  
  74.             /************** 证书发布者端执行 ******************/  
  75.             LicenseManager licenseManager = LicenseManagerHolder  
  76.                     .getLicenseManager(initLicenseParams0());  
  77.             licenseManager.store((createLicenseContent()), new File(licPath));    
  78.         } catch (Exception e) {  
  79.             e.printStackTrace();  
  80.             System.out.println("客户端证书生成失败!");  
  81.             return false;  
  82.         }  
  83.         System.out.println("服务器端生成证书成功!");  
  84.         return true;  
  85.     }  
  86.   
  87.     // 返回生成证书时需要的参数  
  88.     private static LicenseParam initLicenseParams0() {  
  89.         Preferences preference = Preferences  
  90.                 .userNodeForPackage(CreateLicense.class);  
  91.         // 设置对证书内容加密的对称密码  
  92.         CipherParam cipherParam = new DefaultCipherParam(STOREPWD);  
  93.         // 参数1,2从哪个Class.getResource()获得密钥库;参数3密钥库的别名;参数4密钥库存储密码;参数5密钥库密码  
  94.         KeyStoreParam privateStoreParam = new DefaultKeyStoreParam(  
  95.                 CreateLicense.class, priPath, PRIVATEALIAS, STOREPWD, KEYPWD);  
  96.         LicenseParam licenseParams = new DefaultLicenseParam(SUBJECT,  
  97.                 preference, privateStoreParam, cipherParam);  
  98.         return licenseParams;  
  99.     }  
  100.   
  101.     // 从外部表单拿到证书的内容  
  102.         public final static LicenseContent createLicenseContent() {  
  103.             DateFormat format = new SimpleDateFormat("yyyy-MM-dd");  
  104.             LicenseContent content = null;  
  105.             content = new LicenseContent();  
  106.             content.setSubject(SUBJECT);  
  107.             content.setHolder(DEFAULTHOLDERANDISSUER);  
  108.             content.setIssuer(DEFAULTHOLDERANDISSUER);  
  109.             try {  
  110.                 content.setIssued(format.parse(issuedTime));  
  111.                 content.setNotBefore(format.parse(notBefore));  
  112.                 content.setNotAfter(format.parse(notAfter));  
  113.             } catch (ParseException e) {  
  114.                 // TODO Auto-generated catch block  
  115.                 e.printStackTrace();  
  116.             }  
  117.             content.setConsumerType(consumerType);  
  118.             content.setConsumerAmount(consumerAmount);  
  119.             content.setInfo(info);  
  120.             // 扩展  
  121.             content.setExtra(new Object());  
  122.             return content;  
  123.         }  
  124. }  

3、  测试程序licenseCreateTest.java:

[java] view plain copy
  1. package cn.melina.license;  
  2. import cn.melina.license.CreateLicense;  
  3. public class licenseCreateTest {  
  4.     public static void main(String[] args){  
  5.         CreateLicense cLicense = new CreateLicense();  
  6.         //获取参数  
  7.         cLicense.setParam("./param.properties");  
  8.         //生成证书  
  9.         cLicense.create();  
  10.     }  
  11. }  

4、  生成时使用到的param.properties文件如下:

[java] view plain copy
  1. ##########common parameters###########  
  2. #alias  
  3. PRIVATEALIAS=privatekey  
  4. #key(该密码生成密钥对的密码,需要妥善保管,不能让使用者知道)  
  5. KEYPWD=bigdata123456  
  6. #STOREPWD(该密码是在使用keytool生成密钥对时设置的密钥库的访问密码)  
  7. STOREPWD=abc123456  
  8. #SUBJECT  
  9. SUBJECT=bigdata  
  10. #licPath  
  11. licPath=bigdata.lic  
  12. #priPath  
  13. priPath=privateKeys.store  
  14. ##########license content###########  
  15. #issuedTime  
  16. issuedTime=2014-04-01  
  17. #notBeforeTime  
  18. notBefore=2014-04-01  
  19. #notAfterTime  
  20. notAfter=2014-05-01  
  21. #consumerType  
  22. consumerType=user  
  23. #ConsumerAmount  
  24. consumerAmount=1  
  25. #info  
  26. info=this is a license  

根据properties文件可以看出,这里只简单设置了使用时间的限制,当然可以自定义添加更多限制。该文件中表示授权者拥有私钥,并且知道生成密钥对的密码。并且设置license的内容。

四、第三步:验证证书(使用证书)(该部分代码结合需要授权的程序使用)

1、  首先LicenseManagerHolder.java类,同上。

2、  然后是主要验证license的代码VerifyLicense.java:

[java] view plain copy
  1. package cn.melina.license;  
  2.   
  3. import java.io.File;  
  4. import java.io.IOException;  
  5. import java.io.InputStream;  
  6. import java.util.Properties;  
  7. import java.util.prefs.Preferences;  
  8.   
  9. import de.schlichtherle.license.CipherParam;  
  10. import de.schlichtherle.license.DefaultCipherParam;  
  11. import de.schlichtherle.license.DefaultKeyStoreParam;  
  12. import de.schlichtherle.license.DefaultLicenseParam;  
  13. import de.schlichtherle.license.KeyStoreParam;  
  14. import de.schlichtherle.license.LicenseParam;  
  15. import de.schlichtherle.license.LicenseManager;  
  16.   
  17. /** 
  18.  * VerifyLicense 
  19.  * @author melina 
  20.  */  
  21. public class VerifyLicense {  
  22.     //common param  
  23.     private static String PUBLICALIAS = "";  
  24.     private static String STOREPWD = "";  
  25.     private static String SUBJECT = "";  
  26.     private static String licPath = "";  
  27.     private static String pubPath = "";  
  28.       
  29.     public void setParam(String propertiesPath) {  
  30.         // 获取参数  
  31.         Properties prop = new Properties();  
  32.         InputStream in = getClass().getResourceAsStream(propertiesPath);  
  33.         try {  
  34.             prop.load(in);  
  35.         } catch (IOException e) {  
  36.             // TODO Auto-generated catch block  
  37.             e.printStackTrace();  
  38.         }  
  39.         PUBLICALIAS = prop.getProperty("PUBLICALIAS");  
  40.         STOREPWD = prop.getProperty("STOREPWD");  
  41.         SUBJECT = prop.getProperty("SUBJECT");  
  42.         licPath = prop.getProperty("licPath");  
  43.         pubPath = prop.getProperty("pubPath");  
  44.     }  
  45.   
  46.     public boolean verify() {         
  47.         /************** 证书使用者端执行 ******************/  
  48.   
  49.         LicenseManager licenseManager = LicenseManagerHolder  
  50.                 .getLicenseManager(initLicenseParams());  
  51.         // 安装证书  
  52.         try {  
  53.             licenseManager.install(new File(licPath));  
  54.             System.out.println("客户端安装证书成功!");  
  55.         } catch (Exception e) {  
  56.             e.printStackTrace();  
  57.             System.out.println("客户端证书安装失败!");  
  58.             return false;  
  59.         }  
  60.         // 验证证书  
  61.         try {  
  62.             licenseManager.verify();  
  63.             System.out.println("客户端验证证书成功!");  
  64.         } catch (Exception e) {  
  65.             e.printStackTrace();  
  66.             System.out.println("客户端证书验证失效!");  
  67.             return false;  
  68.         }  
  69.         return true;  
  70.     }  
  71.   
  72.     // 返回验证证书需要的参数  
  73.     private static LicenseParam initLicenseParams() {  
  74.         Preferences preference = Preferences  
  75.                 .userNodeForPackage(VerifyLicense.class);  
  76.         CipherParam cipherParam = new DefaultCipherParam(STOREPWD);  
  77.   
  78.         KeyStoreParam privateStoreParam = new DefaultKeyStoreParam(  
  79.                 VerifyLicense.class, pubPath, PUBLICALIAS, STOREPWD, null);  
  80.         LicenseParam licenseParams = new DefaultLicenseParam(SUBJECT,  
  81.                 preference, privateStoreParam, cipherParam);  
  82.         return licenseParams;  
  83.     }  
  84. }  

3、  测试程序licenseVerifyTest.java:

[java] view plain copy
  1. package cn.melina.license;  
  2.   
  3. public class licenseVerifyTest {  
  4.     public static void main(String[] args){  
  5.         VerifyLicense vLicense = new VerifyLicense();  
  6.         //获取参数  
  7.         vLicense.setParam("./param.properties");  
  8.         //验证证书  
  9.         vLicense.verify();  
  10.     }  
  11. }  

4、  验证时使用到的Properties文件如下:

[java] view plain copy
  1. ##########common parameters###########  
  2. #alias  
  3. PUBLICALIAS=publiccert  
  4. #STOREPWD(该密码是在使用keytool生成密钥对时设置的密钥库的访问密码)  
  5. STOREPWD=abc123456  
  6. #SUBJECT  
  7. SUBJECT=bigdata  
  8. #licPath  
  9. licPath=bigdata.lic  
  10. #pubPath  
  11. pubPath=publicCerts.store  

根据该验证的properties可以看出,使用者只拥有公钥,没有私钥,并且也只知道访问密钥库的密码,而不能知道生成密钥对的密码。


原文地址http://blog.csdn.net/luckymelina/article/details/22870665

阅读全文
0 0