3.2.3 MessageDigest

MessageDigest类实现了消息摘要算法,它继承于MessageDigestSpi类,是Java安全提供者体系结构中最为简单的一个引擎类。在本章后续的内容中,我们还将看到更多引擎类。


//实现创建和验证消息摘要的操作。

public abstract class MessageDigest

extends MessageDigestSpi


在Java API的列表中,我们总能看到后缀名带有SPI(Service Provider Interface,服务提供者接口)的类,它们总是与引擎类形影不离。例如MessageDigestSpi类是MessageDigest类的服务提供者接口。如果要实现自定义的消息摘要算法,则需要提供继承于MessageDigestSpi类的子类实现。MessageDigest类自然是Sun提供给我们的一个很好的用于实现自定义算法的范例。在其他引擎类的实现中(除签名算法类Signature类以外),不再继承相对应的SPI类。本书以Java 6所提供的算法为准,不计划介绍如何实现自定义算法。如果读者对SPI类有兴趣,可参照Java API中的相应内容。

❑方法详述

我们可以通过以下方法获得MessageDigest类的实例:


//返回实现指定摘要算法的MessageDigest对象。

public static MessageDigest getInstance(String algorithm)

//返回实现指定摘要算法的MessageDigest对象。

public static MessageDigest getInstance(String algorithm, Provider provider)

//返回实现指定摘要算法的MessageDigest对象。

public static MessageDigest getInstance(String algorithm, String provider)


目前Java 6支持MD2、MD5、SHA-1(SHA)、SHA-256、SHA-384、SHA-512六种消息摘要算法,算法名不区分大小写。

在本书后续的内容中,诸如上述的算法提供者参数(参数Provider provider或参数String provider)会有很多,其值可以为new com.sun.crypto.provider.SunJCE()或"SunJCE"。当使用第三方安全提供者时,需指明provider参数。如果使用BouncyCastleProvider,其值必须为new org.bouncycastle.jce.provider.BouncyCastleProvider()或"BC"。当然,使用第三方安全提供者的前提是需要配置%JDK_HOME%\jre\lib\security\java.security文件。相关内容请参见3.2.1节。

在获得MessageDigest实例化对象后,我们可以利用以下方法对此对象进行操作:

//使用指定的字节更新摘要。


public void update(byte input)

//使用指定的字节数组更新摘要。

public void update(byte[]input)


上述方法参数不同,一个是更新单字节,一个是更新字节数组。

我们也可以使用如下方法,根据偏移量更新摘要:


//使用指定的字节数组,从指定的偏移量开始更新摘要。

public void update(byte[]input, int offset, int len)


当然,我们也可以使用缓冲模式更新摘要,可使用如下方法:


//使用指定的字节缓冲更新摘要。

public void update(ByteBuffer input)


更新摘要信息,其参数可以是更新一个字节、一个字节数组,甚至是字节数组中的某一段偏移量,也可以是字节缓冲对象。

这些方法的调用顺序不受限制,在向摘要中增加所需数据时可以多次调用。

在完成摘要更新后,我们可以通过以下方法完成摘要操作:


//通过执行诸如填充之类的最终操作完成摘要计算,返回消息摘要字节数组。

public byte[]digest()


作者通常会选择上述方法完成摘要处理,也就是在调用上述方法前使用update()方法完成摘要更新后直接使用digest()方法。如果我们只需要执行一次update()方法,不如考虑在digest()方法中直接传入待摘要信息,也就是直接使用如下方法:


/使用指定的字节数组对摘要进行最后更新,然后完成摘要计算,返回消息摘要字节数组。/

public byte[]digest(byte[]input)

/通过执行诸如填充之类的最终操作完成摘要计算,将消息摘要结果按照指定的偏移量存放在字节数组中,返回消息摘要的长度。/

public int digest(byte[]buf, int offset, int len)


完成摘要操作后,可以通过以下方法对比两个摘要信息:


//比较两个摘要的相等性。

public static boolean isEqual(byte[]digesta, byte[]digestb)


当两个摘要中的每个字节都相同,且两个摘要都有相同的长度时,则认为两个摘要相同。


//重置摘要以供再次使用。

public void reset()


执行该重置方法等同于创建一个新的MessageDigest实例化对象。

我们完成了摘要处理,获得了摘要信息,也就能够获得摘要信息的长度,如果需要这样的长度信息,可以使用如下方法:


/返回以字节为单位的摘要长度,如果提供者不支持此操作并且实现是不可复制的,则返回0。/

public final int getDigestLength()


除了上述方法外,还常用到以下几个方法:


//返回算法名称,如MD5。

public final String getAlgorithm()

//返回此信息摘要对象的提供者。

public final Provider getProvider()


MessageDigest类覆盖了Object的如下方法:


//返回此信息摘要对象的字符串表示形式。

public String toString()

//如果实现是可复制的,则返回一个副本。

Object clone()


❑实现示例

我们来做一个简单的摘要处理,如代码清单3-2所示。

代码清单3-2 SHA算法摘要处理


//待做消息摘要算法的原始信息。

byte[]input="sha".getBytes();

//初始化MessageDigest对象,将使用SHA算法。

MessageDigest sha=MessageDigest.getInstance("SHA");

//更新摘要信息。

sha.update(input);

//获取消息摘要结果。

byte[]output=sha.digest();


关于消息摘要算法的实现

MessageDigest、DigestInputStream、DigestOutputStream、Mac均是消息认证技术的引擎类。MessageDigest提供核心的消息摘要实现;DigestInputStream、DigestOutputStream提供以MessageDigest为核心的消息摘要流实现;Mac提供基于秘密密钥的安全消息摘要实现。Mac与MessageDigest无任何依赖关系。

除了MessageDigest类提供的MD和SHA两大类算法外,我们知道还有一种摘要算法—Mac,它的算法实现是通过Mac类(javax.crypto.Mac)来实现的,具体Java API内容请参见下一节内容。