美文网首页
证书链设计

证书链设计

作者: NullBugs | 来源:发表于2018-09-03 11:52 被阅读0次

    加密

    加密(英语:Encryption)是将明文信息改變為難以讀取的密文內容,使之不可读的过程。

    • 不可逆加密算法
        例如:MD4,MD5,HASH,
    • 可逆加密算法
      • 对称加密
          DES算法,3DES算法,TDEA算法,Blowfish算法,RC5算法,IDEA算法
      • 非对称加密
          RSA、Elgamal、背包算法、Rabin、D-H、ECC(椭圆曲线加密算法)。
          使用最广泛的是RSA算法,Elgamal是另一种常用的非对称加密算法。
        RSA原理
        AES原理

    证书链

    20180530103403964.png
    • 授权
      • 生成head
      • 生成证书链Message+DN(RSA+SHA:父证书的privateKey)+publicKey(父证书);
      • AES加密+BASE64编码;

    ROOT证书 check> 中间证书 check> 子证书

    图片1.png
    • 证书格式
      input
      {
        "company": "CompanyNameHere",
        "company_id": CompanyIDHere,
        "type": "redistribute || leaf",
        "product": "ProductNameIncludedInPorductList",
        "model_secret": true,
        "capability": {
          "track": true
        },
        "limit": {
          "uuid": "test_uuid",
          "expiration": [20160501, 20160630],
          "appid": ["com.example.app1", "com.test.*"],
          "cores": 4,
          "_hardware_auth": "athsa204a",
          "_hardware_auth_key": "YWQwYWE0NWVhM2Y5MDNkOWM4ZDQxN2U4NmRmMDU1MzE="
        },
        "counter": {
          "threads": 4
        }
      }
    

    output

    ############################################################
    #  YinLib License
    #  License Product : ProductNameIncludedInPorductList
    #  Expiration : 20160501 ~ 20160630
    #  License SN : 63f09206-1c46-4247-8788-ba9b16bb1994
    ############################################################
    GWfTA0kPlx4+THgLJKZByzgtewJg2AML0Drr33qTzZkTTeuB0K3n6jVVITsY
    ocJxd2w45pIX9GVdbHXl/aaeidWWDLcXAYsig05k34PbxarmdJvLJYUTHjk0
    EN3r+L6sgutdl974QSX+qHqD60fTNu6F801evs9DXBAs2dWphwG0AxJ9IJIi
    npE2nFXJBSfSJ3T7nS157hjF59Y/6xd/1GbGlFZe5onSIZZKvaV3oxHFL6kf
    J6a/1mrHnghQwb4D9csXoEK5ky+3lIsMNGKpZeZanEMm/GUN5fDjuZ6TWj6B
    FjECjIRtHgFvIaj6+FLskoQgFeuPhMCiAuYqm20e/8UJ8Ay51RMsQ/fgLEI3
    v/FAbK6i1B+hKgUk6z8C1XkPeEtF439EF1W+ubj0Z/IOKzyCk87Hcp4GXODD
    2N/tlVLjBZ6qhI1jxwbcYYu6HKEM1VpxVJawZgA4YkyNU9LmsKkLLuiKniJz
    g1OuqNLkVpgkGiSnpSoZFXTk9OQW7ZXP6mLZA7/HiivILEraP1Wfk4CCayCF
    oxxTZpzeQNA5CXWVp4yXNtJdXo2qeX/9AyfQ3PHWdKdYD1aXTldV0tGixOGc
    6ayGpbfy6nuZSIFSrko4BEH/VDqMy2orGhyfUMUmfeXa+TnyIi3iFx8yuP2B
    1z0U1x/yILc26FePSzdZLWaZLCgBldl9N5nfKvUFrAxHiOK3rtMryokCuS0j
    DcKWyPGxiOy5ePFkhrlpDXycngVNF8QhZxy22OLe4VYwWnByGqiChg89t2Gh
    x7gWMd+Z9GDmwrnHQ9q/hT8Awo7L1nPNKxY4+xXVq/rg+4ASFeWiXhw0/Q3D
    gSluEQy8kmmarnRrgEc1QzZ+lp9Tiemnt64q9u1qSWjqJ1moies/3ynqZA68
    7vo0YxGNmKfUW4vQaHfi05AcMtHI2D7c8L8Hnl0=
    ------------------------------------------------------------
    GWfTA0kPlx4+THgLJKZBy9BEimQkYd4jMzDHUnA2hOgCEOSPfmWLlpp7n4eY
    5ED5eYLHOB6SXNf+LFyK1GnCgU1bSCzYVA1LRkOmdfGiLvu+iXsTsci8mKea
    fsyR9IhbVBhQWqLrBi53QHXIQ9WmF+6F801evs9DXBAs2dWphwG0AxJ9IJIi
    npE2nFXJBSfSMZQVOv0nFLV2J4GU5nlAqsebocwKBpJPMlf1FICvADg0imwG
    yoTQHuMLaPDWD9kNxl/y8hREC9oUQODmE1yAxl7cPQUpsrCyGcrvDqX/RwYD
    R0yqZQLHZrtkqhM1HZ4bmAd6c3ve7Rj/u+/FAl5/LSNvl3vzzUzmAqjytlM3
    Gr6BFjECjIRtHgFvIaj6+FLsKSHZE9iSLPXRjcD15LSy44FsbiA9Vg459tKj
    YeuyKbbbyq3KvDrGAlMQ0l361YG+puCliofN0P/j13AoElrPYjU4YGp5lXYm
    Pn1zYqcAXWMGEVK7iSg4+F4aNqVc5lAcVx8oehIc3zUBsRV6L4fLgtjAWdZB
    LNqMn1t0QyQTad44bKZL6m0kYhfhiLJoI9NHQhCDnotyhcV1ELtQtX3hwd+C
    3T/HQz8ECurhKA1nvA7TIq8ToKfUUdqspLXDJ+Tk6j4TaZKjqFMrwCNX1tgt
    ers05ckKPEX36BSVVCPTkjirVuwkBRp4bLe2Sy4V+NjA8I+jkBOfv9qQkH6w
    nYW5C6pkOvPNgZRzMYWk+eDNGG1BB+5ngXxe8u21KhjjUZOdUzXQlA9Gt00O
    oF9shltdl3RR1j/Ub9wso23AxuBW4I+zetETUARucq0RJTqWBCuwELfqQM/6
    sGmNA5yhj/ggMPG8uJ5kp5nZXz1sx2QvmKK2LIEhYHEMya0/9ml8tmF1RKsK
    8lvpzKcSvNIKOlu0EoHn2XGyrGvLDwzHv1ttffN0akqSCvcpl/5vDHCRhA6T
    h0u63ELA4QYExYWVNwFY3xXcLfMQfh1BVUbQm3SZIWY=
    ############################################################
    

    code AES+RSA加密生成License:

    public static final String encrypt(String content, String privateKey, String publicKey, String aesKey) throws Exception{
            if(!StringUtils.isNotEmpty(content) || !StringUtils.isNotEmpty(privateKey) || !StringUtils.isNotEmpty(publicKey) || !StringUtils.isNotEmpty(aesKey)){
                return null;
            }
            content = StringUtils.replaceBlank(content);
            String rsaContent = encrypt(content, privateKey, publicKey);
            System.out.println("encrypt rsa content : " + rsaContent.length());
            String encryptContent = AES.encryptToBase64(rsaContent, aesKey);
            System.out.println("encrypt aes content : " + encryptContent);
            return encryptContent;
        }
        
        public static final String encrypt(String content, String privateKey, String publicKey) throws Exception{
            if(!StringUtils.isNotEmpty(content) || !StringUtils.isNotEmpty(privateKey) || !StringUtils.isNotEmpty(publicKey)){
                return null;
            }
            String rsaData = RSA.sign(content, privateKey);
            LicenseContent licenseContent = new LicenseContent();
            licenseContent.setMessage(content);
            licenseContent.setPublicKey(publicKey);
            licenseContent.setMessageDigest(rsaData);
            String objectStr = StringUtils.replaceBlank(sGson.toJson(licenseContent));
            System.out.println("encrypt rsa content : " + objectStr);
            return objectStr;
        }
    

    Format

        public static String generateLicense() {
            GenerateService.generateRootKeyPare();
            GenerateService.generateSubKeyPare();
            String rootContent = FileUtils.read("root.lic");
            String rootLic = generateRootLicense(rootContent);
            String subContent = FileUtils.read("sub.lic");
            String subLic = generateSubLicense(subContent);
            String head = generateHead(subContent);
            String content = head + StringUtils.formatContent(rootLic) + StringUtils.contentSplit() + StringUtils.formatContent(subLic) + StringUtils.headSplit();
            System.out.println("License format : \n" + content);
            return content;
        }
    
    • 验证
      • 解析
      • 验证签名
      • 验证权限

    解析:License解析
    AES:

        public static String decryptFromBase64(String data, String key){
            try {
                byte[] originalData = Base64.decode(data.getBytes());
                byte[] valueByte = decrypt(originalData, key.getBytes(ConfigureEncryptAndDecrypt.CHAR_ENCODING));
                return new String(valueByte, ConfigureEncryptAndDecrypt.CHAR_ENCODING);
            } catch (UnsupportedEncodingException e) {
                throw new RuntimeException("decrypt fail!", e);
            }
        }
    

    解析后的内容:数据+数据签名+publicKey

    {
        "messageDigest":"N4JeSlY1uaBlFggO96O6OdLmkekkAs0QTClSbb4fEvcs7cQiTw7vHctmGsyMvz1laLx7hXRPEdUB2b9oeZJilQ\u003d\u003d",
        "message":"{\"company\":\"yinlib\",\"company_id\":10001,\"type\":\"redistribute\",\"product\":\"rsatest\",\"model_secret\":false,\"capability\":{\"track\":true},\"limit\":{\"uuid\":\"test_uuid\",\"expiration\":[20160501,20160630],\"appid\":[\"com.example.app1\",\"com.test.*\"],\"cores\":4,\"_hardware_auth\":\"athsa204a\",\"_hardware_auth_key\":\"YWQwYWE0NWVhM2Y5MDNkOWM4ZDQxN2U4NmRmMDU1MzE\u003d\"},\"counter\":{\"threads\":4}}",
        "publicKey":"MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIH+jdyjYL7wBeea08YRYky5mV4mSlVx6rIfMECyeb9JE4lUaPBza3p1sq4oFUp01Ke4ei+XKJRIR7rjD6PrfWUCAwEAAQ\u003d\u003d"
    }
    
    {
        "messageDigest":"TnLSOAzv+UVFxw+7htXiBToQlw3SLj7PnBSwY2Y0SWW8Kl9ITg94gsQ1LXBok5JWEAkhdpH0fQGrI/AYdyR97g\u003d\u003d",
        "message":"{\"company\":\"CompanyNameHere\",\"company_id\":CompanyIDHere,\"type\":\"redistribute||leaf\",\"product\":\"ProductNameIncludedInPorductList\",\"model_secret\":true,\"capability\":{\"track\":true},\"limit\":{\"uuid\":\"test_uuid\",\"expiration\":[20160501,20160630],\"appid\":[\"com.example.app1\",\"com.test.*\"],\"cores\":4,\"_hardware_auth\":\"athsa204a\",\"_hardware_auth_key\":\"YWQwYWE0NWVhM2Y5MDNkOWM4ZDQxN2U4NmRmMDU1MzE\u003d\"},\"counter\":{\"threads\":4}}",
        "publicKey":"MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAIH+jdyjYL7wBeea08YRYky5mV4mSlVx6rIfMECyeb9JE4lUaPBza3p1sq4oFUp01Ke4ei+XKJRIR7rjD6PrfWUCAwEAAQ\u003d\u003d"
    }
    
    

    验证签名:验证License是本人签发,没有被篡改

        private static boolean checkLicenseChain(String[] licenseChain) {
            if(licenseChain == null || licenseChain.length == 0){
                return false;
            }
            int length = licenseChain.length;
            List<LicenseContent> licenseContents = new ArrayList<LicenseContent>(length); 
            List<LicenseInfo> licenseInfos = new ArrayList<LicenseInfo>(length); 
            for(int i = 0; i < length; i++){
                String content = AES.decryptFromBase64(licenseChain[i], AESKEY);
                LicenseContent licenseContent = sGson.fromJson(content, LicenseContent.class);
                System.out.println(content);
                if(licenseContent == null){
                    return false;
                }
                licenseContents.add(licenseContent);
                boolean isSignCheckPass = RSA.checkSign(licenseContent.getMessage(), licenseContent.getMessageDigest(), licenseContent.getPublicKey());
                if(!isSignCheckPass){
                    return false;
                }
                LicenseInfo licenseInfo = sGson.fromJson(licenseContent.getMessage(), LicenseInfo.class);
                if(licenseInfo == null){
                    return false;
                }
                licenseInfos.add(licenseInfo);
                System.out.println("[" + i + "] : " + isSignCheckPass);
            }
            boolean status = checkLicenseChainPermission(licenseInfos);
            return status;
        }
    

    验证权限:验证License的权限

        private static boolean checkLicenseChainPermission(
                List<LicenseInfo> licenseInfos) {
            //check head time / product
            //check child license time/appid/count and so on permission
            return true;
        }
    

    缺陷

    • AES Key是固定的,容易泄露;
    • AES Key泄露后容易被伪造;

    改进策略

    • AES Key随机,并由父证书的PrivateKey加密,Root的publicKey隐藏(不公开),解析时,由root publickey开始逐级解析出AES Key和publickey;
    • AES Key随机秘钥 + 内容的MD5或者其他hash值,重新生成秘钥,验证是验证新秘钥是否包含内容的MD5或者Hash值;
    • 建立父子证书依赖关系,互相验证关系;

    证书链设计Code:GitHub

    相关文章

      网友评论

          本文标题:证书链设计

          本文链接:https://www.haomeiwen.com/subject/qtlbwftx.html