zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    JAVA 8的新特性
    JAVA中map的分类和各自的特性
    设计模式之工厂方法模式(附实例代码下载)
    为什么重写equals还要重写hashcode??
    C# static的用法详解
    1-RadioButton控件的用法
    C#三种常用的读取XML文件的方法
    VS2017 中安装SVN
    pip安装selenium时,报错“You are using pip version 10.0.1, however version 18.0 is available.”的问题
    问题:unknown error: call function result missing 'value' 解决方法
  • 原文地址:https://www.cnblogs.com/xingele0917/p/3685405.html
Copyright © 2011-2022 走看看