Posted on 2008-05-08 15:02
寒武紀(jì) 閱讀(6541)
評(píng)論(2) 編輯 收藏 所屬分類:
信息安全
剛好最近項(xiàng)目中需要用到一點(diǎn)加密的東西,java安全類庫(kù)提供了一個(gè)java.security.MessageDigest類,此 MessageDigest 類為應(yīng)用程序提供信息摘要算法的功能,如 MD5 或 SHA 算法。信息摘要是安全的單向哈希函數(shù),它接收任意大小的數(shù)據(jù),并輸出固定長(zhǎng)度的哈希值。有現(xiàn)成的當(dāng)然是最好的,省事省力。
MD5的非常有實(shí)際應(yīng)用性。有網(wǎng)友給出這樣的描述,可以參照一下:http://blog.csdn.net/Daping_Zhang/archive/2005/05/28/382688.aspx
該類的getInstance(String algorithm)
方法返回一個(gè)MessageDigest的實(shí)體,加密的一系統(tǒng)的digest()
方法和update(byte input)方法。加密后返回一個(gè)byte[],16位,我們經(jīng)常見到很多開源網(wǎng)站的下載地址會(huì)有一個(gè)[md5]的鏈接,打開其實(shí)就是一小段文本內(nèi)容。例如:
MD5 (commons-logging-1.1.1-bin.zip) = f88520ed791673aed6cc4591bc058b55
這是Jakarta的logging組件下載時(shí)提供的MD5摘要信息,是對(duì)這個(gè)zip包進(jìn)行全文加密生成的摘要,摘要碼就是后面的f88520ed791673aed6cc4591bc058b55,如果你下載以后,按照MD5的算法生成自己的摘要,如果這二個(gè)摘要一樣,就證明這個(gè)文件是沒有被人篡改過的。
遇到的問題是Java的MessageDigest類執(zhí)行后返回的byte[16]得轉(zhuǎn)換成十六進(jìn)制的字符串,如果直接用new String(byte[]),得到的結(jié)果將是不正確的。算法有很多網(wǎng)友提供了,照搬了。比較有趣的是,commons-logging提供的那個(gè)MD5居然和我自己生成的不一樣(難道文件被修改過?),后來嘗試了其它地方提供的MD5碼,都沒有問題。
有很多相關(guān)的現(xiàn)成代碼,搜集了一下整理如下(經(jīng)過驗(yàn)證):

public class MD5Builder
{

static Logger logger = Logger.getLogger(MD5Builder.class);
// 用來將字節(jié)轉(zhuǎn)換成 16 進(jìn)制表示的字符

static char hexDigits[] =
{ '0', '1', '2', '3', '4', '5', '6', '7', '8',
'9', 'a', 'b', 'c', 'd', 'e', 'f' };

/** *//**
* 對(duì)文件全文生成MD5摘要
* @param file 要加密的文件
* @return MD5摘要碼
*/

public static String getMD5(File file)
{
FileInputStream fis = null;

try
{
MessageDigest md = MessageDigest.getInstance("MD5");

logger.info("MD5摘要長(zhǎng)度:" + md.getDigestLength());
fis = new FileInputStream(file);
byte[] buffer = new byte[2048];
int length = -1;
logger.info("開始生成摘要");
long s = System.currentTimeMillis();

while ((length = fis.read(buffer)) != -1)
{
md.update(buffer, 0, length);
}
logger.info("摘要生成成功,總用時(shí): "
+ (System.currentTimeMillis() - s) + "ms");
byte[] b = md.digest();
return byteToHexString(b);
// 16位加密
// return buf.toString().substring(8, 24);

} catch (Exception ex)
{
logger.error(ex);
ex.printStackTrace();
return null;

}finally
{

try
{
fis.close();

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


/** *//**
* 對(duì)一段String生成MD5加密信息
* @param message 要加密的String
* @return 生成的MD5信息
*/

public static String getMD5(String message)
{

try
{
MessageDigest md = MessageDigest.getInstance("MD5");
logger.info("MD5摘要長(zhǎng)度:" + md.getDigestLength());
byte[] b = md.digest(message.getBytes());
return byteToHexString(b);

} catch (NoSuchAlgorithmException e)
{
logger.error(e);
e.printStackTrace();
return null;
}
}

/** *//**
* 把byte[]數(shù)組轉(zhuǎn)換成十六進(jìn)制字符串表示形式
* @param tmp 要轉(zhuǎn)換的byte[]
* @return 十六進(jìn)制字符串表示形式
*/

private static String byteToHexString(byte[] tmp)
{
String s;
// 用字節(jié)表示就是 16 個(gè)字節(jié)
char str[] = new char[16 * 2]; // 每個(gè)字節(jié)用 16 進(jìn)制表示的話,使用兩個(gè)字符,
// 所以表示成 16 進(jìn)制需要 32 個(gè)字符
int k = 0; // 表示轉(zhuǎn)換結(jié)果中對(duì)應(yīng)的字符位置

for (int i = 0; i < 16; i++)
{ // 從第一個(gè)字節(jié)開始,對(duì) MD5 的每一個(gè)字節(jié)
// 轉(zhuǎn)換成 16 進(jìn)制字符的轉(zhuǎn)換
byte byte0 = tmp[i]; // 取第 i 個(gè)字節(jié)
str[k++] = hexDigits[byte0 >>> 4 & 0xf]; // 取字節(jié)中高 4 位的數(shù)字轉(zhuǎn)換,
// >>> 為邏輯右移,將符號(hào)位一起右移
str[k++] = hexDigits[byte0 & 0xf]; // 取字節(jié)中低 4 位的數(shù)字轉(zhuǎn)換
}
s = new String(str); // 換后的結(jié)果轉(zhuǎn)換為字符串
return s;
}
}
剛進(jìn)場(chǎng)的時(shí)候戲就落幕