6.3.3 实现
在Java 6中,MessageDigest类支持MD算法的同时也支持SHA算法,几乎涵盖了我们目前所知的全部SHA系列算法,主要包含SHA-1、SHA-256、SHA-384和SHA-512四种算法。通过第三方加密组件包Bouncy Castle(详见本书附录),可支持SHA-224算法。
SHA系列算法支持如表6-2所示。
1.Sun
在Java 6中,“SHA”是“SHA-1”的简称,两种算法名称等同。如果要使用SHA-1算法对数据做消息摘要,可参考如下代码:
//初始化MessageDigest,并指定SHA算法
MessageDigest md=MessageDigest.getInstance("SHA");
//摘要处理
byte[]b=md.digest(data);
在上述代码中,data[]为待做消息摘要处理的数据,b[]是经过消息摘要处理后的摘要信息。
Java 6支持SHA-1、SHA-256、SHA-384和SHA-512四种算法,实现方式如代码清单6-7所示。
代码清单6-7 SHA算法实现1
import java.security.MessageDigest;
/**
*SHA消息摘要组件
*@author梁栋
*@version 1.0
*@since 1.0
*/
public abstract class SHACoder{
/**
*SHA-1消息摘要
*@param data待做摘要处理的数据
*@return byte[]消息摘要
*@throws Exception
*/
public static byte[]encodeSHA(byte[]data)throws Exception{
//初始化MessageDigest
MessageDigest md=MessageDigest.getInstance("SHA");
//执行消息摘要
return md.digest(data);
}
/**
*SHA-256消息摘要
*@param data待做摘要处理的数据
*@return byte[]消息摘要
*@throws Exception
*/
public static byte[]encodeSHA256(byte[]data)throws Exception{
//初始化MessageDigest
MessageDigest md=MessageDigest.getInstance("SHA-256");
//执行消息摘要
return md.digest(data);
}
/**
*SHA-384消息摘要
*@param data待做摘要处理的数据
*@return byte[]消息摘要
*@throws Exception
*/
public static byte[]encodeSHA384(byte[]data)throws Exception{
//初始化MessageDigest
MessageDigest md=MessageDigest.getInstance("SHA-384");
//执行消息摘要
return md.digest(data);
}
/**
*SHA-512消息摘要
*@param data待做摘要处理的数据
*@return byte[]消息摘要
*@throws Exception
*/
public static byte[]encodeSHA512(byte[]data)throws Exception{
//初始化MessageDigest
MessageDigest md=MessageDigest.getInstance("SHA-512");
//执行消息摘要
return md.digest(data);
}
}
对上述代码做测试用例,如代码清单6-8所示。
代码清单6-8 SHA算法实现1测试用例
import static org.junit.Assert.*;
import org.junit.Test;
/**
*SHA校验
*@author梁栋
*@version 1.0
*@since 1.0
*/
public class SHACoderTest{
/**
*测试SHA-1
*@throws Exception
*/
@Test
public final void testEncodeSHA()throws Exception{
String str="SHA1消息摘要";
//获得摘要信息
byte[]data1=SHACoder.encodeSHA(str.getBytes());
byte[]data2=SHACoder.encodeSHA(str.getBytes());
//校验
assertArrayEquals(data1,data2);
}
/**
*测试SHA-256
*@throws Exception
*/
@Test
public final void testEncodeSHA256()throws Exception{
String str="SHA256消息摘要";
//获得摘要信息
byte[]data1=SHACoder.encodeSHA256(str.getBytes());
byte[]data2=SHACoder.encodeSHA256(str.getBytes());
//校验
assertArrayEquals(data1,data2);
}
/**
*测试SHA-384
*@throws Exception
*/
@Test
public final void testEncodeSHA384()throws Exception{
String str="SHA384消息摘要";
//获得摘要信息
byte[]data1=SHACoder.encodeSHA384(str.getBytes());
byte[]data2=SHACoder.encodeSHA384(str.getBytes());
//校验
assertArrayEquals(data1,data2);
}
/**
*测试SHA-512
*@throws Exception
*/
@Test
public final void testEncodeSHA512()throws Exception{
String str="SHA512消息摘要";
//获得摘要信息
byte[]data1=SHACoder.encodeSHA512(str.getBytes());
byte[]data2=SHACoder.encodeSHA512(str.getBytes());
//校验
assertArrayEquals(data1,data2);
}
}
作者和读者朋友一定都会这样想:如果能增加十六进制转换的方法,那就更加方便了!
2.Bouncy Castle
Bouncy Castle不仅支持MD4算法,同时也支持SHA-224算法。
比较简单的实现方式如下所示:
import java.security.Security;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
//加入BouncyCastleProvider支持
Security.addProvider(new BouncyCastleProvider());
//初始化MessageDigest
MessageDigest md=MessageDigest.getInstance("SHA-224");
有关第三方加密组件包Bouncy Castle,读者可参考第3章和第4章相关内容。
对于SHA算法,我们仅仅需要补充SHA-244算法实现,如代码清单6-9所示。
代码清单6-9 SHA224算法实现
import java.security.MessageDigest;
import java.security.Security;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;
/**
*SHA-224消息摘要组件
*@author梁栋
*@version 1.0
*@since 1.0
*/
public abstract class SHA224Coder{
/**
*SHA-224消息摘要
*@param data待做摘要处理的数据
*@return byte[]消息摘要
*@throws Exception
*/
public static byte[]encodeSHA224(byte[]data)throws Exception{
//加入BouncyCastleProvider支持
Security.addProvider(new BouncyCastleProvider());
//初始化MessageDigest
MessageDigest md=MessageDigest.getInstance("SHA-224");
//执行消息摘要
return md.digest(data);
}
/**
*SHA-224消息摘要
*@param data待做摘要处理的数据
*@return String十六进制消息摘要
*@throws Exception
*/
public static String encodeSHA224Hex(byte[]data)throws Exception{
//执行消息摘要
byte[]b=encodeSHA224(data);
//做十六进制编码处理
return new String(Hex.encode(b));
}
}
对于上述实现做测试用例也相当简单,如代码清单6-10所示。
代码清单6-10 SHA224算法实现测试用例
import static org.junit.Assert.*;
import org.junit.Test;
/**
*SHA-224校验
*@author梁栋
*@version 1.0
*@since 1.0
*/
public class SHA224CoderTest{
/**
*测试SHA-224
*@throws Exception
*/
@Test
public final void testEncodeSHA224()throws Exception{
String str="SHA224消息摘要";
//获得摘要信息
byte[]data1=SHACoder.encodeSHA224(str.getBytes());
byte[]data2=SHACoder.encodeSHA224(str.getBytes());
//校验
assertArrayEquals(data1,data2);
}
/**
*测试SHA-224
*@throws Exception
*/
@Test
public final void testEncodeSHA224Hex()throws Exception{
String str="SHA224消息摘要";
//获得摘要信息
String data1=SHA224Coder.encodeSHA224Hex(str.getBytes());
String data2=SHA224Coder.encodeSHA224Hex(str.getBytes());
//校验
assertEquals(data1,data2);
}
}
对于其他SHA算法,我们完全可以对其加工,加入十六进制编码转换实现。我们来关注控制台输出的信息,如下所示:
原文:SHA224Hex消息摘要
SHA224Hex-1:fd0c016cc823d094aafc4d64665837df8ffa1d1712f58e5c44fd20d2
SHA224Hex-2:fd0c016cc823d094aafc4d64665837df8ffa1d1712f58e5c44fd20d2
在上述内容中,我们得到了28位的摘要信息,换算成二进制正好是224位。
3.Commons Codec
DigestUtils类除了MD5算法外,还支持多种SHA系列算法,涵盖了Java 6所支持的全部SHA算法。有关DigestUtils类相关SHA算法支持API,读者可阅读第4章内容。
Commons Codec与Sun所提供的SHA算法实现在本质上毫无差别,关键在于Commons Codec提供了更为方便的实现。我们对上述SHA算法实现做了调整,相关实现如代码清单6-11所示。
代码清单6-11 SHA算法实现2
import org.apache.commons.codec.digest.DigestUtils;
/**
*SHA消息摘要组件
*@author梁栋
*@version 1.0
*@since 1.0
*/
public abstract class SHACoder{
/**
*SHA消息摘要
*@param data待做摘要处理的数据
*@return byte[]消息摘要
*@throws Exception
*/
public static byte[]encodeSHA(String data)throws Exception{
//执行消息摘要
return DigestUtils.sha(data);
}
/**
*SHAHex消息摘要
*@param data待做摘要处理的数据
*@return String消息摘要
*@throws Exception
*/
public static String encodeSHAHex(String data)throws Exception{
//执行消息摘要
return DigestUtils.shaHex(data);
}
/**
*SHA256消息摘要
*@param data待做摘要处理的数据
*@return byte[]消息摘要
*@throws Exception
*/
public static byte[]encodeSHA256(String data)throws Exception{
//执行消息摘要
return DigestUtils.sha256(data);
}
/**
*SHA256Hex消息摘要
*@param data待做摘要处理的数据
*@return String消息摘要
*@throws Exception
*/
public static String encodeSHA256Hex(String data)throws Exception{
//执行消息摘要
return DigestUtils.sha256Hex(data);
}
/**
*SHA384消息摘要
*@param data待做摘要处理的数据
*@return byte[]消息摘要
*@throws Exception
*/
public static byte[]encodeSHA384(String data)throws Exception{
//执行消息摘要
return DigestUtils.sha384(data);
}
/**
*SHA384Hex消息摘要
*@param data待做摘要处理的数据
*@return String消息摘要
*@throws Exception
*/
public static String encodeSHA384Hex(String data)throws Exception{
//执行消息摘要
return DigestUtils.sha384Hex(data);
}
/**
*SHA512Hex消息摘要
*@param data待做摘要处理的数据
*@return byte[]消息摘要
*@throws Exception
*/
public static byte[]encodeSHA512(String data)throws Exception{
//执行消息摘要
return DigestUtils.sha512(data);
}
/**
*SHA512Hex消息摘要
*@param data待做摘要处理的数据
*@return String消息摘要
*@throws Exception
*/
public static String encodeSHA512Hex(String data)throws Exception{
//执行消息摘要
return DigestUtils.sha512Hex(data);
}
}
对于上述实现做测试用例,如代码清单6-12所示。
代码清单6-12 SHA算法实现2测试用例
import static org.junit.Assert.*;
import org.junit.Test;
/**
*SHAHex校验
*@author梁栋
*@version 1.0
*@since 1.0
*/
public class SHACoderTest{
/**
*测试SHA-1
*@throws Exception
*/
@Test
public final void testEncodeSHA()throws Exception{
String str="SHA1消息摘要";
//获得摘要信息
byte[]data1=SHACoder.encodeSHA(str);
byte[]data2=SHACoder.encodeSHA(str);
//校验
assertArrayEquals(data1,data2);
}
/**
*测试SHA-1Hex
*@throws Exception
*/
@Test
public final void testEncodeSHAHex()throws Exception{
String str="SHA-1Hex消息摘要";
//获得摘要信息
String data1=SHACoder.encodeSHAHex(str);
String data2=SHACoder.encodeSHAHex(str);
System.err.println("原文:\t"+str);
System.err.println("SHA1Hex-1:\t"+data1);
System.err.println("SHA1Hex-2:\t"+data2);
//校验
assertEquals(data1,data2);
}
/**
*测试SHA-256
*@throws Exception
*/
@Test
public final void testEncodeSHA256()throws Exception{
String str="SHA256消息摘要";
//获得摘要信息
byte[]data1=SHACoder.encodeSHA256(str);
byte[]data2=SHACoder.encodeSHA256(str);
//校验
assertArrayEquals(data1,data2);
}
/**
*测试SHA-256Hex
*@throws Exception
*/
@Test
public final void testEncodeSHA256Hex()throws Exception{
String str="SHA256Hex消息摘要";
//获得摘要信息
String data1=SHACoder.encodeSHA256Hex(str);
String data2=SHACoder.encodeSHA256Hex(str);
System.err.println("原文:\t"+str);
System.err.println("SHA256Hex-1:\t"+data1);
System.err.println("SHA256Hex-2:\t"+data2);
//校验
assertEquals(data1,data2);
}
/**
*测试SHA-384
*@throws Exception
*/
@Test
public final void testEncodeSHA384()throws Exception{
String str="SHA384消息摘要";
//获得摘要信息
byte[]data1=SHACoder.encodeSHA384(str);
byte[]data2=SHACoder.encodeSHA384(str);
//校验
assertArrayEquals(data1,data2);
}
/**
*测试SHA-384Hex
*@throws Exception
*/
@Test
public final void testEncodeSHA384Hex()throws Exception{
String str="SHA384Hex消息摘要";
//获得摘要信息
String data1=SHACoder.encodeSHA384Hex(str);
String data2=SHACoder.encodeSHA384Hex(str);
System.err.println("原文:\t"+str);
System.err.println("SHA384Hex-1:\t"+data1);
System.err.println("SHA384Hex-2:\t"+data2);
//校验
assertEquals(data1,data2);
}
/**
*测试SHA-512
*@throws Exception
*/
@Test
public final void testEncodeSHA512()throws Exception{
String str="SHA512消息摘要";
//获得摘要信息
byte[]data1=SHACoder.encodeSHA512(str);
byte[]data2=SHACoder.encodeSHA512(str);
//校验
assertArrayEquals(data1,data2);
}
/**
*测试SHA-512Hex
*@throws Exception
*/
@Test
public final void testEncodeSHA512Hex()throws Exception{
String str="SHA512Hex消息摘要";
//获得摘要信息
String data1=SHACoder.encodeSHA512Hex(str);
String data2=SHACoder.encodeSHA512Hex(str);
System.err.println("原文:\t"+str);
System.err.println("SHA512Hex-1:\t"+data1);
System.err.println("SHA512Hex-2:\t"+data2);
//校验
assertEquals(data1,data2);
}
}
在控制台中,我们可以清晰地观察到4种SHA算法的摘要信息长度有所不同。
❑SHA-1
原文:SHA-1Hex消息摘要
SHA1Hex-1:9a4135598d12e61f54d5d790887cf47721cbdd2c
SHA1Hex-2:9a4135598d12e61f54d5d790887cf47721cbdd2c
SHA-1算法的摘要信息是一个40位的十六进制字符串,换算成二进制正好是160位。
❑SHA-256
原文:SHA256Hex消息摘要
SHA256Hex-1:e001852cd945459a14ecd83ec3f9c73b94e02ec12ec8afbf764a98719acce777 SHA256Hex-2:
e001852cd945459a14ecd83ec3f9c73b94e02ec12ec8afbf764a98719acce777
SHA-256算法的摘要信息是一个64位的十六进制字符串,换算成二进制正好是256位。
❑SHA-384和SHA-512
原文:SHA384Hex消息摘要
SHA384Hex-1:
13d87b76ee7a14fcbb7d96c90ed430b8793cdd75afa10700a402ebdce463a29302ce36b19db4f30f e170399897f191ed
SHA384Hex-2:
13d87b76ee7a14fcbb7d96c90ed430b8793cdd75afa10700a402ebdce463a29302ce36b19db4f30f e170399897f191ed
原文:SHA512Hex消息摘要
SHA512Hex-1:
0ecc3742f5ca400c78f84d4bf37a7e34aff371f879d773cab40fe1cd4cb19b6cf2bc598e4bc5a384
808b9b15ef19ff59db4793f0f6b3815bdfd6152208e26756
SHA512Hex-2:
0ecc3742f5ca400c78f84d4bf37a7e34aff371f879d773cab40fe1cd4cb19b6cf2bc598e4bc5a384
808b9b15ef19ff59db4793f0f6b3815bdfd6152208e26756
很显然,SHA-384和SHA-512算法的摘要信息没有任何悬念,分别对应384位和512位的二进制数。
消息摘要长度与安全强度成正比。从这一点来说,SHA系列算法比MD系列算法更具优势。MD系列算法仅有128位,而SHA算法则可以从160位扩充到512位,更具安全性。
4.三种实现方式的差异
三种实现方式以Sun提供的实现为基础,在算法支持上和方法易用性上提供了更好的扩展与支持。
❑Sun
由于Sun提供了较为底层的SHA算法实现,如SHA-1、SHA-256、SHA-384和SHA-512四种算法,但缺少了对应的进制转换实现,多少有些遗憾。
❑Bouncy Castle
Bouncy Castle是对Sun的友善补充,提供了对SHA-224算法的支持,支持十六进制字符串形式的摘要信息,相当方便。
❑Commons Codec
Commons Codec对Sun提供的SHA算法做了包装,支持多种形式的参数,支持十六进制字符串形式的摘要信息,相当方便。
综上所述,若在应用中使用SHA系列算法,且不要求对SHA-224算法提供支持,Commons Codec是更为合适的选择。如果只是需要在Sun原有SHA系列算法支持的基础上加入十六进制编码转换,Bouncy Castle和Commons Codec都是不错的选择。