JAVA 从原理到实现,制作license文件,可用于模块授权,程序授权等

License

关于License的概念、用途和好坏处,网上一搜一大堆的,但我讲的这个License,并非是自娱自乐,而是教大家如何做一个符合商用的license。

如何商用?

可以定义一个或者多个唯一的属性,用来标识License使用方,说白了就是标识谁使用了你的平台、软件、模块或者库,这个标识可以是machine也可以是people,一经生成,便不能修改和删除。比如计算机Mac地址、主板序列号和CPU序列号,或者是软件安装序列号、用户UUID,根据这些number,可以确保授权对象唯一,不可复制。
有了上面的保护之后,那就可以赚钱了。比如你可以区分业务类型,其实就是使用范围,不同业务不同套餐费用,或者是实例创建数量和API调用次数,这些都可以是计费标准,还有最常见的就是时间限制,超过有效时间期限,则无法继续使用。

君子爱财取之有道。是时候切入正题了,在写代码之前,需要制作一对秘钥,私钥对授权内容进行签名,公钥给授权方校验License文件是否正确有效。

秘钥制作

在这里,我用的是JDK自带keytool工具制作的。方法如下:
前提:使用CMD命令进入JDK的bin目录下:
在这里插入图片描述

## 1. 生成私匙库
# validity:私钥的有效期多少天
# alias:私钥别称
#keyalg:指定加密算法,默认是DSA
# keystore: 指定私钥库文件的名称(生成在当前目录)
# storepass:指定私钥库的密码(获取keystore信息所需的密码) 
# keypass:指定别名条目的密码(私钥的密码) 
keytool -genkeypair -keysize 1024 -validity 730 -alias "privateKey" -keyalg "RSA" -keystore "D:\KeyStore\privateKey.keystore" -storepass "654321" -keypass "123456" -dname "CN=mine, OU=test, O=test, L=gz, ST=gd, C=CN"
## 2. 生成证书
# alias:私钥别称
# keystore:指定私钥库的名称(在当前目录查找)
# storepass: 指定私钥库的密码
# file:证书名称
keytool -exportcert -alias "privateKey" -keystore "D:\KeyStore\privateKey.keystore" -storepass "654321" -file "D:\KeyStore\publicCer.cer"

到这里,已经创建好了两个文件了。对于License文件的制作和验证,这两个文件是够用的,我在这里顺便生成公匙库,后面验证签名时,可以选择证书或者公钥进行验证。

## 3. 生成公匙库
# alias:公钥别称
# file:证书名称
# keystore:公钥文件名称
# storepass:指定私钥库的密码
keytool -import -alias "publicKey" -file "D:\KeyStore\publicCer.cer" -keystore "D:\KeyStore\publicKey.keystore" -storepass "123456"

运行完之后截图:
在这里插入图片描述生成文件截图:
在这里插入图片描述

制作License文件

  • 首先,要确定License的内容,确定业务种类、业务范围、有效时间或者其他限制性要求。
    我举个简单的栗子:
<?xml version="1.0" encoding="UTF-8"?>
<license vendor="Steven Jon" expiration="2021-04-29" hostId="Win-C498-97D7-262D-55DD" generated="2020-04-29">
    <feature name="INFramework" expiration="2021-04-29"/>
    <signature>MC0CFHyTYkh59tPA50tylcHk6gVX0KtfAhUAhLnBwN1S1Pi8A1js0BG7cnFzkRE=</signature>
</license>

vendor--------------------------------------------license供应商
expiration----------------------------------------license有效期
hostId---------------------------------------------软件安装序列号,以此为标识
generated----------------------------------------license生成时间
在license下面定义需要使用的功能名称
feature name------------------------------------功能名称,区分业务类型和范围
feature expiration------------------------------功能有效期
我只写了INFramework一个feature,可以写多个feature在这里。
signature-----------------------------------------顾名思义,签名 下面内容讲如何生成

  • signature
    从上面可以看出license文件的全部内容,但是我们不必把它所有内容都进行签名,提取关键信息,按照自己的格式连接起来,然后再进行签名,这样安全性是最高的。
    举栗子,按照这种方式进行连接起来:
//格式:vender expiration hostId generated feature name feature expiration sys hostId
//需要注意的是sys hostId,这个是软件实际的安装序列号,签名时跟hostId值一样,但是验证时一定要读取实际的序列号
//示例
Steven Jon2021-04-29Win-C498-97D7-262D-55DD2020-04-29INFramework2021-04-29Win-C498-97D7-262D-55DD

需要获取私钥对上面内容进行签名:

public class KeyConfig {

    private static final String BASE_FILE_PATH = "D:/KeyStore";

    //私钥存放路径
    public static final String PRIVATE_KEY_FILE_PATH = BASE_FILE_PATH + "/privateKey.keystore";
    //公钥存放路径
    public static final String PUBLICKEY_FILE_PATH = BASE_FILE_PATH + "/publicKey.keystore";
    //Cer证书存放路径
    public static final String CER_FILE_PATH = BASE_FILE_PATH + "/publicCer.cer";


    //私钥别名
    public static final String PRIVATE_ALIAS = "privateKey";
    //公钥别名
    public static final String PUBLIC_ALIAS = "publicKey";
    //获取keystore所需的密码
    public static final String KEYSTORE_PASSWORD = "654321";
    //获取私钥所需密码
    public static final String KEY_PASSWORD = "123456";

}

获取私钥工具类:

public class KeyTools
{
    /**
     * 通过keystore获取private key
     *
     */
    public static PrivateKey getPrivateKey() {

        FileInputStream is = null;
        PrivateKey privateKey = null;
        try {
            KeyStore keyStore = KeyStore.getInstance("JKS");
            is = new FileInputStream(new File(KeyConfig.PRIVATE_KEY_FILE_PATH));
            keyStore.load(is, KeyConfig.KEYSTORE_PASSWORD.toCharArray());
            privateKey = (PrivateKey) keyStore.getKey(KeyConfig.PRIVATE_ALIAS, KeyConfig.KEY_PASSWORD.toCharArray());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (is != null) {
                    is.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return privateKey;
    }

}

签名工具类:

public class SignTools
{
    //非对称密钥算法
    private static final String KEY_ALGORITHM = "SHA1withRSA";

    /**
     * 使用私钥进行许可内容签名
     */
    public static byte[] sign(byte[] message, PrivateKey privateKey) throws Exception {
        Signature signature;
        signature = Signature.getInstance(KEY_ALGORITHM);
        signature.initSign(privateKey);
        signature.update(message);
        return Base64.getEncoder().encode(signature.sign());
    }


}

对示例内容进行签名:

//示例签名内容
String signContent = "Steven Jon2021-04-29Win-C498-97D7-262D-55DD2020-04-29INFramework2021-04-29Win-C498-97D7-262D-55DD";
//进行签名
byte[] sign = SignTools.sign(signContent.getBytes(), KeyTools.getPrivateKey());
System.out.println(">>>>>>>>>>>>>>>>>>私钥签名结果 :" + new String(sign));

把new String(sign)结果填入licence文件下的signature标签里,写到这里,license文件制作完成。

看到这里,是不是觉得so easy,自己完全可以写一个license生成器,这样生成license文件就会很轻松了,一键到位。

验证License文件

验证license是否有效,需要用到证书文件,或者公钥,用cer证书最后也是为了获取公钥的,至于用哪个,看自己的咯,可以把这个文件发给客户,也可以放到服务器上,只要能找到就可以了。
举个栗子,发cer证书给客户,让客户把证书安装在指定位置。
获取公钥工具类:

public class KeyTools
{
  
    /**
     * 通过 cer证书获取公钥
     */
    public static PublicKey getPublicKeyFromCer(){
        PublicKey publicKey = null;
        FileInputStream in = null;
        try {
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            in = new FileInputStream(KeyConfig.CER_FILE_PATH);
            Certificate c = cf.generateCertificate(in);
            publicKey = c.getPublicKey();

        } catch (CertificateException | FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            try {
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return publicKey;
    }

}

验证签名工具类:

public class VerifyTools
{
    //非对称密钥算法
    private static final String KEY_ALGORITHM = "SHA1withRSA";

    /**
     * 验签
     */
    public static boolean verify(byte[] message, byte[] signMessage, PublicKey publicKey) throws Exception {
        Signature signature;
        signature = Signature.getInstance(KEY_ALGORITHM);
        signature.initVerify(publicKey);
        signature.update(message);
        return signature.verify(Base64.getDecoder().decode(signMessage));
    }
}

解析License文件,将里面的关键信息提取出来,按照签名之前的格连接起来。
这一步我就不详细写了,大概过程就是解析xml,难倒是不难,感觉会有点繁琐的,毕竟需要提取的信息比较多。

//偷个懒直接拿上面的
String message = "Steven Jon2021-04-29Win-C498-97D7-262D-55DD2020-04-29INFramework2021-04-29Win-C498-97D7-262D-55DD"; 
boolean verify = VerifyTools.verify(message.getBytes(), sign, KeyTools.getPublicKeyFromCer());
System.out.println(">>>>>>>>>>>>>>>>>>验证结果 verify =" + verify);

好了,文章写完了,非常感谢你能看到最后,如果觉得有帮助,麻烦点个赞哦!

  • 46
    点赞
  • 177
    收藏
    觉得还不错? 一键收藏
  • 26
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 26
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值