6.5.2 实现
Java 6内并没有提供上述算法的实现,这里仅仅是Bouncy Castle的专场。为避免内容冗长,作者在这里以RipeMD系列算法和HmacRipeMD系列算法为例,做简要介绍。
RipeMD系列算法和HmacRipeMD系列算法如表6-4所示。
1.RipeMD系列算法
RipeMD算法的实现具有代表性,Tiger、Whirlpool和GOST3411算法实现与其别无二致。
目前,Bouncy Castle提供了RipeMD128、RipeMD160、RipeMD256和RipeMD320共4种算法实现,代码实现如代码清单6-17所示。
代码清单6-17 RipeMD消息摘要算法实现
import java.security.MessageDigest;
import java.security.Security;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;
/**
*RipeMD系列消息摘要组件
*@author梁栋
*@version 1.0
*@since 1.0
*/
public abstract class RipeMDCoder{
/**
*RipeMD128消息摘要
*@param data待做消息摘要处理的数据
*@return byte[]消息摘要
*@throws Exception
*/
public static byte[]encodeRipeMD128(byte[]data)throws Exception{
//加入BouncyCastleProvider支持
Security.addProvider(new BouncyCastleProvider());
//初始化MessageDigest
MessageDigest md=MessageDigest.getInstance("RipeMD128");
//执行消息摘要
return md.digest(data);
}
/**
*RipeMD128Hex消息摘要
*@param data待做消息摘要处理的数据
*@return byte[]消息摘要
*@throws Exception
*/
public static String encodeRipeMD128Hex(byte[]data)throws Exception{
//执行消息摘要
byte[]b=encodeRipeMD128(data);
//做十六进制编码处理
return new String(Hex.encode(b));
}
/**
*RipeMD160消息摘要
*@param data待做消息摘要处理的数据
*@return byte[]消息摘要
*@throws Exception
*/
public static byte[]encodeRipeMD160(byte[]data)throws Exception{
//加入BouncyCastleProvider支持
Security.addProvider(new BouncyCastleProvider());
//初始化MessageDigest
MessageDigest md=MessageDigest.getInstance("RipeMD160");
//执行消息摘要
return md.digest(data);
}
/**
*RipeMD160Hex消息摘要
*@param data待做消息摘要处理的数据
*@return String消息摘要
*@throws Exception
*/
public static String encodeRipeMD160Hex(byte[]data)throws Exception{
//执行消息摘要
byte[]b=encodeRipeMD160(data);
//做十六进制编码处理
return new String(Hex.encode(b));
}
/**
*RipeMD256消息摘要
*@param data待做消息摘要处理的数据
*@return byte[]消息摘要
*@throws Exception
*/
public static byte[]encodeRipeMD256(byte[]data)throws Exception{
//加入BouncyCastleProvider支持
Security.addProvider(new BouncyCastleProvider());
//初始化MessageDigest
MessageDigest md=MessageDigest.getInstance("RipeMD256");
//执行消息摘要
return md.digest(data);
}
/**
*RipeMD256Hex消息摘要
*@param data待做消息摘要处理的数据
*@return String消息摘要
*@throws Exception
*/
public static String encodeRipeMD256Hex(byte[]data)throws Exception{
//执行消息摘要
byte[]b=encodeRipeMD256(data);
//做十六进制编码处理
return new String(Hex.encode(b));
}
/**
*RipeMD320消息摘要
*@param data待做消息摘要处理的数据
*@return byte[]消息摘要
*@throws Exception
*/
public static byte[]encodeRipeMD320(byte[]data)throws Exception{
//加入BouncyCastleProvider支持
Security.addProvider(new BouncyCastleProvider());
//初始化MessageDigest
MessageDigest md=MessageDigest.getInstance("RipeMD320");
//执行消息摘要
return md.digest(data);
}
/**
*RipeMD320Hex消息摘要
*@param data待做消息摘要处理的数据
*@return String消息摘要
*@throws Exception
*/
public static String encodeRipeMD320Hex(byte[]data)throws Exception{
//执行消息摘要
byte[]b=encodeRipeMD320(data);
//做十六进制编码处理
return new String(Hex.encode(b));
}
}
上述代码对应的测试用例如代码清单6-18所示。
代码清单6-18 RipeMD消息摘要算法实现测试用例
import static org.junit.Assert.*;
import org.junit.Test;
/**
*RipeMD校验
*@author梁栋
*@version 1.0
*@since 1.0
*/
public class RipeMDCoderTest{
/**
*测试RipeMD128
*@throws Exception
*/
@Test
public final void testEncodeRipeMD128()throws Exception{
String str="RipeMD128消息摘要";
//获得摘要信息
byte[]data1=RipeMDCoder.encodeRipeMD128(str.getBytes());
byte[]data2=RipeMDCoder.encodeRipeMD128(str.getBytes());
//校验
assertArrayEquals(data1,data2);
}
/**
*测试RipeMD128Hex
*@throws Exception
*/
@Test
public final void testEncodeRipeMD128Hex()throws Exception{
String str="RipeMD128Hex消息摘要";
//获得摘要信息
String data1=RipeMDCoder.encodeRipeMD128Hex(str.getBytes());
String data2=RipeMDCoder.encodeRipeMD128Hex(str.getBytes());
System.err.println("原文:\t"+str);
System.err.println("RipeMD128Hex-1:\t"+data1);
System.err.println("RipeMD128Hex-2:\t"+data2);
//校验
assertEquals(data1,data2);
}
/**
*测试RipeMD160
*@throws Exception
*/
@Test
public final void testEncodeRipeMD160()throws Exception{
String str="RipeMD160消息摘要";
//获得摘要信息
byte[]data1=RipeMDCoder.encodeRipeMD160(str.getBytes());
byte[]data2=RipeMDCoder.encodeRipeMD160(str.getBytes());
//校验
assertArrayEquals(data1,data2);
}
/**
*测试RipeMD160Hex
*@throws Exception
*/
@Test
public final void testEncodeRipeMD160Hex()throws Exception{
String str="RipeMD160Hex消息摘要";
//获得摘要信息
String data1=RipeMDCoder.encodeRipeMD160Hex(str.getBytes());
String data2=RipeMDCoder.encodeRipeMD160Hex(str.getBytes());
System.err.println("原文:\t"+str);
System.err.println("RipeMD160Hex-1:\t"+data1);
System.err.println("RipeMD160Hex-2:\t"+data2);
//校验
assertEquals(data1,data2);
}
/**
*测试RipeMD256
*@throws Exception
*/
@Test
public final void testEncodeRipeMD256()throws Exception{
String str="RipeMD256消息摘要";
//获得摘要信息
byte[]data1=RipeMDCoder.encodeRipeMD256(str.getBytes());
byte[]data2=RipeMDCoder.encodeRipeMD256(str.getBytes());
//校验
assertArrayEquals(data1,data2);
}
/**
*测试RipeMD256Hex
*@throws Exception
*/
@Test
public final void testEncodeRipeMD256Hex()throws Exception{
String str="RipeMD256Hex消息摘要";
//获得摘要信息
String data1=RipeMDCoder.encodeRipeMD256Hex(str.getBytes());
String data2=RipeMDCoder.encodeRipeMD256Hex(str.getBytes());
System.err.println("原文:\t"+str);
System.err.println("RipeMD256Hex-1:\t"+data1);
System.err.println("RipeMD256Hex-2:\t"+data2);
//校验
assertEquals(data1,data2);
}
/**
*测试RipeMD320
*@throws Exception
*/
@Test
public final void testEncodeRipeMD320()throws Exception{
String str="RipeMD320消息摘要";
//获得摘要信息
byte[]data1=RipeMDCoder.encodeRipeMD320(str.getBytes());
byte[]data2=RipeMDCoder.encodeRipeMD320(str.getBytes());
//校验
assertArrayEquals(data1,data2);
}
/**
*测试RipeMD320Hex
*@throws Exception
*/
@Test
public final void testEncodeRipeMD320Hex()throws Exception{
String str="RipeMD320Hex消息摘要";
//获得摘要信息
String data1=RipeMDCoder.encodeRipeMD320Hex(str.getBytes());
String data2=RipeMDCoder.encodeRipeMD320Hex(str.getBytes());
System.err.println("原文:\t"+str);
System.err.println("RipeMD320Hex-1:\t"+data1);
System.err.println("RipeMD320Hex-2:\t"+data2);
//校验
assertEquals(data1,data2);
}
}
我们一起来观察控制台输出的信息。
以下是RipeMD128处理后的十六进制摘要结果:
原文:RipeMD128Hex消息摘要
RipeMD128Hex-1:3a7d75b69093be33f7f5442b97e09d69
RipeMD128Hex-2:3a7d75b69093be33f7f5442b97e09d69
我们得到了一个32位的十六进制字符串,换算成二进制正好是128位。
对于RipeMD160、RipeMD256和RipeMD320算法的摘要值的十六进制自然是40位、64位和80位。
以下是RipeMD160算法的控制台输出信息:
原文:RipeMD160Hex消息摘要
RipeMD160Hex-1:5baec3e74e72e719fc702bc0057d6bb80c037ee3
RipeMD160Hex-2:5baec3e74e72e719fc702bc0057d6bb80c037ee3
以下是RipeMD256算法的控制台输出信息:
原文:RipeMD256Hex消息摘要
RipeMD256Hex-1:466776542909d4e57215deaaad7f7a50351c6250a0fd3bdddf20cfa28a5f6678
RipeMD256Hex-2:466776542909d4e57215deaaad7f7a50351c6250a0fd3bdddf20cfa28a5f6678
以下是RipeMD320算法的控制台输出信息:
原文:RipeMD320Hex消息摘要
RipeMD320Hex-1:e8e9c116bf1b8762199c1b411f6c4d0bd3ac34fc448736e9ccbb91144f8ec279e55da92c7d3c847c
RipeMD320Hex-2:e8e9c116bf1b8762199c1b411f6c4d0bd3ac34fc448736e9ccbb91144f8ec279e55da92c7d3c847c
对于Tiger、Whirlpool和GOST3411算法的实现与测试用例,与RipeMD无任何差别,只需替换算法名称即可,作者在这里就不再复述了。
2.HmacRipeMD系列算法
HmacRipeMD算法是RipeMD与MAC两种算法的融合,实现起来较为简单。目前,Bouncy Castle提供了HmacRipeMD128和HmacRipeMD160两种算法实现,代码实现如代码清单6-19所示。
代码清单6-19 HmacRipeMD系列算法实现
import java.security.Security;
import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Hex;
/**
*HmacRipeMD系列消息摘要组件
*@author梁栋
*@version 1.0
*@since 1.0
*/
public abstract class HmacRipeMDCoder{
/**
*初始化HmacRipeMD128密钥
*@return byte[]密钥
*@throws Exception
*/
public static byte[]initHmacRipeMD128Key()throws Exception{
//加入BouncyCastleProvider支持
Security.addProvider(new BouncyCastleProvider());
//初始化KeyGenerator
KeyGenerator keyGenerator=KeyGenerator.getInstance("HmacRipeMD128");
//产生秘密密钥
SecretKey secretKey=keyGenerator.generateKey();
//获得密钥
return secretKey.getEncoded();
}
/**
*HmacRipeMD128消息摘要
*@param data待做消息摘要处理的数据
*@param key密钥
*@return byte[]消息摘要
*@throws Exception
*/
public static byte[]encodeHmacRipeMD128(byte[]data, byte[]key)
throws Exception{
//加入BouncyCastleProvider支持
Security.addProvider(new BouncyCastleProvider());
//还原密钥
SecretKey secretKey=new SecretKeySpec(key,"HmacRipeMD128");
//实例化Mac
Mac mac=Mac.getInstance(secretKey.getAlgorithm());
//初始化Mac
mac.init(secretKey);
//执行消息摘要
return mac.doFinal(data);
}
/**
*HmacRipeMD128Hex消息摘要
*@param data待做消息摘要处理的数据
*@param key密钥
*@return String消息摘要
*@throws Exception
*/
public static String encodeHmacRipeMD128Hex(byte[]data, byte[]key)
throws Exception{
//执行消息摘要
byte[]b=encodeHmacRipeMD128(data, key);
//做十六进制转换
return new String(Hex.encode(b));
}
/**
*初始化HmacRipeMD160密钥
*@return byte[]密钥
*@throws Exception
*/
public static byte[]initHmacRipeMD160Key()throws Exception{
//加入BouncyCastleProvider支持
Security.addProvider(new BouncyCastleProvider());
//初始化KeyGenerator
KeyGenerator keyGenerator=KeyGenerator.getInstance("HmacRipeMD160");
//产生秘密密钥
SecretKey secretKey=keyGenerator.generateKey();
//获得密钥
return secretKey.getEncoded();
}
/**
*HmacRipeMD160消息摘要
*@param data待做消息摘要处理的数据
*@param key密钥
*@return byte[]消息摘要
*@throws Exception
*/
public static byte[]encodeHmacRipeMD160(byte[]data, byte[]key)
throws Exception{
//加入BouncyCastleProvider支持
Security.addProvider(new BouncyCastleProvider());
//还原密钥
SecretKey secretKey=new SecretKeySpec(key,"HmacRipeMD160");
//实例化Mac
Mac mac=Mac.getInstance(secretKey.getAlgorithm());
//初始化Mac
mac.init(secretKey);
//执行消息摘要
return mac.doFinal(data);
}
/**
*HmacRipeMD160Hex消息摘要
*@param data待做消息摘要处理的数据
*@param key密钥
*@return String消息摘要
*@throws Exception
*/
public static String encodeHmacRipeMD160Hex(byte[]data, byte[]key)
throws Exception{
//执行消息摘要
byte[]b=encodeHmacRipeMD160(data, key);
//做十六进制转换
return new String(Hex.encode(b));
}
对上述代码做相关测试,如代码清单6-20所示。
代码清单6-20 HmacRipeMD系列算法实现测试用例
import static org.junit.Assert.*;
import org.junit.Test;
/**
*HmacRipeMD校验
*@author梁栋
*@version 1.0
*@since 1.0
*/
public class HmacRipeMDCoderTest{
/**
*测试HmacRipeMD128
*@throws Exception
*/
@Test
public final void testEncodeHmacRipeMD128()throws Exception{
String str="HmacRipeMD128消息摘要";
//初始化密钥
byte[]key=HmacRipeMDCoder.initHmacRipeMD128Key();
//获得摘要信息
byte[]data1=HmacRipeMDCoder.encodeHmacRipeMD128(str.getBytes(),key);
byte[]data2=HmacRipeMDCoder.encodeHmacRipeMD128(str.getBytes(),key);
//校验
assertArrayEquals(data1,data2);
}
/**
*测试HmacRipeMD128Hex
*@throws Exception
*/
@Test
public final void testEncodeHmacRipeMD128Hex()throws Exception{
String str="HmacRipeMD128Hex消息摘要";
//初始化密钥
byte[]key=HmacRipeMDCoder.initHmacRipeMD128Key();
//获得摘要信息
String data1=HmacRipeMDCoder.encodeHmacRipeMD128Hex(str.getBytes(),key);
String data2=HmacRipeMDCoder.encodeHmacRipeMD128Hex(str.getBytes(),key);
System.err.println("原文:\t"+str);
System.err.println("HmacRipeMD128Hex-1:\t"+data1);
System.err.println("HmacRipeMD128Hex-2:\t"+data2);
//校验
assertEquals(data1,data2);
}
/**
*测试HmacRipeMD160
*@throws Exception
*/
@Test
public final void testEncodeHmacRipeMD160()throws Exception{
String str="HmacRipeMD160消息摘要";
//初始化密钥
byte[]key=HmacRipeMDCoder.initHmacRipeMD160Key();
//获得摘要信息
byte[]data1=HmacRipeMDCoder.encodeHmacRipeMD160(str.getBytes(),key);
byte[]data2=HmacRipeMDCoder.encodeHmacRipeMD160(str.getBytes(),key);
//校验
assertArrayEquals(data1,data2);
}
/**
*测试HmacRipeMD160Hex
*@throws Exception
*/
@Test
public final void testEncodeHmacMD4Hex()throws Exception{
String str="HmacRipeMD160Hex消息摘要";
//初始化密钥
byte[]key=HmacRipeMDCoder.initHmacRipeMD160Key();
//获得摘要信息
String data1=HmacRipeMDCoder.encodeHmacRipeMD160Hex(str.getBytes(),key);
String data2=HmacRipeMDCoder.encodeHmacRipeMD160Hex(str.getBytes(),key);
System.err.println("原文:\t"+str);
System.err.println("HmacRipeMD160Hex-1:\t"+data1);
System.err.println("HmacRipeMD160Hex-2:\t"+data2);
//校验
assertEquals(data1,data2);
}
}
以下是控制台中对应的输出信息:
原文:HmacRipeMD128Hex消息摘要
HmacRipeMD128Hex-1:f08ccebbafe66f852ade9c73dcfdf14f
HmacRipeMD128Hex-2:f08ccebbafe66f852ade9c73dcfdf14f
原文:HmacRipeMD160Hex消息摘要
HmacRipeMD160Hex-1:0843ab8d7f3c3d0aca920fa7b8429268bacf5615
HmacRipeMD160Hex-2:0843ab8d7f3c3d0aca920fa7b8429268bacf5615
消息摘要长度与相应的摘要算法的摘要长度相同:HmacRipeMD128与RipeMD128相对应,消息摘要都是32个字符的十六进制串;HmacRipeMD160与RipeMD160相对应,消息摘要值都是40个字符的十六进制串。
目前,Bouncy Castle不仅提供了HmacRipeMD系列算法实现,同时还提供了HMacTiger算法实现。实现方式与代码清单6-19相类似。
作者在整理Bouncy Castle加密组件时,才发现原来还有这么多不为人知的消息摘要算法。可见,各种消息摘要算法正以其独到之处快速地发展着,经过一番优胜劣汰,逐步成为标准。