我的評論
re: Sun的Web Service開源實現--Metro 牛 david.turing 2008-12-27 09:17
我是BEA的工程師,WebLogic現在是雙棧運行,目前JAX-WS是基于Metro的,base JAXB的。
re: 將Spring用于高并發環境的隱憂 david.turing 2008-06-14 09:49
典型的部署期泄露,這種有可能是Spring的Bug,它可能沒有正確實現J2EE的context銷毀接口。
re: 將Spring用于高并發環境的隱憂[未登錄] david.turing 2008-04-24 13:05
1.5的concurrent hashmap產生的用途就是為了hashmap同步
re: 將Spring用于高并發環境的隱憂 david.turing 2008-04-23 11:01
邢總說對了,佩服。不過,廠家的支持會讓Spring更適用于商業化。未來的WebLogic版本(Essex),應該對Spring有較大的優化,包括:
1, 基于Spring的部署方式實現本地WLS部署,我們可以將Spring Module實現weblogic.application.Module接口,即可讓Spring模塊享受WebLogic的2階段部署的特性。
2, 一些預配置的Beans能夠無需Spring配置聲明即可注入到Spring應用中,applicationContext看上去會簡潔很多
3, 為Beans提供scope,比如ClusteringScope,以便支持集群技術
4, WebLogic Consle展示Spring應用的RuntimeMBeans
5, 9.2之后WLDF可以用于上面的RuntimeMBeans,可以定期抓取Runtime信息了
6, Spring應用默認支持OpenJPA作為持久層支持,當然,KODO、Hibernate切換也是簡單的
1, 基于Spring的部署方式實現本地WLS部署,我們可以將Spring Module實現weblogic.application.Module接口,即可讓Spring模塊享受WebLogic的2階段部署的特性。
2, 一些預配置的Beans能夠無需Spring配置聲明即可注入到Spring應用中,applicationContext看上去會簡潔很多
3, 為Beans提供scope,比如ClusteringScope,以便支持集群技術
4, WebLogic Consle展示Spring應用的RuntimeMBeans
5, 9.2之后WLDF可以用于上面的RuntimeMBeans,可以定期抓取Runtime信息了
6, Spring應用默認支持OpenJPA作為持久層支持,當然,KODO、Hibernate切換也是簡單的
re: 將Spring用于高并發環境的隱憂 david.turing 2008-04-22 10:16
說的沒錯,任何優秀的產品都會有Bug,但除非用的場景足夠多和復雜,否則某些嚴重的Bug還是會隱藏的很深。
re: Java讀取BMP文件 david.turing 2007-11-07 17:52
我暈,沒有publish到blog的文章也能google到?
re: RSA使用簡述 david.turing 2007-11-04 09:46
如果你使用了SHA1并對散列值進行RSA簽名、加密,則Padding的過程無需你本人去干預。
或者你可以看看下面的代碼(RSAUtils.java):
package org.dev2dev.security.crypto.Asymmetric;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.math.BigInteger;
import java.security.SecureRandom;
import org.bouncycastle.crypto.AsymmetricBlockCipher;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.encodings.OAEPEncoding;
import org.bouncycastle.crypto.encodings.PKCS1Encoding;
import org.bouncycastle.crypto.engines.DESEngine;
import org.bouncycastle.crypto.engines.RSAEngine;
import org.bouncycastle.crypto.generators.RSAKeyPairGenerator;
import org.bouncycastle.crypto.params.RSAKeyGenerationParameters;
import org.bouncycastle.crypto.params.RSAKeyParameters;
import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
import org.bouncycastle.util.encoders.Hex;
import org.dev2dev.security.crypto.blockcipher.BlockCipherTool;
/**
* RSA工具類
* @author david.turing
* @copyright GuangZhou BEA Usergroup
* @version 0.7
* @modifyTime 22:30:34
*/
public class RSAUtils {
int keylength=1024;
int certainty=20;
RSAKeyGenerationParameters keyparam;
AsymmetricBlockCipher eng = null;
RSAKeyPairGenerator pGen = null;
AsymmetricCipherKeyPair pair = null;
public RSAUtils()
{
}
public String getName()
{
return "RSA";
}
/**
* 設置RSA的密鑰長度
* @param rsakeylength
*/
public void setKeyLength(int rsakeylength)
{
if(rsakeylength==512||rsakeylength==768||rsakeylength==1024||rsakeylength==2048)
keylength=rsakeylength;
}
/**
* 設置RSA Key Pair的素數產生經度,該數值越大,理論產生的RSA Key安全性越高
* @param certaintyofprime
*/
public void setCertaintyOfPrime(int certaintyofprime)
{
certainty=certaintyofprime;
}
/**
* 生成RSA Keypair,如果你不是通過ImportPublicKey和ImportPrivateKey
* 來導入密鑰對,則可通過此方法隨機生成。
*
* @return RSAKeyGenerationParameters
*/
public void initRSAKeyPair()
{
/**
* 注意, 第一個參數被寫死了,它是publicExponent, 即e
* e通常選3,17,65537
* X.509建議使用65537
* PEM建議使用3
* PKCS#1建議使用3或65537
* 在本算法中,它使用了3,即0x3
*/
RSAKeyGenerationParameters rsaparam=
new RSAKeyGenerationParameters(BigInteger.valueOf(0x3),
new SecureRandom(), this.keylength, this.certainty);
this.keyparam = rsaparam;
//RSA Keypair的生成依賴于rsaparam
RSAKeyPairGenerator pGen = new RSAKeyPairGenerator();
pGen.init(keyparam);
pair = pGen.generateKeyPair();
pair.getPublic();
}
/**
* 設置RSA密鑰對,此方法用于從外部文件導入RSA密鑰對
* @see ImportPublicKey(String)
* @see ImportPrivateKey(String)
* @param pubparam 公鑰
* @param privparam 私鑰
*/
public void setRSAKeyPair(RSAKeyParameters pubparam, RSAPrivateCrtKeyParameters privparam)
{
AsymmetricCipherKeyPair newpair=new AsymmetricCipherKeyPair(pubparam,privparam);
pair=newpair;
}
/**
* 該函數返回公鑰
* @return
*/
public RSAKeyParameters getPublicKey()
{
return (RSAKeyParameters)pair.getPublic();
}
/**
* 該函數返回私鑰
* 注意,RSAPrivateCrtKeyParameters其實繼承了RSAKeyParameters
* @see getPublicKey()
* @return
*/
public RSAPrivateCrtKeyParameters getPrivateKey()
{
return (RSAPrivateCrtKeyParameters)pair.getPrivate();
}
/**
* RSA的padding模式,安全性依次遞增
* mode=1 RAW RSA 安全性最差
* mode=2 PKCS1
* mode=3 OAEP
* @param mode
*/
public void setRSAMode(int mode)
{
eng = new RSAEngine(); //默認就是RAW模式, 安全性問題,已不再使用
if (mode==2)
eng = new PKCS1Encoding(eng);
else
eng = new OAEPEncoding(eng); //mode==3
}
/**
* 該RSAEngine的每次處理輸入數據,以Block為單位,是32Bytes
* 因此,本函數的輸入要嚴格控制在32Byte,即256bit數據
* 超出該長度會拋出異常。
* 本函數要求輸入必須為16進制字符0-F。
*
* @see Decrypt(String input)
* @param input
* @return
*/
public String encrypt(String input)
{
byte[] inputdata=Hex.decode(input);
//用公鑰加密
eng.init(true, pair.getPublic());
System.out.println(">>>加密參數");
System.out.println(">>>明文字節數:"+inputdata.length);
System.out.println(">>>RSA Engine Input Block Size="+this.eng.getInputBlockSize());
System.out.println(">>>RSA Engine Output Block Size="+this.eng.getOutputBlockSize());
try
{
inputdata = eng.processBlock(inputdata, 0, inputdata.length);
}
catch (Exception e)
{
e.printStackTrace();
}
return new String(Hex.encode(inputdata));
}
/**
* 該函數輸入為字節,并規定其長度為32字節
* 超出該長度會拋出異常
* @see Decrypt(byte[] inputdata)
* @param inputdata
* @return
*/
public byte[] encrypt(byte[] inputdata)
{
byte[] outputdata=null;
//用公鑰加密
eng.init(true, pair.getPublic());
try
{
inputdata = eng.processBlock(inputdata, 0, inputdata.length);
outputdata=new byte[eng.getOutputBlockSize()];
outputdata=inputdata;
}
catch (Exception e)
{
e.printStackTrace();
}
return outputdata;
}
/**
* 加密ByteArrayInputStream流,在該方法中,會對input做分段處理,每段都將會
* 以inBlockSize來劃分明文,密文同樣會設置換行,因此,將來在加密過程中,密文
* 需要分行讀入,在明文、密文,唯一對應的是inBlock和outBlock,它們是換行對應的。
*
* 本函數已經處理結尾Block問題
* @param input
* @param Key
* @return
*/
public byte[] encryptPro(byte[] inputload)
{
ByteArrayInputStream inputstream=new ByteArrayInputStream(inputload);
ByteArrayOutputStream outputstream=new ByteArrayOutputStream();
//用公鑰加密
eng.init(true, pair.getPublic());
int inBlockSize =this.eng.getInputBlockSize() ;
int outBlockSize = this.eng.getOutputBlockSize();
try {
System.out.println("加密的 InBlockSize="+inBlockSize);
System.out.println("加密的outBlockSize="+outBlockSize);
encryptPro(inputstream, outputstream);
} catch (DataLengthException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch(Exception e){
e.printStackTrace();
}
byte[] outputload=outputstream.toByteArray();
System.out.println("###[1]明文大?。?quot;+inputload.length);
System.out.println("###[1]密文大?。?quot;+outputload.length);
return outputload;
}
/**
* 加密BufferedInputStream流,在該方法中,會對input做分段處理,每段都將會
* 以inBlockSize來劃分明文,密文同樣會設置換行,因此,將來在加密過程中,密文
* 需要分行讀入,在明文、密文,唯一對應的是inBlock和outBlock,它們是換行對應的。
*
*此函數未處理padding,如果你不想自己調整padding,請用encryptPro
*@see encryptPro(BufferedInputStream inputstream,BufferedOutputStream outputstream)
*
* @param input
* @param Key
* @return
*/
public void encrypt(BufferedInputStream inputstream,BufferedOutputStream outputstream)
{
//用公鑰加密
eng.init(true, pair.getPublic());
int inBlockSize =this.eng.getInputBlockSize() ;
int outBlockSize = this.eng.getOutputBlockSize();
byte[] inblock = new byte[inBlockSize];
byte[] outblock = new byte[outBlockSize];
byte[] rv = null;
try {
while (inputstream.read(inblock, 0, inBlockSize) > 0)
{
outblock = eng.processBlock(inblock, 0, inBlockSize);
rv = Hex.encode(outblock, 0, outBlockSize);
outputstream.write(rv, 0, rv.length);
outputstream.write('\n');
}
} catch (DataLengthException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch(Exception e){
e.printStackTrace();
}
}
/**
* 加密BufferedInputStream流,在該方法中,會對input做分段處理,每段都將會
* 以inBlockSize來劃分明文,密文同樣會設置換行,因此,將來在加密過程中,密文
* 需要分行讀入,在明文、密文,唯一對應的是inBlock和outBlock,它們是換行對應的。
*
* 該函數會在加密文件的頭部注明padding_size
* padding_size即padding_size即明文流按照inBlockSize劃分后
* 最后一個block的未占滿的大?。ㄗ止潝担?
*
* @param input
* @param Key
* @return
*/
public void encryptPro(InputStream inputstream,OutputStream outputstream)
{
//用公鑰加密
eng.init(true, pair.getPublic());
int inBlockSize =this.eng.getInputBlockSize() ;
int outBlockSize = this.eng.getOutputBlockSize();
byte[] inblock = new byte[inBlockSize];
byte[] outblock = new byte[outBlockSize];
byte[] rv = null;
try {
//System.out.println("stream length="+inputstream.available());
int padding_size=inBlockSize-(inputstream.available() % inBlockSize);
//System.out.println("padding_size="+padding_size);
/*寫入padding_size,處理最后一個Block不夠inBlockSize的情況
* 記住不要自己修改inBlockSize,因為RSA共有三種模式,每種模式
* 對Padding的處理方式都不一樣,所以,不要修改對processBlock
* 的加密解密方式??傊?,不要修改RSA的inBlock!
*/
outputstream.write((padding_size+"").getBytes());
outputstream.write('\n');
while (inputstream.read(inblock, 0, inBlockSize) > 0)
{
outblock = eng.processBlock(inblock, 0, inBlockSize);
rv = Hex.encode(outblock, 0, outBlockSize);
//System.out.println("Hex len="+rv.length);
outputstream.write(rv, 0, rv.length);
outputstream.write('\n');
}
} catch (DataLengthException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch(Exception e){
e.printStackTrace();
}
}
/**
* 解密字符串
* @param input
* @return
*/
public String decrypt(String input)
{
byte[] inputdata=Hex.decode(input);
eng.init(false,pair.getPrivate());
System.out.println(">>>加密參數");
System.out.println(">>>RSA Engine Input Block Size="+this.eng.getInputBlockSize());
System.out.println(">>>RSA Engine Output Block Size="+this.eng.getOutputBlockSize());
try
{
inputdata=eng.processBlock(inputdata,0,inputdata.length);
}
catch(Exception e)
{
e.printStackTrace();
}
return new String(Hex.encode(inputdata));
}
/**
* 解密字節數組
* @param inputdata
* @return
*/
public byte[] decrypt(byte[] inputdata)
{
byte[] outputdata=null;
//用公鑰加密
eng.init(false, pair.getPrivate());
try
{
inputdata = eng.processBlock(inputdata, 0, inputdata.length);
outputdata=new byte[eng.getOutputBlockSize()];
outputdata=inputdata;
}
catch (Exception e)
{
e.printStackTrace();
}
return outputdata;
}
/**
* 解密流
*
* 本函數已經處理結尾Block問題
* @see encryptPro(byte[] inputload)
*
* @param inputstream 被加密過的流
* @param outputstream 解密輸出的流
*/
public byte[] decryptPro(byte[] inputload)
{
ByteArrayInputStream inputstream=new ByteArrayInputStream(inputload);
ByteArrayOutputStream outputstream=new ByteArrayOutputStream();
//設置引擎
eng.init(false, pair.getPrivate());
int inBlockSize =this.eng.getInputBlockSize() ;
int outBlockSize = this.eng.getOutputBlockSize();
try {
System.out.println("解密的In BlockSize="+inBlockSize);
System.out.println("解密的out BlockSize="+outBlockSize);
this.decryptPro(inputstream, outputstream);
} catch (DataLengthException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
}
catch(Exception e)
{
e.printStackTrace();
}
//System.out.println("解密。。。outputload="+new String(outputload));
//byte[] outputload=new byte[outputstream.size()];
byte[] outputload=outputstream.toByteArray();
System.out.println("###[2]密文大小:"+inputload.length);
System.out.println("###[2]明文大小:"+outputload.length);
return outputload;
}
/**
* 解密RSA流,首先先讀取RSA的流的padding_size(第一行)
*
* @param inputstream 被加密過的流
* @param outputstream 解密輸出的流
*/
public void decryptPro(InputStream inputstream, OutputStream outputstream)
{
//設置引擎
eng.init(false, pair.getPrivate());
BufferedReader br = new BufferedReader(new InputStreamReader(inputstream));
int inBlockSize =this.eng.getInputBlockSize() ;
int outBlockSize = this.eng.getOutputBlockSize();
int lines;
byte[] outblock = new byte[outBlockSize];
String rv = null;
int inL=0;
byte[] last=null;
try {
int amout=inputstream.available();
lines=amout/(inBlockSize*2);
//System.out.println("lines="+lines);
rv=br.readLine();
//System.out.println("#########padding size="+rv);
int padding_size=Integer.parseInt(rv);
while ((rv = br.readLine()) != null)
{
lines--;
/* 要注意,Hex處理密文是將每個byte用2個16進制表示
* 一個Hex碼其實只需4bit來表示,一個byte有8bit,因此
* 需要2個Hex碼表示,所以,一個字符經Hex Encode會
* 變成兩個Hex字符。
*/
inL=rv.length()/2;
last=new byte[inL];
last = Hex.decode(rv);
outblock = eng.processBlock(last, 0, inBlockSize);
if(lines>0)
{
outputstream.write(outblock, 0, outBlockSize);
}
else
outputstream.write(outblock, 0, outBlockSize-padding_size);
}
} catch (DataLengthException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
}
catch(Exception e)
{
e.printStackTrace();
}
}
/**
* 輸出公鑰到文件
* @param Filename
*/
public void ExportPublicKey(String Filename)
{
String outfile = Filename;
BufferedOutputStream outstream = null;
try
{
outstream = new BufferedOutputStream(new FileOutputStream(outfile));
}
catch (IOException fnf)
{
System.err.println("無法創建公鑰文件 ["+outfile+"]");
System.exit(1);
}
RSAKeyParameters mypubkey=this.getPublicKey();
BigInteger mypubkey_modulus=mypubkey.getModulus();
BigInteger mypubkey_exponent=mypubkey.getExponent();
System.out.println("[ExportPublicKey]mypubkey_modulus="+mypubkey_modulus.toString());
System.out.println("[ExportPublicKey]mypubkey_exponent="+mypubkey_exponent);
try
{
outstream.write(mypubkey_modulus.toString().getBytes());
outstream.write('\n');
outstream.write(mypubkey_exponent.toString().getBytes());
outstream.flush();
outstream.close();
}
catch (IOException closing)
{
closing.printStackTrace();
}
System.out.println("公鑰輸出到文件:"+Filename);
}
/**
* 從文件中導入公鑰到內存
* @param Filename
* @return
*/
public RSAKeyParameters ImportPublicKey(String Filename)
{
String infile = Filename;
BufferedInputStream instream = null;
RSAKeyParameters RSAParam=null;
try
{
instream = new BufferedInputStream(new FileInputStream(infile));
}
catch (FileNotFoundException fnf)
{
System.err.println("公鑰文件沒有找到 ["+infile+"]");
System.exit(1);
}
BufferedReader br = new BufferedReader(new InputStreamReader(instream));
BigInteger mypubkey_modulus=null;
BigInteger mypubkey_exponent=null;
String readstr=null;
try {
readstr = br.readLine();
mypubkey_modulus= new BigInteger(readstr);
System.out.println("[ImportPublicKey]mypubkey_modulus="+mypubkey_modulus.toString());
readstr = br.readLine();
mypubkey_exponent=new BigInteger(readstr);
System.out.println("[ImportPublicKey]mypubkey_exponent="+mypubkey_exponent);
RSAParam=new RSAKeyParameters(false,mypubkey_modulus,mypubkey_exponent);
} catch (DataLengthException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
}
catch(Exception e)
{
e.printStackTrace();
}
return RSAParam;
}
/**
* 輸出私鑰到指定的文件
* @param Filename
*/
public void ExportPrivateKey(String Filename)
{
String outfile = Filename;
BufferedOutputStream outstream = null;
try
{
outstream = new BufferedOutputStream(new FileOutputStream(outfile));
}
catch (IOException fnf)
{
System.err.println("輸出文件無法創建 ["+outfile+"]");
System.exit(1);
}
RSAPrivateCrtKeyParameters myprivkey=this.getPrivateKey();
BigInteger myprivkey_modulus=myprivkey.getModulus();
BigInteger myprivkey_exponent=myprivkey.getExponent();
BigInteger e=myprivkey.getPublicExponent(); //e is public
BigInteger dP=myprivkey.getDP();
BigInteger dQ=myprivkey.getDQ();
BigInteger p=myprivkey.getP();
BigInteger q=myprivkey.getQ();
BigInteger qInv=myprivkey.getQInv();
try
{
outstream.write(myprivkey_modulus.toString().getBytes());
outstream.write('\n');
outstream.write(e.toString().getBytes());
outstream.write('\n');
outstream.write(myprivkey_exponent.toString().getBytes());
outstream.write('\n');
outstream.write(p.toString().getBytes());
outstream.write('\n');
outstream.write(q.toString().getBytes());
outstream.write('\n');
outstream.write(dP.toString().getBytes());
outstream.write('\n');
outstream.write(dQ.toString().getBytes());
outstream.write('\n');
outstream.write(qInv.toString().getBytes());
outstream.write('\n');
outstream.flush();
outstream.close();
}
catch (IOException closing)
{
closing.printStackTrace();
}
System.out.println("私鑰輸出到文件:"+Filename);
}
/**
* 輸出私鑰到指定的文件,私鑰經過密碼加密
* 強烈建議在生產環境中使用此方法而不要使用
* ExportPrivateKey(String Filename)
*
* @param Filename 私鑰文件
* @param Password 私鑰的保護密碼
*/
public void ExportPrivateKeyWithPass(String Filename, String Password)
{
String outfile = Filename;
ByteArrayOutputStream outstream=null;
BufferedOutputStream keyoutstream=null;
//借助BlockCipherTool來加密私鑰
BlockCipherTool cipherTool=new BlockCipherTool();
//暫時使用DES加密私鑰
//cipherTool.setEngine(new AESEngine());
//cipherTool.setEngine(new IDEAEngine());
cipherTool.setEngine(new DESEngine());
//cipherTool.setEngine(new BlowfishEngine());
//cipherTool.setKeyLength(64); //AES 32(Hex)*4=128bit
//String keyStr="123456789012345678901234567890FF"; //16進制 128bit AES Key
//String keyStr="123456789012345678901234567890FF123456789012345678901234567890FF"; //16進制 256bit AES Key
//String keyStr="123456789012345678901234567890FF"; //16進制 128bit IDEA Key
//String keyStr="0123456789abcdef"; //16進制 64bit(56) DES Key
//String keyStr="0123456789ABCDEF"; //16進制 64bit(56) Blowfish Key
outstream = new ByteArrayOutputStream();
try
{
keyoutstream = new BufferedOutputStream(new FileOutputStream(outfile));
}
catch (Exception fnf)
{
System.err.println("輸出文件無法創建 ["+outfile+"]");
System.exit(1);
}
RSAPrivateCrtKeyParameters myprivkey=this.getPrivateKey();
BigInteger myprivkey_modulus=myprivkey.getModulus();
BigInteger myprivkey_exponent=myprivkey.getExponent();
BigInteger e=myprivkey.getPublicExponent(); //e is public
BigInteger dP=myprivkey.getDP();
BigInteger dQ=myprivkey.getDQ();
BigInteger p=myprivkey.getP();
BigInteger q=myprivkey.getQ();
BigInteger qInv=myprivkey.getQInv();
try
{
// 產生正確的私鑰流
outstream.write(myprivkey_modulus.toString().getBytes());
outstream.write('\n');
outstream.write(e.toString().getBytes());
outstream.write('\n');
outstream.write(myprivkey_exponent.toString().getBytes());
outstream.write('\n');
outstream.write(p.toString().getBytes());
outstream.write('\n');
outstream.write(q.toString().getBytes());
outstream.write('\n');
outstream.write(dP.toString().getBytes());
outstream.write('\n');
outstream.write(dQ.toString().getBytes());
outstream.write('\n');
outstream.write(qInv.toString().getBytes());
outstream.write('\n');
byte[] privatekey_withtoutpass=outstream.toByteArray();
ByteArrayInputStream keyinstream=new ByteArrayInputStream(privatekey_withtoutpass);
//加密私鑰
cipherTool.init(true,Password);
//將outstream轉型成keyinstream,將keyinstream執行DES加密
cipherTool.Encrypt(keyinstream,keyoutstream);
keyinstream.close();
keyoutstream.flush();
keyoutstream.close();
}
catch (IOException closing)
{
closing.printStackTrace();
}
System.out.println("私鑰經過加密并輸出到文件:"+Filename);
}
/**
* 從某個文件中導入私鑰,假定私鑰未被加密
* @see ExportPrivateKey(String Filename)
* @param Filename
* @return
*/
public RSAPrivateCrtKeyParameters ImportPrivateKey(String Filename)
{
String infile = Filename;
BufferedInputStream instream = null;
RSAPrivateCrtKeyParameters RSAPrivParam=null;
try
{
instream = new BufferedInputStream(new FileInputStream(infile));
}
catch (FileNotFoundException fnf)
{
System.err.println("私鑰文件沒有找到 ["+infile+"]");
System.exit(1);
}
BufferedReader br = new BufferedReader(new InputStreamReader(instream));
BigInteger myprivkey_modulus=null;
BigInteger myprivkey_exponent=null;
BigInteger e=null;
BigInteger p=null;
BigInteger q=null;
BigInteger dP=null;
BigInteger dQ=null;
BigInteger qInv=null;
String readstr=null;
try {
readstr = br.readLine();
myprivkey_modulus= new BigInteger(readstr);
readstr = br.readLine();
e= new BigInteger(readstr);
readstr = br.readLine();
myprivkey_exponent= new BigInteger(readstr);
readstr = br.readLine();
p= new BigInteger(readstr);
readstr = br.readLine();
q= new BigInteger(readstr);
readstr = br.readLine();
dP= new BigInteger(readstr);
readstr = br.readLine();
dQ= new BigInteger(readstr);
readstr = br.readLine();
qInv= new BigInteger(readstr);
RSAPrivParam=new RSAPrivateCrtKeyParameters(myprivkey_modulus, myprivkey_exponent,
e,p,q,dP,dQ,qInv);
} catch (DataLengthException ex) {
ex.printStackTrace();
} catch (IllegalStateException ex) {
ex.printStackTrace();
}
catch(Exception ex)
{
ex.printStackTrace();
}
return RSAPrivParam;
}
/**
* 從私鑰文件中導入私鑰,并用保護密碼通過DES解密該私鑰
* 放入內存,該方法跟ExportPrivateKeyWithPass 對應
*
* @see ExportPrivateKeyWithPass(String Filename, String Password)
* @param Filename
* @param Password
* @return
*/
public RSAPrivateCrtKeyParameters ImportPrivateKeyWithPass(String Filename,String Password)
{
String infile = Filename;
InputStream instream = null;
ByteArrayInputStream keyinstream =null;
ByteArrayOutputStream keyoutstream = new ByteArrayOutputStream();
//借助BlockCipherTool來加密私鑰
BlockCipherTool cipherTool=new BlockCipherTool();
//暫時使用DES加密私鑰
//cipherTool.setEngine(new AESEngine());
//cipherTool.setEngine(new IDEAEngine());
cipherTool.setEngine(new DESEngine());
//cipherTool.setEngine(new BlowfishEngine());
//cipherTool.setKeyLength(64); //AES 32(Hex)*4=128bit
//String keyStr="123456789012345678901234567890FF"; //16進制 128bit AES Key
//String keyStr="123456789012345678901234567890FF123456789012345678901234567890FF"; //16進制 256bit AES Key
//String keyStr="123456789012345678901234567890FF"; //16進制 128bit IDEA Key
//String keyStr="0123456789abcdef"; //16進制 64bit(56) DES Key
//String keyStr="0123456789ABCDEF"; //16進制 64bit(56) Blowfish Key
RSAPrivateCrtKeyParameters RSAPrivParam=null;
try
{
instream = new BufferedInputStream(new FileInputStream(infile));
}
catch (FileNotFoundException fnf)
{
System.err.println("私鑰文件沒有找到 ["+infile+"]");
System.exit(1);
}
cipherTool.init(false,Password);
//keyinstream-->ByteArrayOutputStream,將keyinstream執行DES加密
cipherTool.Decrypt(instream,keyoutstream);
byte[] privatekey_withtoutpass=keyoutstream.toByteArray();
keyinstream=new ByteArrayInputStream(privatekey_withtoutpass);
BigInteger myprivkey_modulus=null;
BigInteger myprivkey_exponent=null;
BigInteger e=null;
BigInteger p=null;
BigInteger q=null;
BigInteger dP=null;
BigInteger dQ=null;
BigInteger qInv=null;
String readstr=null;
try {
BufferedReader br = new BufferedReader(new InputStreamReader(keyinstream));
readstr = br.readLine();
myprivkey_modulus= new BigInteger(readstr);
readstr = br.readLine();
e= new BigInteger(readstr);
readstr = br.readLine();
myprivkey_exponent= new BigInteger(readstr);
readstr = br.readLine();
p= new BigInteger(readstr);
readstr = br.readLine();
q= new BigInteger(readstr);
readstr = br.readLine();
dP= new BigInteger(readstr);
readstr = br.readLine();
dQ= new BigInteger(readstr);
readstr = br.readLine();
qInv= new BigInteger(readstr);
RSAPrivParam=new RSAPrivateCrtKeyParameters(myprivkey_modulus, myprivkey_exponent,
e,p,q,dP,dQ,qInv);
keyinstream.close();
keyoutstream.flush();
keyoutstream.close();
} catch (DataLengthException ex) {
ex.printStackTrace();
} catch (IllegalStateException ex) {
ex.printStackTrace();
}
catch(Exception ex)
{
ex.printStackTrace();
}
return RSAPrivParam;
}
/**
* 為一個Block清0
* @param block
*/
public void reset(byte[] block)
{
for(int i=0;i<block.length;i++)
block[i]=(byte)0;
}
/**
* 將某個Block自off后的字節清0
* @param block
* @param off
*/
public void padding(byte[] block, int off)
{
for(int i=off;i<block.length;i++)
block[i]=(byte)0;
}
}
或者你可以看看下面的代碼(RSAUtils.java):
package org.dev2dev.security.crypto.Asymmetric;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.math.BigInteger;
import java.security.SecureRandom;
import org.bouncycastle.crypto.AsymmetricBlockCipher;
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.encodings.OAEPEncoding;
import org.bouncycastle.crypto.encodings.PKCS1Encoding;
import org.bouncycastle.crypto.engines.DESEngine;
import org.bouncycastle.crypto.engines.RSAEngine;
import org.bouncycastle.crypto.generators.RSAKeyPairGenerator;
import org.bouncycastle.crypto.params.RSAKeyGenerationParameters;
import org.bouncycastle.crypto.params.RSAKeyParameters;
import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
import org.bouncycastle.util.encoders.Hex;
import org.dev2dev.security.crypto.blockcipher.BlockCipherTool;
/**
* RSA工具類
* @author david.turing
* @copyright GuangZhou BEA Usergroup
* @version 0.7
* @modifyTime 22:30:34
*/
public class RSAUtils {
int keylength=1024;
int certainty=20;
RSAKeyGenerationParameters keyparam;
AsymmetricBlockCipher eng = null;
RSAKeyPairGenerator pGen = null;
AsymmetricCipherKeyPair pair = null;
public RSAUtils()
{
}
public String getName()
{
return "RSA";
}
/**
* 設置RSA的密鑰長度
* @param rsakeylength
*/
public void setKeyLength(int rsakeylength)
{
if(rsakeylength==512||rsakeylength==768||rsakeylength==1024||rsakeylength==2048)
keylength=rsakeylength;
}
/**
* 設置RSA Key Pair的素數產生經度,該數值越大,理論產生的RSA Key安全性越高
* @param certaintyofprime
*/
public void setCertaintyOfPrime(int certaintyofprime)
{
certainty=certaintyofprime;
}
/**
* 生成RSA Keypair,如果你不是通過ImportPublicKey和ImportPrivateKey
* 來導入密鑰對,則可通過此方法隨機生成。
*
* @return RSAKeyGenerationParameters
*/
public void initRSAKeyPair()
{
/**
* 注意, 第一個參數被寫死了,它是publicExponent, 即e
* e通常選3,17,65537
* X.509建議使用65537
* PEM建議使用3
* PKCS#1建議使用3或65537
* 在本算法中,它使用了3,即0x3
*/
RSAKeyGenerationParameters rsaparam=
new RSAKeyGenerationParameters(BigInteger.valueOf(0x3),
new SecureRandom(), this.keylength, this.certainty);
this.keyparam = rsaparam;
//RSA Keypair的生成依賴于rsaparam
RSAKeyPairGenerator pGen = new RSAKeyPairGenerator();
pGen.init(keyparam);
pair = pGen.generateKeyPair();
pair.getPublic();
}
/**
* 設置RSA密鑰對,此方法用于從外部文件導入RSA密鑰對
* @see ImportPublicKey(String)
* @see ImportPrivateKey(String)
* @param pubparam 公鑰
* @param privparam 私鑰
*/
public void setRSAKeyPair(RSAKeyParameters pubparam, RSAPrivateCrtKeyParameters privparam)
{
AsymmetricCipherKeyPair newpair=new AsymmetricCipherKeyPair(pubparam,privparam);
pair=newpair;
}
/**
* 該函數返回公鑰
* @return
*/
public RSAKeyParameters getPublicKey()
{
return (RSAKeyParameters)pair.getPublic();
}
/**
* 該函數返回私鑰
* 注意,RSAPrivateCrtKeyParameters其實繼承了RSAKeyParameters
* @see getPublicKey()
* @return
*/
public RSAPrivateCrtKeyParameters getPrivateKey()
{
return (RSAPrivateCrtKeyParameters)pair.getPrivate();
}
/**
* RSA的padding模式,安全性依次遞增
* mode=1 RAW RSA 安全性最差
* mode=2 PKCS1
* mode=3 OAEP
* @param mode
*/
public void setRSAMode(int mode)
{
eng = new RSAEngine(); //默認就是RAW模式, 安全性問題,已不再使用
if (mode==2)
eng = new PKCS1Encoding(eng);
else
eng = new OAEPEncoding(eng); //mode==3
}
/**
* 該RSAEngine的每次處理輸入數據,以Block為單位,是32Bytes
* 因此,本函數的輸入要嚴格控制在32Byte,即256bit數據
* 超出該長度會拋出異常。
* 本函數要求輸入必須為16進制字符0-F。
*
* @see Decrypt(String input)
* @param input
* @return
*/
public String encrypt(String input)
{
byte[] inputdata=Hex.decode(input);
//用公鑰加密
eng.init(true, pair.getPublic());
System.out.println(">>>加密參數");
System.out.println(">>>明文字節數:"+inputdata.length);
System.out.println(">>>RSA Engine Input Block Size="+this.eng.getInputBlockSize());
System.out.println(">>>RSA Engine Output Block Size="+this.eng.getOutputBlockSize());
try
{
inputdata = eng.processBlock(inputdata, 0, inputdata.length);
}
catch (Exception e)
{
e.printStackTrace();
}
return new String(Hex.encode(inputdata));
}
/**
* 該函數輸入為字節,并規定其長度為32字節
* 超出該長度會拋出異常
* @see Decrypt(byte[] inputdata)
* @param inputdata
* @return
*/
public byte[] encrypt(byte[] inputdata)
{
byte[] outputdata=null;
//用公鑰加密
eng.init(true, pair.getPublic());
try
{
inputdata = eng.processBlock(inputdata, 0, inputdata.length);
outputdata=new byte[eng.getOutputBlockSize()];
outputdata=inputdata;
}
catch (Exception e)
{
e.printStackTrace();
}
return outputdata;
}
/**
* 加密ByteArrayInputStream流,在該方法中,會對input做分段處理,每段都將會
* 以inBlockSize來劃分明文,密文同樣會設置換行,因此,將來在加密過程中,密文
* 需要分行讀入,在明文、密文,唯一對應的是inBlock和outBlock,它們是換行對應的。
*
* 本函數已經處理結尾Block問題
* @param input
* @param Key
* @return
*/
public byte[] encryptPro(byte[] inputload)
{
ByteArrayInputStream inputstream=new ByteArrayInputStream(inputload);
ByteArrayOutputStream outputstream=new ByteArrayOutputStream();
//用公鑰加密
eng.init(true, pair.getPublic());
int inBlockSize =this.eng.getInputBlockSize() ;
int outBlockSize = this.eng.getOutputBlockSize();
try {
System.out.println("加密的 InBlockSize="+inBlockSize);
System.out.println("加密的outBlockSize="+outBlockSize);
encryptPro(inputstream, outputstream);
} catch (DataLengthException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch(Exception e){
e.printStackTrace();
}
byte[] outputload=outputstream.toByteArray();
System.out.println("###[1]明文大?。?quot;+inputload.length);
System.out.println("###[1]密文大?。?quot;+outputload.length);
return outputload;
}
/**
* 加密BufferedInputStream流,在該方法中,會對input做分段處理,每段都將會
* 以inBlockSize來劃分明文,密文同樣會設置換行,因此,將來在加密過程中,密文
* 需要分行讀入,在明文、密文,唯一對應的是inBlock和outBlock,它們是換行對應的。
*
*此函數未處理padding,如果你不想自己調整padding,請用encryptPro
*@see encryptPro(BufferedInputStream inputstream,BufferedOutputStream outputstream)
*
* @param input
* @param Key
* @return
*/
public void encrypt(BufferedInputStream inputstream,BufferedOutputStream outputstream)
{
//用公鑰加密
eng.init(true, pair.getPublic());
int inBlockSize =this.eng.getInputBlockSize() ;
int outBlockSize = this.eng.getOutputBlockSize();
byte[] inblock = new byte[inBlockSize];
byte[] outblock = new byte[outBlockSize];
byte[] rv = null;
try {
while (inputstream.read(inblock, 0, inBlockSize) > 0)
{
outblock = eng.processBlock(inblock, 0, inBlockSize);
rv = Hex.encode(outblock, 0, outBlockSize);
outputstream.write(rv, 0, rv.length);
outputstream.write('\n');
}
} catch (DataLengthException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch(Exception e){
e.printStackTrace();
}
}
/**
* 加密BufferedInputStream流,在該方法中,會對input做分段處理,每段都將會
* 以inBlockSize來劃分明文,密文同樣會設置換行,因此,將來在加密過程中,密文
* 需要分行讀入,在明文、密文,唯一對應的是inBlock和outBlock,它們是換行對應的。
*
* 該函數會在加密文件的頭部注明padding_size
* padding_size即padding_size即明文流按照inBlockSize劃分后
* 最后一個block的未占滿的大?。ㄗ止潝担?
*
* @param input
* @param Key
* @return
*/
public void encryptPro(InputStream inputstream,OutputStream outputstream)
{
//用公鑰加密
eng.init(true, pair.getPublic());
int inBlockSize =this.eng.getInputBlockSize() ;
int outBlockSize = this.eng.getOutputBlockSize();
byte[] inblock = new byte[inBlockSize];
byte[] outblock = new byte[outBlockSize];
byte[] rv = null;
try {
//System.out.println("stream length="+inputstream.available());
int padding_size=inBlockSize-(inputstream.available() % inBlockSize);
//System.out.println("padding_size="+padding_size);
/*寫入padding_size,處理最后一個Block不夠inBlockSize的情況
* 記住不要自己修改inBlockSize,因為RSA共有三種模式,每種模式
* 對Padding的處理方式都不一樣,所以,不要修改對processBlock
* 的加密解密方式??傊?,不要修改RSA的inBlock!
*/
outputstream.write((padding_size+"").getBytes());
outputstream.write('\n');
while (inputstream.read(inblock, 0, inBlockSize) > 0)
{
outblock = eng.processBlock(inblock, 0, inBlockSize);
rv = Hex.encode(outblock, 0, outBlockSize);
//System.out.println("Hex len="+rv.length);
outputstream.write(rv, 0, rv.length);
outputstream.write('\n');
}
} catch (DataLengthException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch(Exception e){
e.printStackTrace();
}
}
/**
* 解密字符串
* @param input
* @return
*/
public String decrypt(String input)
{
byte[] inputdata=Hex.decode(input);
eng.init(false,pair.getPrivate());
System.out.println(">>>加密參數");
System.out.println(">>>RSA Engine Input Block Size="+this.eng.getInputBlockSize());
System.out.println(">>>RSA Engine Output Block Size="+this.eng.getOutputBlockSize());
try
{
inputdata=eng.processBlock(inputdata,0,inputdata.length);
}
catch(Exception e)
{
e.printStackTrace();
}
return new String(Hex.encode(inputdata));
}
/**
* 解密字節數組
* @param inputdata
* @return
*/
public byte[] decrypt(byte[] inputdata)
{
byte[] outputdata=null;
//用公鑰加密
eng.init(false, pair.getPrivate());
try
{
inputdata = eng.processBlock(inputdata, 0, inputdata.length);
outputdata=new byte[eng.getOutputBlockSize()];
outputdata=inputdata;
}
catch (Exception e)
{
e.printStackTrace();
}
return outputdata;
}
/**
* 解密流
*
* 本函數已經處理結尾Block問題
* @see encryptPro(byte[] inputload)
*
* @param inputstream 被加密過的流
* @param outputstream 解密輸出的流
*/
public byte[] decryptPro(byte[] inputload)
{
ByteArrayInputStream inputstream=new ByteArrayInputStream(inputload);
ByteArrayOutputStream outputstream=new ByteArrayOutputStream();
//設置引擎
eng.init(false, pair.getPrivate());
int inBlockSize =this.eng.getInputBlockSize() ;
int outBlockSize = this.eng.getOutputBlockSize();
try {
System.out.println("解密的In BlockSize="+inBlockSize);
System.out.println("解密的out BlockSize="+outBlockSize);
this.decryptPro(inputstream, outputstream);
} catch (DataLengthException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
}
catch(Exception e)
{
e.printStackTrace();
}
//System.out.println("解密。。。outputload="+new String(outputload));
//byte[] outputload=new byte[outputstream.size()];
byte[] outputload=outputstream.toByteArray();
System.out.println("###[2]密文大小:"+inputload.length);
System.out.println("###[2]明文大小:"+outputload.length);
return outputload;
}
/**
* 解密RSA流,首先先讀取RSA的流的padding_size(第一行)
*
* @param inputstream 被加密過的流
* @param outputstream 解密輸出的流
*/
public void decryptPro(InputStream inputstream, OutputStream outputstream)
{
//設置引擎
eng.init(false, pair.getPrivate());
BufferedReader br = new BufferedReader(new InputStreamReader(inputstream));
int inBlockSize =this.eng.getInputBlockSize() ;
int outBlockSize = this.eng.getOutputBlockSize();
int lines;
byte[] outblock = new byte[outBlockSize];
String rv = null;
int inL=0;
byte[] last=null;
try {
int amout=inputstream.available();
lines=amout/(inBlockSize*2);
//System.out.println("lines="+lines);
rv=br.readLine();
//System.out.println("#########padding size="+rv);
int padding_size=Integer.parseInt(rv);
while ((rv = br.readLine()) != null)
{
lines--;
/* 要注意,Hex處理密文是將每個byte用2個16進制表示
* 一個Hex碼其實只需4bit來表示,一個byte有8bit,因此
* 需要2個Hex碼表示,所以,一個字符經Hex Encode會
* 變成兩個Hex字符。
*/
inL=rv.length()/2;
last=new byte[inL];
last = Hex.decode(rv);
outblock = eng.processBlock(last, 0, inBlockSize);
if(lines>0)
{
outputstream.write(outblock, 0, outBlockSize);
}
else
outputstream.write(outblock, 0, outBlockSize-padding_size);
}
} catch (DataLengthException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
}
catch(Exception e)
{
e.printStackTrace();
}
}
/**
* 輸出公鑰到文件
* @param Filename
*/
public void ExportPublicKey(String Filename)
{
String outfile = Filename;
BufferedOutputStream outstream = null;
try
{
outstream = new BufferedOutputStream(new FileOutputStream(outfile));
}
catch (IOException fnf)
{
System.err.println("無法創建公鑰文件 ["+outfile+"]");
System.exit(1);
}
RSAKeyParameters mypubkey=this.getPublicKey();
BigInteger mypubkey_modulus=mypubkey.getModulus();
BigInteger mypubkey_exponent=mypubkey.getExponent();
System.out.println("[ExportPublicKey]mypubkey_modulus="+mypubkey_modulus.toString());
System.out.println("[ExportPublicKey]mypubkey_exponent="+mypubkey_exponent);
try
{
outstream.write(mypubkey_modulus.toString().getBytes());
outstream.write('\n');
outstream.write(mypubkey_exponent.toString().getBytes());
outstream.flush();
outstream.close();
}
catch (IOException closing)
{
closing.printStackTrace();
}
System.out.println("公鑰輸出到文件:"+Filename);
}
/**
* 從文件中導入公鑰到內存
* @param Filename
* @return
*/
public RSAKeyParameters ImportPublicKey(String Filename)
{
String infile = Filename;
BufferedInputStream instream = null;
RSAKeyParameters RSAParam=null;
try
{
instream = new BufferedInputStream(new FileInputStream(infile));
}
catch (FileNotFoundException fnf)
{
System.err.println("公鑰文件沒有找到 ["+infile+"]");
System.exit(1);
}
BufferedReader br = new BufferedReader(new InputStreamReader(instream));
BigInteger mypubkey_modulus=null;
BigInteger mypubkey_exponent=null;
String readstr=null;
try {
readstr = br.readLine();
mypubkey_modulus= new BigInteger(readstr);
System.out.println("[ImportPublicKey]mypubkey_modulus="+mypubkey_modulus.toString());
readstr = br.readLine();
mypubkey_exponent=new BigInteger(readstr);
System.out.println("[ImportPublicKey]mypubkey_exponent="+mypubkey_exponent);
RSAParam=new RSAKeyParameters(false,mypubkey_modulus,mypubkey_exponent);
} catch (DataLengthException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
}
catch(Exception e)
{
e.printStackTrace();
}
return RSAParam;
}
/**
* 輸出私鑰到指定的文件
* @param Filename
*/
public void ExportPrivateKey(String Filename)
{
String outfile = Filename;
BufferedOutputStream outstream = null;
try
{
outstream = new BufferedOutputStream(new FileOutputStream(outfile));
}
catch (IOException fnf)
{
System.err.println("輸出文件無法創建 ["+outfile+"]");
System.exit(1);
}
RSAPrivateCrtKeyParameters myprivkey=this.getPrivateKey();
BigInteger myprivkey_modulus=myprivkey.getModulus();
BigInteger myprivkey_exponent=myprivkey.getExponent();
BigInteger e=myprivkey.getPublicExponent(); //e is public
BigInteger dP=myprivkey.getDP();
BigInteger dQ=myprivkey.getDQ();
BigInteger p=myprivkey.getP();
BigInteger q=myprivkey.getQ();
BigInteger qInv=myprivkey.getQInv();
try
{
outstream.write(myprivkey_modulus.toString().getBytes());
outstream.write('\n');
outstream.write(e.toString().getBytes());
outstream.write('\n');
outstream.write(myprivkey_exponent.toString().getBytes());
outstream.write('\n');
outstream.write(p.toString().getBytes());
outstream.write('\n');
outstream.write(q.toString().getBytes());
outstream.write('\n');
outstream.write(dP.toString().getBytes());
outstream.write('\n');
outstream.write(dQ.toString().getBytes());
outstream.write('\n');
outstream.write(qInv.toString().getBytes());
outstream.write('\n');
outstream.flush();
outstream.close();
}
catch (IOException closing)
{
closing.printStackTrace();
}
System.out.println("私鑰輸出到文件:"+Filename);
}
/**
* 輸出私鑰到指定的文件,私鑰經過密碼加密
* 強烈建議在生產環境中使用此方法而不要使用
* ExportPrivateKey(String Filename)
*
* @param Filename 私鑰文件
* @param Password 私鑰的保護密碼
*/
public void ExportPrivateKeyWithPass(String Filename, String Password)
{
String outfile = Filename;
ByteArrayOutputStream outstream=null;
BufferedOutputStream keyoutstream=null;
//借助BlockCipherTool來加密私鑰
BlockCipherTool cipherTool=new BlockCipherTool();
//暫時使用DES加密私鑰
//cipherTool.setEngine(new AESEngine());
//cipherTool.setEngine(new IDEAEngine());
cipherTool.setEngine(new DESEngine());
//cipherTool.setEngine(new BlowfishEngine());
//cipherTool.setKeyLength(64); //AES 32(Hex)*4=128bit
//String keyStr="123456789012345678901234567890FF"; //16進制 128bit AES Key
//String keyStr="123456789012345678901234567890FF123456789012345678901234567890FF"; //16進制 256bit AES Key
//String keyStr="123456789012345678901234567890FF"; //16進制 128bit IDEA Key
//String keyStr="0123456789abcdef"; //16進制 64bit(56) DES Key
//String keyStr="0123456789ABCDEF"; //16進制 64bit(56) Blowfish Key
outstream = new ByteArrayOutputStream();
try
{
keyoutstream = new BufferedOutputStream(new FileOutputStream(outfile));
}
catch (Exception fnf)
{
System.err.println("輸出文件無法創建 ["+outfile+"]");
System.exit(1);
}
RSAPrivateCrtKeyParameters myprivkey=this.getPrivateKey();
BigInteger myprivkey_modulus=myprivkey.getModulus();
BigInteger myprivkey_exponent=myprivkey.getExponent();
BigInteger e=myprivkey.getPublicExponent(); //e is public
BigInteger dP=myprivkey.getDP();
BigInteger dQ=myprivkey.getDQ();
BigInteger p=myprivkey.getP();
BigInteger q=myprivkey.getQ();
BigInteger qInv=myprivkey.getQInv();
try
{
// 產生正確的私鑰流
outstream.write(myprivkey_modulus.toString().getBytes());
outstream.write('\n');
outstream.write(e.toString().getBytes());
outstream.write('\n');
outstream.write(myprivkey_exponent.toString().getBytes());
outstream.write('\n');
outstream.write(p.toString().getBytes());
outstream.write('\n');
outstream.write(q.toString().getBytes());
outstream.write('\n');
outstream.write(dP.toString().getBytes());
outstream.write('\n');
outstream.write(dQ.toString().getBytes());
outstream.write('\n');
outstream.write(qInv.toString().getBytes());
outstream.write('\n');
byte[] privatekey_withtoutpass=outstream.toByteArray();
ByteArrayInputStream keyinstream=new ByteArrayInputStream(privatekey_withtoutpass);
//加密私鑰
cipherTool.init(true,Password);
//將outstream轉型成keyinstream,將keyinstream執行DES加密
cipherTool.Encrypt(keyinstream,keyoutstream);
keyinstream.close();
keyoutstream.flush();
keyoutstream.close();
}
catch (IOException closing)
{
closing.printStackTrace();
}
System.out.println("私鑰經過加密并輸出到文件:"+Filename);
}
/**
* 從某個文件中導入私鑰,假定私鑰未被加密
* @see ExportPrivateKey(String Filename)
* @param Filename
* @return
*/
public RSAPrivateCrtKeyParameters ImportPrivateKey(String Filename)
{
String infile = Filename;
BufferedInputStream instream = null;
RSAPrivateCrtKeyParameters RSAPrivParam=null;
try
{
instream = new BufferedInputStream(new FileInputStream(infile));
}
catch (FileNotFoundException fnf)
{
System.err.println("私鑰文件沒有找到 ["+infile+"]");
System.exit(1);
}
BufferedReader br = new BufferedReader(new InputStreamReader(instream));
BigInteger myprivkey_modulus=null;
BigInteger myprivkey_exponent=null;
BigInteger e=null;
BigInteger p=null;
BigInteger q=null;
BigInteger dP=null;
BigInteger dQ=null;
BigInteger qInv=null;
String readstr=null;
try {
readstr = br.readLine();
myprivkey_modulus= new BigInteger(readstr);
readstr = br.readLine();
e= new BigInteger(readstr);
readstr = br.readLine();
myprivkey_exponent= new BigInteger(readstr);
readstr = br.readLine();
p= new BigInteger(readstr);
readstr = br.readLine();
q= new BigInteger(readstr);
readstr = br.readLine();
dP= new BigInteger(readstr);
readstr = br.readLine();
dQ= new BigInteger(readstr);
readstr = br.readLine();
qInv= new BigInteger(readstr);
RSAPrivParam=new RSAPrivateCrtKeyParameters(myprivkey_modulus, myprivkey_exponent,
e,p,q,dP,dQ,qInv);
} catch (DataLengthException ex) {
ex.printStackTrace();
} catch (IllegalStateException ex) {
ex.printStackTrace();
}
catch(Exception ex)
{
ex.printStackTrace();
}
return RSAPrivParam;
}
/**
* 從私鑰文件中導入私鑰,并用保護密碼通過DES解密該私鑰
* 放入內存,該方法跟ExportPrivateKeyWithPass 對應
*
* @see ExportPrivateKeyWithPass(String Filename, String Password)
* @param Filename
* @param Password
* @return
*/
public RSAPrivateCrtKeyParameters ImportPrivateKeyWithPass(String Filename,String Password)
{
String infile = Filename;
InputStream instream = null;
ByteArrayInputStream keyinstream =null;
ByteArrayOutputStream keyoutstream = new ByteArrayOutputStream();
//借助BlockCipherTool來加密私鑰
BlockCipherTool cipherTool=new BlockCipherTool();
//暫時使用DES加密私鑰
//cipherTool.setEngine(new AESEngine());
//cipherTool.setEngine(new IDEAEngine());
cipherTool.setEngine(new DESEngine());
//cipherTool.setEngine(new BlowfishEngine());
//cipherTool.setKeyLength(64); //AES 32(Hex)*4=128bit
//String keyStr="123456789012345678901234567890FF"; //16進制 128bit AES Key
//String keyStr="123456789012345678901234567890FF123456789012345678901234567890FF"; //16進制 256bit AES Key
//String keyStr="123456789012345678901234567890FF"; //16進制 128bit IDEA Key
//String keyStr="0123456789abcdef"; //16進制 64bit(56) DES Key
//String keyStr="0123456789ABCDEF"; //16進制 64bit(56) Blowfish Key
RSAPrivateCrtKeyParameters RSAPrivParam=null;
try
{
instream = new BufferedInputStream(new FileInputStream(infile));
}
catch (FileNotFoundException fnf)
{
System.err.println("私鑰文件沒有找到 ["+infile+"]");
System.exit(1);
}
cipherTool.init(false,Password);
//keyinstream-->ByteArrayOutputStream,將keyinstream執行DES加密
cipherTool.Decrypt(instream,keyoutstream);
byte[] privatekey_withtoutpass=keyoutstream.toByteArray();
keyinstream=new ByteArrayInputStream(privatekey_withtoutpass);
BigInteger myprivkey_modulus=null;
BigInteger myprivkey_exponent=null;
BigInteger e=null;
BigInteger p=null;
BigInteger q=null;
BigInteger dP=null;
BigInteger dQ=null;
BigInteger qInv=null;
String readstr=null;
try {
BufferedReader br = new BufferedReader(new InputStreamReader(keyinstream));
readstr = br.readLine();
myprivkey_modulus= new BigInteger(readstr);
readstr = br.readLine();
e= new BigInteger(readstr);
readstr = br.readLine();
myprivkey_exponent= new BigInteger(readstr);
readstr = br.readLine();
p= new BigInteger(readstr);
readstr = br.readLine();
q= new BigInteger(readstr);
readstr = br.readLine();
dP= new BigInteger(readstr);
readstr = br.readLine();
dQ= new BigInteger(readstr);
readstr = br.readLine();
qInv= new BigInteger(readstr);
RSAPrivParam=new RSAPrivateCrtKeyParameters(myprivkey_modulus, myprivkey_exponent,
e,p,q,dP,dQ,qInv);
keyinstream.close();
keyoutstream.flush();
keyoutstream.close();
} catch (DataLengthException ex) {
ex.printStackTrace();
} catch (IllegalStateException ex) {
ex.printStackTrace();
}
catch(Exception ex)
{
ex.printStackTrace();
}
return RSAPrivParam;
}
/**
* 為一個Block清0
* @param block
*/
public void reset(byte[] block)
{
for(int i=0;i<block.length;i++)
block[i]=(byte)0;
}
/**
* 將某個Block自off后的字節清0
* @param block
* @param off
*/
public void padding(byte[] block, int off)
{
for(int i=off;i<block.length;i++)
block[i]=(byte)0;
}
}
re: 發布GIF4J破解版 david.turing 2007-09-16 12:57
哦,JPG似乎不支持吧?
re: 關于配置Weblogic的NodeManager服務 david.turing 2007-09-06 12:00
如果嫌SSL配置麻煩,可以使用Demo Identity和Demo Trust,即不過,還有一種更簡單的方式,即nodemanager.properties中使用Demo方式(反注釋Demo哪一行即可),其他配置一樣。
re: 認為有必要抵制房地產商的朋友請留下芳名 david.turing 2007-08-29 21:30
這個老帖子都過去一年多了,居然還能通過google找到,再次介紹1下廣州的QQ群:16699048
re: 國內第一例自由軟件盜用事件(Captcha開源社區的Captchio) david.turing 2007-05-22 08:49
目前,國內,引用文章主要有幾種
1,完全不修改作者原來的內容,并且注明出處
2,完全不修改作者原來的內容,不注明出處
3,在作者原來的內容并把著作權相關的東西換成自己的
1,完全不修改作者原來的內容,并且注明出處
2,完全不修改作者原來的內容,不注明出處
3,在作者原來的內容并把著作權相關的東西換成自己的
re: 國內第一例自由軟件盜用事件(Captcha開源社區的Captchio)[未登錄] david.turing 2007-05-21 22:36
樓上的兄弟問的非常好
pgp.org.cn是幫java2s.com做了一個鏡像(mirror),完全引用了java2s
不信看看所有的頁面,最后都是有
---------------------------
Home| Contact Us
Copyright 2003 - 04 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.
----------------------------
基本上所有source都是鏈回去java2s.
ReLicense是另外一個問題。
pgp.org.cn是幫java2s.com做了一個鏡像(mirror),完全引用了java2s
不信看看所有的頁面,最后都是有
---------------------------
Home| Contact Us
Copyright 2003 - 04 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.
----------------------------
基本上所有source都是鏈回去java2s.
ReLicense是另外一個問題。
re: 中國應該有自己的PGP群體[未登錄] david.turing 2007-05-20 12:16
大部分PGP軟件都以一個sig的文件存在,對于郵件文本,你可以選擇用
-----BEGIN PGP SIGNED MESSAGE-----
-----END PGP SIGNATURE-----
的方式括起來,PGP客戶端會幫你識別,如果你選擇dat格式,則你需要手動用PGP Desktop打開來驗證,鼠標右鍵有這個功能。
-----BEGIN PGP SIGNED MESSAGE-----
-----END PGP SIGNATURE-----
的方式括起來,PGP客戶端會幫你識別,如果你選擇dat格式,則你需要手動用PGP Desktop打開來驗證,鼠標右鍵有這個功能。
re: 發布一個簡易的EclipseDos Plugin(6KB) david.turing 2007-05-11 13:33
文件菜單我沒做Explorer功能,因為文件應該是找到他的目錄或者package就能定位了吧?另外,這個東西太簡單,才6K,你們解壓一下,自己改裝把。
因為很多人用ultraedit的ultracompare或Beyond Compare去比較文件,而不是vim的diff,所以自己各取所需去寫吧,我做了一個vim diff,適合自己用多一點。
顏色圖標這個容易,下次我加上去。
因為很多人用ultraedit的ultracompare或Beyond Compare去比較文件,而不是vim的diff,所以自己各取所需去寫吧,我做了一個vim diff,適合自己用多一點。
顏色圖標這個容易,下次我加上去。
re: 發布一個簡易的EclipseDos Plugin(6KB) david.turing 2007-05-09 21:41
thx for advice, 已經加入了這些常用的繁瑣功能
re: 發布一個簡易的EclipseDos Plugin david.turing 2007-05-09 14:26
增加了一個VIM Open功能,都是方便自己而已
re: Weblogic download url記載 david.turing 2007-04-13 22:33
[Weblogic for Linux]
Weblogic 10 for Redhat Linux:
http://download2.bea.com/pub/platform/100/server100_linux32.bin
http://download2.bea.com/pub/platform/92/server920_linux32.bin
Weblogic 10 for Redhat Linux:
http://download2.bea.com/pub/platform/100/server100_linux32.bin
http://download2.bea.com/pub/platform/92/server920_linux32.bin
re: Weblogic download url記載 david.turing 2007-04-10 17:32
re: Portal技術最新動態與企業門戶開發經驗交流(廣州User Group活動) david.turing 2007-04-03 11:03
現在報名人數已經到了78人了,100人封頂啊
re: Portal技術最新動態與企業門戶開發經驗交流(廣州User Group活動) david.turing 2007-04-02 20:14
of course, see dev2dev gz ug bbs
re: Portal技術最新動態與企業門戶開發經驗交流(廣州User Group活動) david.turing 2007-03-30 16:23
去dev2dev,申請一下吧
re: Portal技術最新動態與企業門戶開發經驗交流(廣州User Group活動) david.turing 2007-03-30 14:04
呵呵,你都去Hero2007了
re: Portal技術最新動態與企業門戶開發經驗交流(廣州User Group活動) david.turing 2007-03-30 08:24
可以
re: Weblogic download url記載 david.turing 2007-03-23 10:59
Weblogic 8.1.4 Platform for AIX
http://download2.bea.com/pub/platform/81/pj_platform814_generic.jar
Weblogic 9.2 Server for AIX
http://download2.bea.com/pub/platform/92/server921_generic.jar
http://download2.bea.com/pub/platform/81/pj_platform814_generic.jar
Weblogic 9.2 Server for AIX
http://download2.bea.com/pub/platform/92/server921_generic.jar
re: Yale CAS異常問題總結(2)Unable to validate ProxyTicketValidator之unable to find valid certification path to requested target[未登錄] david.turing 2007-02-08 20:10
This is a trustcert entry but you need to import it into %JAVA_HOME%\jre\lib\security\cacerts where your CAS can't locate it. Make sure you do that, and the password for cacerts has a lot of un-useful trustcert, remove all of them and importyour "tomcat" entry into cacerts(through SecureRCP)
re: Weblogic download url記載 david.turing 2007-02-05 16:29
下載Weblogic Platform 8.1 SP6的鏈接
http://download2.bea.com/pub/platform/81/server816_solaris32.bin
http://download2.bea.com/pub/platform/81/server816_solaris32.bin
re: PGP技術與網絡實名制的思考 david.turing 2007-02-05 10:28
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
匿名是一種權利,實名也是一種權利
我們可以讓這兩者同時存在,
喜歡實名,可以使用PGP
Signature去確保自己的言論不會被別人篡改然后再發布
喜歡匿名,可以用PGP
Encrytpion加密信息后,發給自己信任的發布者。
-----BEGIN PGP SIGNATURE-----
Version: PGP Desktop 9.0.5 - Enterprise license
Comment: www.pgp.org.cn
iQA/AwUBRcaV5E2j31FcBpdPEQJgMQCfUDEL9yQ0+bsFHSjXccPRZL2paMQAn2EQ
9OPNRzDS36Fy9meTwu3EPD98
=lwOs
-----END PGP SIGNATURE-----
Hash: SHA1
匿名是一種權利,實名也是一種權利
我們可以讓這兩者同時存在,
喜歡實名,可以使用PGP
Signature去確保自己的言論不會被別人篡改然后再發布
喜歡匿名,可以用PGP
Encrytpion加密信息后,發給自己信任的發布者。
-----BEGIN PGP SIGNATURE-----
Version: PGP Desktop 9.0.5 - Enterprise license
Comment: www.pgp.org.cn
iQA/AwUBRcaV5E2j31FcBpdPEQJgMQCfUDEL9yQ0+bsFHSjXccPRZL2paMQAn2EQ
9OPNRzDS36Fy9meTwu3EPD98
=lwOs
-----END PGP SIGNATURE-----
re: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: No trusted certificate found david.turing 2007-02-05 09:30
請閱讀http://www.aygfsteel.com/security/archive/2007/01/07/SecureXRCP.html
------------
我使用xca導出證書為pkcs#12后,在securex里導入密匙對時提示如下錯誤
org.dev2dev.security.keytool.CryptoException: Could not load keystore as type 'PKCS12'.
------------
我使用xca導出證書為pkcs#12后,在securex里導入密匙對時提示如下錯誤
org.dev2dev.security.keytool.CryptoException: Could not load keystore as type 'PKCS12'.
re: SecureX Eclipse Plugin Alpha2發布 david.turing 2007-01-26 15:14
re: CAS如何跟普通的Web系統融合認證和授權 david.turing 2007-01-25 10:12
1,認證跟授權分離, 可以實現組件甚至應用服務的分離.
2,得益于1,因此,我們可以將原先各個獨立的應用服務器系統中認證模塊抽取到一個單點,做一個Single Sign-On
3,于是原先的公式是
N個認證模塊+N個授權模塊=>1個認證模塊+N個授權模塊
你考慮的問題最終會體現實認證的互操作性,但目標仍然沒有脫離統一認證這個需求.
但考慮到各個應用集成商之間對認證過程的不同實現標準, 的確需要一個統一的認證接口, SAML會是一個很好的開始.
但前提是你是否充分理解了,在SSO的過程中,協議是如何安全地傳遞用戶的Credential,這一點非常關鍵, 以致于你提問題的方式也會有所不同.
2,得益于1,因此,我們可以將原先各個獨立的應用服務器系統中認證模塊抽取到一個單點,做一個Single Sign-On
3,于是原先的公式是
N個認證模塊+N個授權模塊=>1個認證模塊+N個授權模塊
你考慮的問題最終會體現實認證的互操作性,但目標仍然沒有脫離統一認證這個需求.
但考慮到各個應用集成商之間對認證過程的不同實現標準, 的確需要一個統一的認證接口, SAML會是一個很好的開始.
但前提是你是否充分理解了,在SSO的過程中,協議是如何安全地傳遞用戶的Credential,這一點非常關鍵, 以致于你提問題的方式也會有所不同.
re: Weblogic download url記載 david.turing 2007-01-18 21:00
Download WebLogic Portal 8.1 with SP5 for HP-UX (PA-RISC)
http://download2.bea.com/pub/platform/81/Platform815_hpux32.bin
Download WebLogic Server/Express 8.1 with SP5 for HP-UX (PA-RISC)
http://download2.bea.com/pub/platform/81/server815_hpux32.bin
http://download2.bea.com/pub/platform/81/Platform815_hpux32.bin
Download WebLogic Server/Express 8.1 with SP5 for HP-UX (PA-RISC)
http://download2.bea.com/pub/platform/81/server815_hpux32.bin
re: 發布一個簡易版本的SecureXRCP david.turing 2007-01-08 18:10
請注意,大家使用SecureX的時候記得去除JDK的出口限制
請參看下面的文章
關于Java加密擴展的出口限制
http://www.aygfsteel.com/security/archive/2006/03/08/34381.html
請參看下面的文章
關于Java加密擴展的出口限制
http://www.aygfsteel.com/security/archive/2006/03/08/34381.html
re: SecureX Eclipse Plugin Alpha2發布 david.turing 2007-01-08 18:05
兄弟,org.dev2dev.security.keytool.CryptoException: Could not load keystore as type 'PKCS12'. 誤導了你了,
你的更底層拋出的異常應該是:
java.security.InvalidKeyException:
Illegal key size
at org.bouncycastle.jce.provider.JDKPKCS12KeyStore.unwrapKey(Unknown Source)
at org.bouncycastle.jce.provider.JDKPKCS12KeyStore.engineLoad(Unknown Source)
at java.security.KeyStore.load(KeyStore.java:1150)
......
解決辦法請參看:我的一篇Blog《關于Java加密擴展的出口限制》
http://www.aygfsteel.com/security/category/8296.html?Show=All
我發布SecureXRCP的時候大意了,沒注意大家的JDK使用的弱版本的加密出口限制,謝謝你的提醒。
你的更底層拋出的異常應該是:
java.security.InvalidKeyException:
Illegal key size
at org.bouncycastle.jce.provider.JDKPKCS12KeyStore.unwrapKey(Unknown Source)
at org.bouncycastle.jce.provider.JDKPKCS12KeyStore.engineLoad(Unknown Source)
at java.security.KeyStore.load(KeyStore.java:1150)
......
解決辦法請參看:我的一篇Blog《關于Java加密擴展的出口限制》
http://www.aygfsteel.com/security/category/8296.html?Show=All
我發布SecureXRCP的時候大意了,沒注意大家的JDK使用的弱版本的加密出口限制,謝謝你的提醒。
re: SecureX Eclipse Plugin Alpha2發布 david.turing 2007-01-07 10:58
to ROM:我這邊測試沒有這種問題,你能否說具體一些。
re: 安裝測試Apache Proxy For Weblogic Cluster筆記 david.turing 2006-12-30 09:02
conf/httpd.conf:
<IfModule mod_weblogic.c>
Include conf/weblogic.conf
</IfModule>
conf/weblogic.conf:
<IfModule mod_weblogic.c>
WeblogicCluster wls1:8001,wls2:8001
MatchExpression *.jsp
MatchExpression *.do
</IfModule>
<IfModule mod_weblogic.c>
Include conf/weblogic.conf
</IfModule>
conf/weblogic.conf:
<IfModule mod_weblogic.c>
WeblogicCluster wls1:8001,wls2:8001
MatchExpression *.jsp
MatchExpression *.do
</IfModule>
re: [原創]國內大部分的USBKey通過B/S方式(CAPICOM)產生數字簽名的嚴重安全漏洞 david.turing 2006-12-05 20:30
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
你說對了,但我的工作是要客戶認為這足夠安全,并且讓
客戶認為(他們會找第三方公司對SecureX的客戶端源代碼
進行核實,然后才部署),這樣會相對安全很多。
-----BEGIN PGP SIGNATURE-----
Version: PGP Desktop 9.0.5 - Enterprise license
Comment: http://www.pgp.org.cn
iQA/AwUBRXVmn02j31FcBpdPEQJLoQCfbWlFvBJ6jpOxIpjR/4PU1bzOHfAAoMr9
BQyMQ7d7qfMetMZbqUbGruAT
=FEqC
-----END PGP SIGNATURE-----
re: 如何用腳本快速修改IP地址(Netsh) david.turing 2006-11-27 20:23
使用dhcp自動分配ip的快捷netsh命令:
netsh interface ip set address name="本地連接" source=dhcp
netsh interface ip set address name="本地連接" source=dhcp
re: SecureX Eclipse Plugin Alpha2發布 david.turing 2006-11-17 16:43
圖形化的Keytool工具
re: 將郵件與PGP綁定,建立安全身份認證基礎 david.turing 2006-11-13 16:40
你們要Update Key到MIT的KeyServer阿
re: [原創]國內大部分的USBKey通過B/S方式(CAPICOM)產生數字簽名的嚴重安全漏洞 david.turing 2006-11-13 14:52
該頁面可以放在信任站點的任何路徑上,然后直接調用客戶端的Capicom產生簽名,神不知鬼不覺。
測試頁面可見于:
http://securex.sourceforge.net/testusb/SilentSign.htm
1,把securex.sourceforge.net設置成信任站點(目前很多項目都是這樣做的)
2,訪問上面的頁面,然后看看html源代碼
測試頁面可見于:
http://securex.sourceforge.net/testusb/SilentSign.htm
1,把securex.sourceforge.net設置成信任站點(目前很多項目都是這樣做的)
2,訪問上面的頁面,然后看看html源代碼
re: 安裝SecureX david.turing 2006-11-09 18:24
沒有用Birt阿,你能否詳細一些,因為我立即就要發布alpha2了(支持向導方式創建CA證書/KeyPair),希望修正一些Bug
re: [轉載]推薦一下CSDN《程序員》的《開源大本營》 david.turing 2006-11-08 16:09
你沒看到我的字眼——“僅僅”
re: [原創]實施WebService Security[WS-Security1.0]的Encrypt和Sign模式(XFire+WSS4J) david.turing 2006-10-27 12:53
Debug一下,我在SpringSide2提供了一個測試的使用類,去借鑒一下?
re: [原創] SSO(Single Sign-on) in Action(上篇) david.turing 2006-10-27 09:12
看mailist是嘗試支持,但目前我拿到的Dev版本還沒有支持。
估計應該是在一個版本提供吧:)
估計應該是在一個版本提供吧:)
re: Infragistics的JSF組件 david.turing 2006-10-27 08:19
老大,我準備買你的書哇:)
re: Weblogic download url記載 david.turing 2006-10-12 12:11
Weblogic portal 9.2 download
http://download2.bea.com/pub/platform/92/portal920_win32.exe
http://download2.bea.com/pub/platform/92/portal920_win32.exe
re: BEA廣州UserGroup招募Speaker david.turing 2006-10-11 18:21
成都真好玩, 我玩了兩天才回去.
非常感謝Ray.yu和菠菜作我的導游....
非常感謝Ray.yu和菠菜作我的導游....
re: 靈感之源的Guardio/Defendio究竟值多少錢? david.turing 2006-10-11 18:19
Will safe360/guardio be an opensource?
hope so, but......
hope so, but......
re: BEA廣州UserGroup招募Speaker david.turing 2006-10-09 19:43
BEA UserGroup主要是分享心得和經驗,作為Speaker,需要做一些精彩的Demo和寫一些PPT,現場演示給聽眾。
UserGroup全球有50多個,中國有8個,大家對一些J2EE技術/框架/理念有新的并且希望分享都可以聯系我。
http://dev2dev.bea.com.cn/bbs/index.jspa
UserGroup全球有50多個,中國有8個,大家對一些J2EE技術/框架/理念有新的并且希望分享都可以聯系我。
http://dev2dev.bea.com.cn/bbs/index.jspa
re: [原創] SSO(Single Sign-on) in Action(上篇) david.turing 2006-10-09 10:05