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