深入理解信息摘要加密算法MD5

标签: 算法


前言:加密算法分对称加密与非对称加密,在常见对称加密算法中,信息摘要算法MD5是被广泛应用的一种,本文深入分析MD5算法的实现及其底层实现

1.什么是MD5算法?

MD5信息摘要算法,是将对输入的任意长度的信息进行计算,产生一个128位长度的“指纹”或“信息摘要”。MD5算法适合用在数据签名应用中,在此应用中,一个大的文件必须在类似RSA算法的公用密钥系统中用私人密钥加密前被“压缩”在一种安全模式下。

2.MD5算法的特性

* 长度固定:任意长的字符串加密后长度相同,方便平时信息的统计和管理
* 易计算:字符串和文件加密过程较简单,开发者很容易理解和做出加密工具
* 细微性:字符串里任意一个字符改变都会引起MD5值改变
* 不可逆性:提高数据的安全性

3.暴力破解方法:破解概率较低,步骤如下:

  • 第一步:建立一个大型的数据库,将日常的各个语句,通过MD5加密成密文,不断地积累大量的语句,组成一个庞大的数据库
  • 第二步:将截取到的密文,进行数据库匹配,撞库成功即破解

4.如何实现一个MD5加密算法?

 //一种Java实现,详细介绍见注释
 public static String MD5(String key) {
    //十六进制转换表,0xf
    char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
    try {
        byte[] btInput = key.getBytes();
        // 获得MD5摘要算法的 MessageDigest 对象
        MessageDigest mdInst = MessageDigest.getInstance("MD5");
        // 使用指定的字节更新摘要
        mdInst.update(btInput);
        // 获取摘要密文
        byte[] md = mdInst.digest();

        //md是字节类型的数组,而MD5是一串十六进制的字符
        // 因此要把密文转换成十六进制的字符串形式,长度为32个字符
        int j = md.length;
        //开辟一个缓冲区,用于存转换结果
        char str[] = new char[j * 2];
        int k = 0;
        //加噪声
        for (int i = 0; i < j; i++) {
        //逐个取摘要密文中的字符
            byte byte0 = md[i];
            //无符号右移4位,与0xf([1111])取与,获得高四位
            str[k++] = hexDigits[byte0 >>> 4 & 0xf];
            //获取低四位,这也是srt[]数组长度是2*j的原因
            str[k++] = hexDigits[byte0 & 0xf];
        }
        return new String(str);
        } catch (Exception e) {
            logger.error("生成MD5失败", e);
            return null;
        }
    }

5.深入MD5底层实现:

  • 信息摘要类的实现:Java对其封装在java.security.MessageDigest包下,部分源码,如下:
public abstract class MessageDigest extends MessageDigestSpi {

    private static final Debug pdebug =
                        Debug.getInstance("provider", "Provider");
    private static final boolean skipDebug =
        Debug.isOn("engine=") && !Debug.isOn("messagedigest");

    private String algorithm;

    // The state of this digest
    private static final int INITIAL = 0;
    private static final int IN_PROGRESS = 1;
    private int state = INITIAL;

    // The provider
    private Provider provider;
    ...
    //主要方法,该类对以下方法作了许多重载,仅列出主要方法名
    //获取单例信息摘要对象
    public static MessageDigest getInstance(String algorithm)
    throws NoSuchAlgorithmException{...}
    
    //更新摘要方法
    public void update(byte input) {...}
    
    //摘要方法
    public byte[] digest() {...}
    
    //更新摘要方法引擎
     protected void engineUpdate(ByteBuffer input) {...}
}
  • 获取单例信息摘要对象的方法,其源码如下:
 public static MessageDigest getInstance(String algorithm, String provider)
        throws NoSuchAlgorithmException, NoSuchProviderException
    {
        if (provider == null || provider.length() == 0)
            throw new IllegalArgumentException("missing provider");
        Object[] objs = Security.getImpl(algorithm, "MessageDigest", provider);
        if (objs[0] instanceof MessageDigest) {
            MessageDigest md = (MessageDigest)objs[0];
            md.provider = (Provider)objs[1];
            return md;
        } else {
            MessageDigest delegate =
                new Delegate((MessageDigestSpi)objs[0], algorithm);
            delegate.provider = (Provider)objs[1];
            return delegate;
        }
    }

可以看到,该方法返回一个MessageDigest实例

  • 更新摘要方法,其源码如下:
/**
     * Updates the digest using the specified array of bytes.
     *
     * @param input the array of bytes.
     */
    public void update(byte[] input) {
        engineUpdate(input, 0, input.length);
        state = IN_PROGRESS;
    }

内部通过调用MessageDigestSpi类的engineUpdate方法实现,其源码如下:

/**
 * Update the digest using the specified ByteBuffer. The digest is
 * updated using the {@code input.remaining()} bytes starting
 * at {@code input.position()}.
 * Upon return, the buffer's position will be equal to its limit;
* its limit will not have changed.
*
* @param input the ByteBuffer
* @since 1.5
*/
    protected void engineUpdate(ByteBuffer input) {
        if (input.hasRemaining() == false) {
            return;
        }
        if (input.hasArray()) {
            byte[] b = input.array();
            int ofs = input.arrayOffset();
            int pos = input.position();
            int lim = input.limit();
            engineUpdate(b, ofs + pos, lim - pos);
            input.position(lim);
        } else {
            int len = input.remaining();
            int n = JCAUtil.getTempArraySize(len);
            if ((tempArray == null) || (n > tempArray.length)) {
                tempArray = new byte[n];
            }
            while (len > 0) {
                int chunk = Math.min(len, tempArray.length);
                input.get(tempArray, 0, chunk);
                engineUpdate(tempArray, 0, chunk);
                len -= chunk;
            }
        }
    }

内部通过io操作来完成执行操作(这部分较为复杂,待深究)

  • 摘要方法,放回摘要密文,源码如下:
/**
* Completes the hash computation by performing final operations
* such as padding. The digest is reset after this call is made.
*
* @return the array of bytes for the resulting hash value.
*/
    public byte[] digest() {
        /* Resetting is the responsibility of implementors. */
        byte[] result = engineDigest();
        state = INITIAL;
        return result;
    }

内部通过调用MessageDigestSpi类的engineDigest方法实现,跟踪engineDigest方法源码,

protected int engineDigest(byte[] buf, int offset, int len)
    throws DigestException {

        byte[] digest = engineDigest();
        if (len < digest.length) throw new DigestException("partial digests not returned");
        if (buf.length - offset < digest.length)
    throw new DigestException("insufficient space in the output "
        + "buffer to store the digest");
        System.arraycopy(digest, 0, buf, offset, digest.length);
        return digest.length;
    }

至此,MD算法主要源码展示完毕。

6.总结:

  • Java实现MD5算法过程:输入字符串并转换字节数组--->获取java.security.MessageDigest类实例mdInst--->调用MD实例mdInst.update()方法,将字符串数组更新到MD内部进行摘要--->调用MD实例mdInst.digest方法获取摘要字节数组--->将摘要字节数组转换成十六进制字符(32个)--->返回加密字符串结果

  • MessageDigest底层实现:

  • 主要类:MessageDigest类与MessageDigestSpi类

  • 主要方法:

  • getInstance()获取摘要对象实例

  • update()更新摘要字节数组,进行取摘要

  • digest()获取摘要字节数组

  • engineUpdate()执行摘要更新

  • engineDigest()执行摘要操作

  • MD5算法应用场景:实现安全登录、文件加密等,实际使用中,单单使用MD5加密还是不够的,一般会进行加盐值,通过UUID生成系统唯一标识符(其中一种方法),将标识符与待加密字符串进行拼接后,再执行MD5加密,从而进一步提升加密效果。

希望本文能对你有所帮助,欢迎回来~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,570评论 25 707
  • 概述 之前一直对加密相关的算法知之甚少,只知道类似DES、RSA等加密算法能对数据传输进行加密,且各种加密算法各有...
    Henryzhu阅读 2,931评论 0 14
  • 乍看《香水》,评价只会是两个字:变态。事实上,这就是我在看这部影片时时不时冒出的一句粗口,还有一句话是,他怎么可以...
    小玉哥阅读 2,131评论 2 0
  • 【点石成金】20170914 学习力6 Day121 语言启蒙词汇扩展指读一遍 想吃苹果的鼠小弟 ...
    叶子ya豆子阅读 180评论 0 0
  • ​​spring [英][sprɪŋ][美][sprɪŋ] n.春季;泉水,小溪;弹簧,弹性;跳跃; vi.跳,跃...
    d56ea089160e阅读 1,516评论 0 1