Java 加密技術(shù):消息摘要。
一個(gè)消息摘要就是一個(gè)數(shù)據(jù)塊的數(shù)字指紋。即對(duì)一個(gè)任意長(zhǎng)度的一個(gè)數(shù)據(jù)塊進(jìn)行計(jì)算,產(chǎn)生一個(gè)唯一指印(對(duì)于SHA1是產(chǎn)生一個(gè)20字節(jié)的二進(jìn)制數(shù)組)。
消息摘要有兩個(gè)基本屬性:
兩個(gè)不同的報(bào)文難以生成相同的摘要
難以對(duì)指定的摘要生成一個(gè)報(bào)文,而由該報(bào)文反推算出該指定的摘要
代表:美國(guó)國(guó)家標(biāo)準(zhǔn)技術(shù)研究所的SHA1和麻省理工學(xué)院Ronald Rivest提出的MD5
類 java.security.MessageDigest
java.lang.Object | +----java.security.MessageDigest
- public abstract class MessageDigest
- extends Object
MessageDigest 提供了消息摘要算法,如 MD5 或 SHA,的功能。消息摘要是安全單向散列函數(shù),它采用任意大小的數(shù)據(jù)并輸出一個(gè)固定長(zhǎng)度的散列值。
象 Java 安全性中的其它基于算法的類一樣,MessageDigest 有兩個(gè)主要的組件:
- 消息摘要 API ( 應(yīng)用程序接口 )
- 這是需要消息摘要服務(wù)的應(yīng)用調(diào)用的方法的接口。這個(gè) API 由所有公有方法組成。
- 消息摘要 SPI ( 服務(wù)提供者接口 )
- 該接口是由提供特殊算法的提供者實(shí)現(xiàn)的接口。它由所有名字前綴為 engine 的方法組成。每個(gè)這樣的方法由具有相應(yīng)名字的公有 API 方法調(diào)用。例如,
engineReset
方法由reset
方法調(diào)用。SPI 方法是抽象的;提供者必須提供一個(gè)具體的實(shí)現(xiàn)。
MessageDigest 對(duì)象在啟動(dòng)時(shí)被初始化。使用 update 方法處理數(shù)據(jù)。在任何地方都可調(diào)用 reset 復(fù)位摘要。一旦所有需要修改的數(shù)據(jù)都被修改了,將調(diào)用一個(gè) digest 方法完成散列碼的計(jì)算。
對(duì)于給定次數(shù)的修改,只能調(diào)用 digest
方法一次。在調(diào)用 digest
之后,MessageDigest 對(duì)象被復(fù)位為初始化的狀態(tài)。
可以自由的實(shí)現(xiàn) Cloneable 接口,這樣做將會(huì)使客戶應(yīng)用在復(fù)制前用 instanceof Cloneable
測(cè)試可復(fù)制性:
MessageDigest md = MessageDigest.getInstance("SHA"); if (md instanceof Cloneable) { md.update(toChapter1); MessageDigest tc1 = md.clone(); byte[] toChapter1Digest = tc1.digest; md.update(toChapter2); ...etc. } else { throw new DigestException("couldn't make digest of partial content"); }
注意如果給定的實(shí)現(xiàn)是不可復(fù)制的,如果事先知道摘要的數(shù)目,仍然能以幾個(gè)實(shí)例為例計(jì)算中間的摘要。
構(gòu)造子
MessageDigest
protected MessageDigest(String algorithm)
- 用指定的算法名創(chuàng)建一個(gè)消息摘要。
- 參數(shù):
- algorithm - 摘要算法的標(biāo)準(zhǔn)字符串名。 Java 密碼結(jié)構(gòu) API 說(shuō)明書(shū) & 參考 的附錄 A。 -->
方法
getInstance
public static MessageDigest getInstance(String algorithm) throws NoSuchAlgorithmException
- 生成一個(gè) MessageDigest 對(duì)象,它實(shí)現(xiàn)指定的摘要算法。 如果缺省的提供者包包含一個(gè)實(shí)現(xiàn)了該算法 MessageDigest 子類,則返回該子類的一個(gè)實(shí)例。如果算法在缺省包中是不可用的,將搜索其它的包。
- 參數(shù):
- algorithm - 申請(qǐng)的算法名。 Java 密碼結(jié)構(gòu) API 說(shuō)明書(shū) & 參考 的附錄 A。 -->
- 返回值:
- 一個(gè)實(shí)現(xiàn)指定算法的 Message Digest 對(duì)象。
- 拋出: NoSuchAlgorithmException
- 如果算法在調(diào)用者環(huán)境中是不可用的。
getInstance
public static MessageDigest getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, NoSuchProviderException
- 生成一個(gè) MessageDigest 對(duì)象,實(shí)現(xiàn)指定的算法,如果提供者的算法是可用的,那么該算法由該提供者提供。
- 參數(shù):
- algorithm - 申請(qǐng)的算法名。 Java 密碼結(jié)構(gòu) API 說(shuō)明書(shū) & 參考 的附錄 A。 -->
- provider - 提供者的名字。
- 返回值:
- 一個(gè)實(shí)現(xiàn)指定算法的 Message Digest 對(duì)象。
- 拋出: NoSuchAlgorithmException
- 如果算法在申請(qǐng)的調(diào)用者提供的包中是不可用的。
- 拋出: NoSuchProviderException
- 如果提供者在環(huán)境中是不可用的。
- 參見(jiàn):
- Provider
update
public void update(byte input)
- 用指定的字節(jié)修改該摘要。
- 參數(shù):
- input - 用于修改摘要的字節(jié)。
update
public void update(byte input[], int offset, int len)
- 從數(shù)組指定的偏移量開(kāi)始,用指定的字節(jié)數(shù)組修改摘要。
- 參數(shù):
- input - 該字節(jié)數(shù)組。
- offset - 字節(jié)數(shù)組中開(kāi)始的偏移量。
- len - 從
offset
開(kāi)始用的字節(jié)數(shù)。 - offset - 字節(jié)數(shù)組中開(kāi)始的偏移量。
update
public void update(byte input[])
- 用指定的字節(jié)數(shù)組修改該摘要。
- 參數(shù):
- input - 該字節(jié)數(shù)組。
digest
public byte[] digest()
- 通過(guò)執(zhí)行最后的諸如填充的操作完成散列碼的計(jì)算。 在調(diào)用之后復(fù)位該摘要。
- 返回值:
- 存放結(jié)果散列值的字節(jié)數(shù)組。
digest
public byte[] digest(byte input[])
- 使用指定的字節(jié)數(shù)組執(zhí)行對(duì)摘要最后的修改,然后完成摘要計(jì)算。 即,這個(gè)方法首先對(duì)數(shù)組調(diào)用 update,然后調(diào)用 digest()。
- 參數(shù):
- input - 在摘要計(jì)算完成之前用于修改的輸入值。
- 返回值:
- 結(jié)果散列值的字節(jié)數(shù)組。
toString
public String toString()
isEqual
public static boolean isEqual(byte digesta[], byte digestb[])
- 比較兩個(gè)摘要是否相同。 進(jìn)行簡(jiǎn)單的比較。
- 參數(shù):
- digesta - 要比較的一個(gè)摘要。
- digestb - 要比較的另一個(gè)摘要。
- 返回值:
- 如果兩個(gè)摘要相等則為 true ,否則為 false。
reset
public void reset()
- 為將來(lái)的使用復(fù)位該摘要。
一個(gè)消息摘要就是一個(gè)數(shù)據(jù)塊的數(shù)字指紋。即對(duì)一個(gè)任意長(zhǎng)度的一個(gè)數(shù)據(jù)塊進(jìn)行計(jì)算,產(chǎn)生一個(gè)唯一指印(對(duì)于SHA1是產(chǎn)生一個(gè)20字節(jié)的二進(jìn)制數(shù)組)。
消息摘要有兩個(gè)基本屬性:
兩個(gè)不同的報(bào)文難以生成相同的摘要
難以對(duì)指定的摘要生成一個(gè)報(bào)文,而由該報(bào)文反推算出該指定的摘要
代表:美國(guó)國(guó)家標(biāo)準(zhǔn)技術(shù)研究所的SHA1和麻省理工學(xué)院Ronald Rivest提出的MD5.
消息摘要MD5和SHA的使用
使用方法:
首先用生成一個(gè)MessageDigest類,確定計(jì)算方法
java.security.MessageDigest alga=java.security.MessageDigest.getInstance("SHA-1");
添加要進(jìn)行計(jì)算摘要的信息
alga.update(myinfo.getBytes());
計(jì)算出摘要
byte[] digesta=alga.digest();
發(fā)送給其他人你的信息和摘要
其他人用相同的方法初始化,添加信息,最后進(jìn)行比較摘要是否相同
algb.isEqual(digesta,algb.digest())
相關(guān)AIP
java.security.MessageDigest 類
static getInstance(String algorithm)
返回一個(gè)MessageDigest對(duì)象,它實(shí)現(xiàn)指定的算法
參數(shù):算法名,如 SHA-1 或MD5
void update (byte input)
void update (byte[] input)
void update(byte[] input, int offset, int len)
添加要進(jìn)行計(jì)算摘要的信息
byte[] digest()
完成計(jì)算,返回計(jì)算得到的摘要(對(duì)于MD5是16位,SHA是20位)
void reset()
復(fù)位
static boolean isEqual(byte[] digesta, byte[] digestb)
比效兩個(gè)摘要是否相同
代碼:
import java.security.*;
public class myDigest {
public static void main(String[] args) {
myDigest my = new myDigest();
my.testDigest();
}
public void testDigest() {
try {
String myinfo = "我的測(cè)試信息";
// java.security.MessageDigest
// alg=java.security.MessageDigest.getInstance("MD5");
java.security.MessageDigest alga = java.security.MessageDigest
.getInstance("SHA-1");
alga.update(myinfo.getBytes());
byte[] digesta = alga.digest();
System.out.println("本信息摘要是:" + byte2hex(digesta));
// 通過(guò)某種方式傳給其他人你的信息(myinfo)和摘要(digesta) 對(duì)方可以判斷是否更改或傳輸正常
java.security.MessageDigest algb = java.security.MessageDigest
.getInstance("SHA-1");
algb.update(myinfo.getBytes());
if (algb.isEqual(digesta, algb.digest())) {
System.out.println("信息檢查正常");
} else {
System.out.println("摘要不相同");
}
} catch (java.security.NoSuchAlgorithmException ex) {
System.out.println("非法摘要算法");
}
}
public String byte2hex(byte[] b) // 二行制轉(zhuǎn)字符串
{
String hs = "";
String stmp = "";
for (int n = 0; n < b.length; n++) {
stmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
if (stmp.length() == 1)
hs = hs + "0" + stmp;
else
hs = hs + stmp;
}
return hs.toUpperCase();
}
}
b[n] & 0XFF 的作用是將byte轉(zhuǎn)化為int。
因?yàn)?/span>0xff是整型, byte[] b; b[index] & 0xff 向大的數(shù)據(jù)類型靠攏,就是整型了。
java中的byte 是sign的 ,所以 將一個(gè)負(fù)byte強(qiáng)制轉(zhuǎn)換成int,就會(huì)損壞原來(lái)的binary表示,例如:
byte bb=(byte) 0xf1; //11110001
printBinary((int)bb);//11111111111111111111111111110001
printBinary(bb & 0xff);//00000000000000000000000011110001
運(yùn)行結(jié)果:
int: -15 binary:
11111111111111111111111111110001
int: 241 binary:
00000000000000000000000011110001