Posted on 2005-10-24 13:58
在路上... 閱讀(1636)
評論(2) 編輯 收藏 所屬分類:
java軟件研究
最近安裝了一個JIRA,順便研究了一下它的注冊機制,屬于一個典型的DSA簽名算法的實現,按照常理,很自然的想到自己生成一對publickey和privatekey替換掉原來軟件帶的publickey,就可以生成自己的注冊碼了。
但是搞定才發現網上有很多的注冊機,想不到DSA算法的privatekey也有人能夠分析出來??經過驗證,事實就擺在面前了,的確從JIRA 2.6.1開始這對密匙就沒變過,所以注冊機就可以一直沿用到現在了,難道在早期的版本不小心將私匙給泄漏出來了?或者所謂的黑客真的破解了JIRA的密匙?
首先分析一下JIRA的內部機制,與注冊相關的對象都放在com.atlassian.license包下面,其中publickey的文件名是bug.class,在com\atlassian\jira\issue下面,其中WEB-INF\classes和atlassian-extras-0.7.10.jar中各有一個。利用下面代碼就可以讀出publickey的內容了:
InputStream keyfis=new FileInputStream(pubfilename);
byte encKey[] = new byte[keyfis.available()];
keyfis.read(encKey);
keyfis.close();
X509EncodedKeySpec pubKeySpec = new X509EncodedKeySpec(encKey);
KeyFactory keyFactory = KeyFactory.getInstance("DSA");
PublicKey pubkey=keyFactory.generatePublic(pubKeySpec);
DSAPublicKeySpec pubkeyspec=(DSAPublicKeySpec) keyFactory.getKeySpec(pubkey, DSAPublicKeySpec.class);
System.out.println("P="+pubkeyspec.getP());
System.out.println("Q="+pubkeyspec.getQ());
System.out.println("G="+pubkeyspec.getG());
System.out.println("Y="+pubkeyspec.getY());
運行結果如下:
P=178011905478542266528237562450159990145232156369120674273274450314442865788737020770612695252123463079567156784778466449970650770920727857050009668388144034129745221171818506047231150039301079959358067395348717066319802262019714966524135060945913707594956514672855690606794135837542707371727429551343320695239
Q=864205495604807476120572616017955259175325408501
G=174068207532402095185811980123523436538604490794561350978495831040599953488455823147851597408940950725307797094915759492368300574252438761037084473467180148876118103083043754985190983472601550494691329488083395492313850000361646482644608492304078721818959999056496097769368017749273708962006689187956744210730
Y=104878378611578608516131988304241730575226860461304117604293580069983220227094632807881557460560834347944389679413307090500106772833435437017122610074687673247552012771759005247409187709312922876281831426019398155097541955193653855246734321859930303643524786168850036251099739995507172205951987756012523624501

如果有興趣可以從這里入手去找尋privatekey的X,難度可想而知,但是在網上可以下載的注冊機中就有X,不管你是否相信,真讓人懷疑DSA的安全性,值如下:
X=240907294874328356661328650403099424255880489796
這下就可以很方便的生成注冊碼了:
明文:licenseTypeCode ^ dateCreated ^ datePurchased ^ organisation
其中licenseTypeCode =267就是JIRA Enterprise: Commercial Server
dateCreated =datePurchased =new Date()就可以了
organisation隨便
代碼如下:
import com.atlassian.license.LicensePair;

import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.Signature;
import java.security.interfaces.DSAPrivateKey;
import java.security.spec.DSAPrivateKeySpec;
import java.util.Date;


public class JIRAKeyGen
{

public static void main(String[] args)
{
Date dt = new Date();
long d = dt.getTime();
BigInteger x = new BigInteger("240907294874328356661328650403099424255880489796");
BigInteger p = new BigInteger("178011905478542266528237562450159990145232156369120674273274450314442865788737020770612695252123463079567156784778466449970650770920727857050009668388144034129745221171818506047231150039301079959358067395348717066319802262019714966524135060945913707594956514672855690606794135837542707371727429551343320695239");
BigInteger q = new BigInteger("864205495604807476120572616017955259175325408501");
BigInteger g = new BigInteger("174068207532402095185811980123523436538604490794561350978495831040599953488455823147851597408940950725307797094915759492368300574252438761037084473467180148876118103083043754985190983472601550494691329488083395492313850000361646482644608492304078721818959999056496097769368017749273708962006689187956744210730");

try
{
DSAPrivateKeySpec keyspec = new DSAPrivateKeySpec(x, p, q, g);
KeyFactory keyFactory = KeyFactory.getInstance("DSA");
DSAPrivateKey prikey = (DSAPrivateKey) keyFactory.generatePrivate(keyspec);
String messageString = "267^" + d + "^" + d + "^blogjava";
//生成簽名hash
Signature signature = Signature.getInstance("SHA1withDSA");
signature.initSign(prikey);
signature.update(messageString.getBytes());
byte[] lichash = signature.sign();
//編碼
LicensePair pair = new LicensePair(messageString.getBytes(), lichash);
System.out.println(pair.toString());

} catch (Exception ex)
{
ex.printStackTrace();
}
}
}

當然還有另外一種方法,自己生成DSA算法的key,然后覆蓋原來的bug.class,利用與上面相同的辦法就可以生成license了。
示例代碼如下:

public void genDSAKey()
{

try
{
//生成DSA key
KeyPairGenerator gen = KeyPairGenerator.getInstance("DSA");
KeyPair kp = gen.genKeyPair();
DSAPublicKey pubkey = (DSAPublicKey) kp.getPublic();
DSAPrivateKey prikey = (DSAPrivateKey) kp.getPrivate();
saveEncodedData(pubkey.getEncoded(), "bug.class");
saveEncodedData(prikey.getEncoded(), "privatekey.key");
//簽名計算,下次需要直接從文件中讀取privatekey.key,初始化prikey
Signature signature = Signature.getInstance("SHA1withDSA");
signature.initSign(prikey);
Date dt=new Date();
long d = dt.getTime();
String messageString = "267^" + d + "^" + d + "^blogjava";
System.out.println(dt.getTime());
signature.initSign(prikey);
signature.update(messageString.getBytes());
byte[] lichash=signature.sign();
LicensePair pair=new LicensePair(messageString.getBytes(),lichash);
System.out.println(pair.toString());

} catch (Exception ex)
{
ex.printStackTrace();
}
}


public boolean saveEncodedData(byte[] data, String filename)
{
boolean res = true;

try
{
FileOutputStream fs = new FileOutputStream(filename);
fs.write(data);
fs.close();

} catch (Exception ex)
{
res = false;
ex.printStackTrace();
}
return res;
}
注意上面的代碼需要調用atlassian-extras-0.7.10,在WEB-INF\lib目錄下面可以找到