6.5.2 实现

Java 6内并没有提供上述算法的实现,这里仅仅是Bouncy Castle的专场。为避免内容冗长,作者在这里以RipeMD系列算法和HmacRipeMD系列算法为例,做简要介绍。

RipeMD系列算法和HmacRipeMD系列算法如表6-4所示。

figure_0209_0047

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加密组件时,才发现原来还有这么多不为人知的消息摘要算法。可见,各种消息摘要算法正以其独到之处快速地发展着,经过一番优胜劣汰,逐步成为标准。