MessageDigest简介

一.概述

MessageDigest 类为应用程序提供信息摘要算法的功能,如 MD5 或 SHA 算法。信息摘要是安全的单向哈希函数,它接收任意大小的数据,并输出固定长度的哈希值。

MessageDigest 对象开始被初始化。该对象通过使用 update()方法处理数据。任何时候都可以调用 reset()方法重置摘要。一旦所有需要更新的数据都已经被更新了,应该调用digest() 方法之一完成哈希计算。

对于给定数量的更新数据,digest 方法只能被调用一次。在调用 digest 之后,MessageDigest 对象被重新设置成其初始状态。

MessageDigest 类为应用程序提供信息摘要算法的功能,如 MD5 或 SHA 算法。信息摘要是安全的单向哈希函数,它接收任意大小的数据,并输出固定长度的哈希值。

MessageDigest 对象开始被初始化。该对象通过使用 update()方法处理数据。任何时候都可以调用 reset()方法重置摘要。一旦所有需要更新的数据都已经被更新了,应该调用digest() 方法之一完成哈希计算。

对于给定数量的更新数据,digest 方法只能被调用一次。在调用 digest 之后,MessageDigest 对象被重新设置成其初始状态。

1、public static MessageDigest getInstance(String algorithm) throws NoSuchAlgorithmException
  返回实现指定摘要算法的 MessageDigest 对象。
algorithm - 所请求算法的名称
2、public static MessageDigest getInstance(String algorithm,String provider) throws NoSuchAlgorithmException,NoSuchProviderException
  返回实现指定摘要算法的 MessageDigest 对象。
  algorithm - 所请求算法的名称
  provider - 提供者的名称。
3、public void update(byte[] input)
  使用指定的 byte 数组更新摘要。
4、public byte[] digest()
  通过执行诸如填充之类的最终操作完成哈希计算。在调用此方法之后,摘要被重置。
5、public static boolean isEqual(byte[] digesta,byte[] digestb)
  比较两个摘要的相等性。做简单的字节比较。

注意:Provider可以通过 java.security.Security.getProviders() 方法获取已注册提供者列表。比较常用的有“SUN”

SUN提供的常用的算法名称有:
MD2
MD5
SHA-1
SHA-256
SHA-384
SHA-512

二、
2.1、创建 MessageDigest 对象
计算信息摘(即散列码)要做的第一步是创建 MessageDigest对象 实例。像所有的引擎类一样,获取某类报文摘要算法(即散列算法,比如MD5)的  MessageDigest 对象的途径是调用 MessageDigest 类中的 getInstance 静态 factory 方法:

public static MessageDigest getInstance(String algorithm)
注意:算法名不区分大小写。例如,以下所有调用都是相等的:

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

调用程序可选择指定提供者名称,以保证所要求的算法是由已命名提供者实现的:

public static MessageDigest getInstance(String algorithm, String provider);
调用 getInstance 将返回已初始化过的MessageDigest对象。因此,它不需要进一步的初始化。
2.2、向MessageDigest传送要计算的数据
计算数据的摘要的第二步是向已初始化的MessageDigest对象提供传送要计算的数据。这将通过一次或多次调用以下某个 update(更新)方法来完成:

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

2.3、计算摘要
通过调用 update 方法向MessageDigest对象传送要计算的数据后,你就可以调用以下某个 digest(摘要)方法来计算摘要(即生成散列码):

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

前两个方法返回计算出的摘要。后一个方法把计算出的摘要储存在所提供的 buf 缓冲区中,起点是 offset。len 是 buf 中分配给该摘要的字节数。该方法返回实际存储在 buf 中的字节数。
对第二个接受输入字节数组变量的 digest 方法的调用等价于用指定的输入调用:

public void update(byte[] input)
,接着调用不带参数的 digest 方法.
三、例子演示
3.1、★ 编程思路:
java.security包中的MessageDigest类提供了计算消息摘要即生成散列码的方法,首先生成对象,执行其update( )方法可
以将原始数据传递给该对象,然后执行其digest( )方法即可得到消息摘要。具体步骤如下:
(1)生成MessageDigest对象

MessageDigest m=MessageDigest.getInstance("MD5");
MessageDigest类也是一个工厂类,其构造器是受保护的,不允许
直接使用new MessageDigist( )来创建对象,而必须通过其静态方法getInstance( )生成MessageDigest对象
其中传入的参数指定计算消息摘要所使用的算法,常用的有"MD5","SHA"等。
(2)传入需要计算的字符串

m.update(x.getBytes("UTF8" ));
分析:x为需要计算的字符串,update传入的参数是字节类型或字节类型数组,对于字符串,需要先使用getBytes( )方法生成字符串数组。
(3)计算消息摘要

byte s[ ]=m.digest( );
分析:执行MessageDigest对象的digest( )方法完成计算,计算的结果通过字节类型的数组返回。
(4)处理计算结果
必要的话可以使用如下代码将计算结果(byte数组)转换为字符串。
 
3.2、示例:
 1 public class test_md5_1 {
 2 
 3     public static void main(String[] args) {
 4         //待加密的字符串
 5         String myinfo = "abc123";
 6         System.out.println("加密前字符串:"+myinfo);
 7         try {
 8             MessageDigest m1 = MessageDigest.getInstance("MD5");
 9             m1.update(myinfo.getBytes());
10             byte[] digesta = m1.digest();
11             System.out.println("本信息摘要是:" + convertToHexString(digesta));
12 
13         } catch (NoSuchAlgorithmException e) {
14             System.out.println("非法摘要算法");
15         }
16     }
17 
18     /**
19      * 计算结果(byte数组)转换为字符串
20      */
21     public static String convertToHexString(byte[] digesta) {
22         String result = "";
23         for (int i = 0; i < digesta.length; i++) {
24             //0xff & digesta[i] 取低8位
25             System.out.println("digesta["+i+"]:"+digesta[i]);
26             String temp = Integer.toHexString(0xff & digesta[i]);
27             
28             result += temp;
29         }
30         return result;
31     }
32 
33 }

执行结果:

加密前字符串:abc123
digesta[0]:-23
digesta[1]:-102
digesta[2]:24
digesta[3]:-60
digesta[4]:40
digesta[5]:-53
digesta[6]:56
digesta[7]:-43
digesta[8]:-14
digesta[9]:96
digesta[10]:-123
digesta[11]:54
digesta[12]:120
digesta[13]:-110
digesta[14]:46
digesta[15]:3
本信息摘要是:e99a18c428cb38d5f260853678922e3

 ps:为什么取低8位?

Integer.toHexString();方法传入的值是int类型的,所以当传入byte的时候就会自动转换成int类型,又由于byte类型只占8位并且int类型占32位,所以会进行补位,如果byte是整数的话没什么影响,因为前面补的是0。但是如果是负数的话就会出现问题了,例如byte b = -112; byte的2进制表示为:1001 0000,java中是以补码的形式进行表示的,这样前面补满22位个1的时候就会出现很多f,所以取低8位。

接着仔细看下输出结果是31位。为什么会少一位,byte数组中有的值可能小于16,所以转换成16进制的时候用1位就可以表示了。这个时候我们应该在前面加上个0。

修改转换字符串的代码:

 1 /**
 2      * 计算结果(byte数组)转换为字符串
 3      */
 4     public static String convertToHexString(byte[] digesta) {
 5         String result = "";
 6         for (int i = 0; i < digesta.length; i++) {
 7             //0xff & digesta[i] 取低8位
 8             String temp = Integer.toHexString(0xff & digesta[i]);
 9             if(temp.length()==1){
10                 temp = "0"+temp;
11             }
12             result += temp;
13         }
14         return result;
15     }

执行结果:

加密前字符串:abc123
digesta[0]:-23
digesta[1]:-102
digesta[2]:24
digesta[3]:-60
digesta[4]:40
digesta[5]:-53
digesta[6]:56
digesta[7]:-43
digesta[8]:-14
digesta[9]:96
digesta[10]:-123
digesta[11]:54
digesta[12]:120
digesta[13]:-110
digesta[14]:46
digesta[15]:3
本信息摘要是:e99a18c428cb38d5f260853678922e03

 上面字节数组补码形式为:

-23|-102|24|-60|40|-53|56|-43|-14|96|-123|54|120|-110|46|3

11101001|10011010|00011000|11000100|00101000|11001011|00111000|11010101|11110010|01100000|10000101|00110110|01111000|10010010|00101110|00000011

原文地址:https://www.cnblogs.com/xingele0917/p/3685405.html