MD5算法介绍以及在Android中的实现

什么是MD5?

基本概念

MD5,Message Digest Algorithm MD5(消息摘要算法第五版)是计算机安全领域广泛使用的的一种散列函数,用于确保信息传输完整一致。由MD2、MD3、MD4演变过来的,是一种单向加密算法,是不可逆的一种的加密方式。

将数据(如一段文字)运算变为另一固定长度值,是散列算法的基础原理。

特点

MD5算法具有以下特点:

  1. 压缩性:任意长度的数据,算出的MD5值长度都是固定的。
  2. 容易计算:从原数据计算出MD5值很容易。
  3. 抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别。
  4. 强抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的。这里“碰撞”我们理解为一种破解手段。

散列

一般128位的MD5散列被表示为32位十六进制数字。以下是一个43位长的仅ASCII字母列的MD5散列:

MD5("The quick brown fox jumps over the lazy dog")
= 9e107d9d372bb6826bd81d3542a419d6

即使在原文中作一个小变化(比如用c取代d)其散列也会发生巨大的变化:

MD5("The quick brown fox jumps over the lazy cog")
= 1055d3e698d289f2af8663725127bd4b

空文的散列为:

MD5("")
= d41d8cd98f00b204e9800998ecf8427e

MD5的应用

  • 一致性验证
    MD5的典型应用是对一段信息(Message)产生信息摘要(Message-Digest),以防止被篡改。
    MD5将整个文件当作一个大文本信息,通过其不可逆的字符串变换算法,产生了这个唯一的MD5信息摘要。
    比如下载服务器针对一个文件预先提供一个MD5值,用户下载完该文件后,用我这个算法重新计算下载文件的MD5值,通过比较这两个值是否相同,就能判断下载的文件是否出错,或者说下载的文件是否被篡改了。

  • 数字签名
    文件认证。消息摘要用于生成唯一且可靠的数据标识符。它们有时被称为数据的“数字指纹”。

  • 安全访问认证
    MD5将任意长度的“字节串”映射为一个128bit的大整数,并且是通过该128bit反推原始字符串是困难的。例如,我们在Android中用户的密码使用MD5加密之后,再传给服务器。

Android中的实现

MessageDigest

在java.security这个包下有一个类MessageDigest,在Android中我们就是通过这个类的相关方法来实现计算文件的MD5。

使用方法:

//方法1:返回MessageDigest实例 algorithm算法名称
public static MessageDigest getInstance(String algorithm)
            throws NoSuchAlgorithmException {}
//方法2:更新计算消息摘要的数据内容
public void update(byte[] input) {}

//方法3:计算消息摘要
 public byte[] digest(){}

进行初始化操作,需要指定算法

算法名称不区分大小写。例如,以下所有调用都是等同的:

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

进行消息摘要内容的更新

这个方法不是一定要调用的,但是对于计算很大的数据的MD5,比方文件。我们就需要通过分段读取多次调用 update( ) 方法来将数据更新给MessageDigest对象。我们要理解这个方法的是,调用执行update并没有计算MD5的值,真正计算的MD5值是调用digest()

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

计算消息摘要的值并返回

当使用更新方法提供数据之后,通过调用digest( ) 方法来返回消息摘要。

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

获取字符串的MD5

public static String getStringMD5(String sourceStr) {
        String s = null;
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            //这两行代码的作用是:
            // 将bytes数组转换为BigInterger类型。1,表示 +,即正数。
            BigInteger bigInt = new BigInteger(1, md.digest(sourceStr.getBytes()));
            // 通过format方法,获取32位的十六进制的字符串。032,代表高位补0 32位,X代表十六进制的整形数据。
            //为什么是32位?因为MD5算法返回的时一个128bit的整数,我们习惯于用16进制来表示,那就是32位。
            s = String.format("%032x", bigInt);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return s;
    }

获取文件的MD5

public static String getFileMD5(File file) {
        String s = null;
        
        if (!file.exists()) {
            return null;
        }
        
        FileInputStream in = null;
        byte buffer[] = new byte[1024];
        int len;

        try {  
            MessageDigest md = MessageDigest.getInstance("MD5");
            in = new FileInputStream(file);
            while ((len = in.read(buffer, 0, 1024)) != -1) {
                md.update(buffer, 0, len);
            }
            in.close();

            BigInteger bigInt = new BigInteger(1, md.digest());
            s = String.format("%032x", bigInt);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        
        
        
        return s;
    }

这里和读取字符串的MD5差别主要在文件读取和使用update方法更新数据。更新数据我们前面已经讲解过了。

对于文件的读取有很多种方式,例如通过FileInputStream读取字节流,也可以包装成InputStreamReader读取字节流,也可以包装成BufferedInputStream进行带缓冲区的读取,以及RandomAccessFile或者nio 包中FileChannel加内存映射的方式。
在Android中,我们推荐使用RandomAccessFile方法,因为这种方式性能更好。

更重要的:计算文件MD5值是一个比较耗时的操作,不要在主线程中计算。

RandomAccessFile方式:

...
    //RandomAccessFile方式:
    RandomAccessFile randomAccessFile = null;
    byte buffer[] = new byte[1024];
    int len;
    
        try {  
            MessageDigest md = MessageDigest.getInstance("MD5");
            randomAccessFile = new RandomAccessFile(file,"r");
            while ((len = randomAccessFile.read(buffer, 0, 1024)) != -1) {
                md.update(buffer, 0, len);
            }
            randomAccessFile.close();

            BigInteger bigInt = new BigInteger(1, md.digest());
            s = String.format("%032x", bigInt);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
...

MD5的安全性

从MD5加密本身来讲这个过程是不可逆的,但不意味着MD5算法不可破解。但是破解对于我们将MD5算法应用于文件的一致性检验并没有什么太大的影响。这

这个大家有兴趣的可以了解一下:

中国的王小云教授带领的研究小组于2004年、2005年先后破解了被广泛应用于计算机安全系统的MD5和SHA-1两大密码算法。

——百度百科-王小云

参考文章

声明

  1. 由于互联网数据的分享性,如果我发表的文章,来源于您的原创文章,且我没有注明,请微博私信或者邮件macouen@gmail.com说明。
  2. 欢迎转载,但请注明文章原始出处。
    原文作者:橡樹先生
    原文地址: https://www.jianshu.com/p/83fc0c13104c
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞