最近在网上找到一个邮件系统,需要使用授权文件才能使用,所以想练习一下。网站上介绍是采用spring框架的,但是我不知道什么是spring,这不是春天的意思吗?!! 而且还有这么多人学这玩意儿,搞不懂。
任务开始:
step 1: 定位授权检测位置 WEB-INF/class 目录中包含了 该系统的类文件。
定位到 com.laszalsystem.license.LicenseLoader 类 发现该类中包含了 spring 结构中的资源定位的 Resource类 同时在 WEB-INF/lib 目录中发现了 com.laszalsystem.license.License 等类
仔细研究了一下 License、LicenseUtil、EncryptionUtil等类 发现了license的原始格式:就是Java当中支持的属性文件,其中包括各种字段(companyName,contactEmail,userLimit,productCode,licenseType)等等,同时授权文件使用LicenseUtil来校验和编码
最为重要的是 laszal mail 使用了 非对称算法 文件中包含 laszal的公钥文件,通过公钥文件对授权文件进行解码并验证,如果签名验证成功 在获取License对象的信息
step 2: 怎样才能破解经过非对称算法保护的软件呢? 嘿嘿 替换公钥文件
生成自己的密钥对 KeyPair , 输出私钥、公钥文件,那么如果替换了原有的公钥文件,那我就可以用自己的私钥来签名License的输出,同时就可以生成完美的授权文件了。
step 3: License 对象 到 授权文件的 过程
License对象 就是一个 Properties 类 文件就是属性文件 , 获取属性文件的 byte[], 使用自身的私钥将byte[]加密,生成BASE64 b1 同时将byte[] 的签名生成 BASE64 b2 将 这两个 String 用 #连接
其中充分应用到 laszal Mail 系统中的类 com.laszalsystem.license 包中的类。
具体的源代码 以及 解释
License类封装
import java.io.*;
import java.util.*;
import java.security.*;
import java.security.spec.*;
import sun.misc.*;
import com.laszlosystems.license.*;
public class LicenseGen
{
/**
* 以下是License要用到的属性
*
*/
private static final String COMPANY_NAME = "companyName";
private static final String EMAIL_ADDRESS = "contactEmail";
private static final String EXPIRATION_DATE = "expirationDate";
public static final String USER_LIMIT = "userLimit";
public static final String PRODUCT_CODE = "productCode";
public static final String LICENSE_TYPE = "licenseType";
private static KeyPair keys;
private BASE64Encoder be;
private BASE64Decoder bd;
private License genLicense;
public LicenseGen()
{
genLicense = new License();
genLicense.setProperty("productCode","lzmail"); // 默认信息
genLicense.setProperty("licenseType","Purchase"); // 默认信息
genLicense.setProperty("userLimit","65535"); // 用户最大限制
keys = null;
}
public void setCompanyName(String cpName)
{
genLicense.setCompanyName(cpName);
}
public String getCompanyName()
{
return genLicense.getCompanyName();
}
public void setContactEmail(String email)
{
genLicense.setEmailAddress(email);
}
public String getContactEmail()
{
return genLicense.getEmailAddress();
}
public void setExpirationDate(Date date) // setExpirationDate(null) 没有过期限制
{
genLicense.setExpirationDate(date);
}
public Date getExpirationDate()
{
return genLicense.getExpirationDate();
}
public boolean isExpired()
{
return genLicense.isExpired();
}
public void write(OutputStream out) throws IOException // 输出原始属性
{
byte [] buf = genLicense.toByteArray();
out.write(buf,0,buf.length);
}
public void read(InputStream in) throws Exception
{
byte [] buf = new byte[in.available()];
in.read(buf);
genLicense = new License(buf);
}
public KeyPair genKeyPair() // 生成 KeyPair
{
keys = EncryptionUtil.generateKeyPair();
return keys;
}
public void writePublicKey(OutputStream out) throws IOException // 输出公钥文件
{
PublicKey pk = keys.getPublic();
byte buf[] = pk.getEncoded();
be = new BASE64Encoder();
String pkstr = be.encode(buf);
buf = pkstr.getBytes();
out.write(buf, 0, buf.length);
}
public void writePublicKey(OutputStream out, PublicKey pk) throws IOException // 输出指定的公钥文件
{
byte buf[] = pk.getEncoded();
be = new BASE64Encoder();
String pkstr = be.encode(buf);
buf = pkstr.getBytes();
out.write(buf, 0, buf.length);
}
public void writePrivateKey(OutputStream out) throws IOException // 输出私钥文件
{
PrivateKey pk = keys.getPrivate();
byte buf[] = pk.getEncoded();
be = new BASE64Encoder();
String pkstr = be.encode(buf);
buf = pkstr.getBytes();
out.write(buf, 0, buf.length);
}
public void writePrivateKey(OutputStream out, PrivateKey pk) throws IOException
{
byte buf[] = pk.getEncoded();
be = new BASE64Encoder();
String pkstr = be.encode(buf);
buf = pkstr.getBytes();
out.write(buf, 0, buf.length);
}
public PublicKey readPublicKey(InputStream in) throws Exception // 获取公钥文件
{
byte[] buf = new byte[in.available()];
in.read(buf);
in.close();
String tmp = new String(buf,"US-ASCII");
bd = new BASE64Decoder();
buf = bd.decodeBuffer(tmp);
PublicKey pk = EncryptionUtil.loadPublicKey(buf);
return pk;
}
public PrivateKey readPrivateKey(InputStream in) throws Exception // 获取私钥文件
{
byte[] buf = new byte[in.available()];
in.read(buf);
in.close();
String tmp = new String(buf,"US-ASCII");
bd = new BASE64Decoder();
buf = bd.decodeBuffer(tmp);
PrivateKey pk = EncryptionUtil.loadPrivateKey(buf);
return pk;
}
public void genLicenseFile(OutputStream out) throws Exception // 生成授权文件
{
String data = LicenseUtil.signAndEncode(genLicense,keys.getPrivate()); // 使用私钥签名并加密
byte [] buf = data.getBytes();
out.write(buf);
}
}
LicenseUtil类 // 验证工具类
package com.laszlosystems.license;
import java.security.*;
public class LicenseUtil
{
private static final String SIGNATURE_DELIMITER = "#";
private LicenseUtil()
{
}
public static String signAndEncode(License license, PrivateKey privatekey) // 将License对象用私钥签名加密
throws InvalidKeyException
{
byte abyte0[] = license.toByteArray();
byte abyte1[] = EncryptionUtil.sign(abyte0, privatekey);
String s = Base64.encodeBytes(abyte0, 8);
String s1 = Base64.encodeBytes(abyte1, 8);
return s + "#" + s1;
}
public static License decodeAndVerifySignature(String s, PublicKey publickey) // 使用公钥解密并验证
throws InvalidKeyException, LicenseException
{
String as[];
as = s.trim().split("#");
if(as.length != 2)
throw new LicenseException("malformed license key");
byte abyte0[];
abyte0 = Base64.decode(as[0]);
byte abyte1[] = Base64.decode(as[1]);
if(!EncryptionUtil.isValidSignature(abyte0, abyte1, publickey))
throw new LicenseException("invalid license signature");
return new License(abyte0);
IllegalArgumentException illegalargumentexception;
illegalargumentexception;
throw new LicenseException("invalid license");
}
}
最终:生成授权文件的代码:
import java.io.*;
import java.util.*;
import java.security.*;
import com.laszlosystems.license.*;
public class Gen
{
public static void main(String args[]) throws Exception
{
FileOutputStream fout1 = new FileOutputStream("laszlomail_license");
FileOutputStream fout2 = new FileOutputStream("laszlosystems_public.key");
LicenseGen lg = new LicenseGen();
lg.setCompanyName("FiveRats");
lg.setContactEmail("vhly@163.com");
lg.setExpirationDate(null);
lg.genKeyPair();
lg.writePublicKey(fout2);
lg.genLicenseFile(fout1);
fout2.close();
fout1.close();
lg = null;
fout1 = null;
fout2 = null;
System.gc();
}
}
2006/04/13