MD5加密

转自:https://blog.csdn.net/u012611878/article/details/54000607

           http://www.crazyit.org/thread-12283-1-1.html


在java中实现MD5是很简单的,在包java.security有个类MessageDigest。官方文档如下 

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

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

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

JAVA代码如下:

import java.security.MessageDigest;

public class MyMD5 {

    public static void main(String[] args) {
        try{
            MessageDigest md5 = MessageDigest.getInstance("MD5");//申明使用MD5算法
            md5.update("a".getBytes());//
            System.out.println("md5(a)="+byte2str(md5.digest()));
            md5.update("a".getBytes());
            md5.update("bc".getBytes());
            System.out.println("md5(abc)="+byte2str(md5.digest()));
        }catch(Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 将字节数组转换成十六进制字符串
     * @param bytes
     * @return
     */
    private static String byte2str(byte []bytes){       StringBuilder builder = new StringBuilder();       for (int j = 0; j < b.length; j++) {        // 把字节按位与,转换为int           int v = b[j] & 0xFF;           if (v < 16) {             // 如果转换后的数字小于十六,先添加一个0到总的字符串里面             builder.append(0);           }             // 把按位与后的int,转换为十六进制的String追加到总的字符串里面           builder.append(Integer.toHexString(v));       }
    }
} 
为什么把byte转换为16进制字符串的时候要先按位与呢?
  • StringBuilder builder = new StringBuilder();
  • for (int j = 0; j < b.length; j++) {
  •     // 把字节按位与,转换为int
  •     int v = b[j] & 0xFF;
  •     if (v < 16) {
  •         // 如果转换后的数字小于十六,先添加一个0到总的字符串里面
  •         builder.append(0);
  •     }
  •     // 把按位与后的int,转换为十六进制的String追加到总的字符串里面
  •     builder.append(Integer.toHexString(v));
  • }


这里我们主要来讨论一下:为何要 b[j]  & 0xFF 呢?这句话起了什么作用呢?
讨论的时候,我们首先要知道按位与的作用,总结就是一句话:两边数字每位比较,如果两边都是1,结果为1。下面通过一个表格来进行简单说明。
00000101
01000100


上面两行二进制数据,分别表示整数5和68,那么执行按位与以后,结果为多少呢?按照两边(上下)相同、结果为1的来看,结果为:
00000100

这里转换为十进制的意义不大,我们只是为了通过上面这两个表格,阐述按位与的规则。



那么现在我有两个byte,要转换为16进制的字符串,这两个byte的值分别为100和-120。把整数转换为十六进制字符串的方式,可以通过JDK里面自带的Integer.toHexString(int i ) 方法来转换,这个方法的作用就是把int转换为十六进制字符串。

需要注意的是:Integer.toHexString方法要求的参数类型为int,也就是说:把byte传入此方法以后,会被自动转换为int传入进去。对应的二进制数据转换如下两个表格:
100的byte转换为int之后的变化
 

-120的byte转换为int之后的变化
 

大家通过上面的两个转换发现,把正数从byte转换为int,没有任何变化;而负数在转换为byte以后,左边会多出一堆的0。那么这对我们转换十六进制字符串的时候,就会造成很大的困扰:实际上我们的数据并没有那么多位数,只是因为进制转换以后自动在左边补符号位了。
那么当-120转换为int以后,再转换为十六进制字符串以后,我们会得到一个很离谱的字符串:ffffffee
这是不合理的、也是不正确的,因为-120转换为无符号十六进制数字,得到的结果为88,是两位数。

那么我们怎么才能得到实际要的数据呢?其实非常简单,我们只需要把左边补的符号位,全变成0即可!那么我们让int类型的-120和无符号byte的最大值(255、0xFF)按位与一下,看看得到什么:
 

于是大家就发现,-120左边的1全部被去掉了,变成了最后一行的结果。
那么这个结果,其实就是-120转换为无符号整数以后对应的数字:十进制136、16进制88。在Java里面,并不强调无符号整数这个概念,但是在计算机历史中,无符号整数依然有它存在的道理。

好了,为什么要按位与的原因,我们已经从最后一个图里面看到了:就是为了把自动补的符号位全给去掉。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值