加密
加密(英语:Encryption)是将明文信息改變為難以讀取的密文內容,使之不可读的过程。
- 不可逆加密算法
例如:MD4,MD5,HASH, - 可逆加密算法
- 对称加密
DES算法,3DES算法,TDEA算法,Blowfish算法,RC5算法,IDEA算法 - 非对称加密
RSA、Elgamal、背包算法、Rabin、D-H、ECC(椭圆曲线加密算法)。
使用最广泛的是RSA算法,Elgamal是另一种常用的非对称加密算法。
RSA原理
AES原理
- 对称加密
证书链
- 授权
- 生成head
- 生成证书链Message+DN(RSA+SHA:父证书的privateKey)+publicKey(父证书);
- AES加密+BASE64编码;
ROOT证书 check> 中间证书 check> 子证书
- 证书格式
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 licenseContents = new ArrayList(length);
List licenseInfos = new ArrayList(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 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