跳至主要內容
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?

4563博客

全新的繁體中文 WordPress 網站
  • 首頁
  • md5 padding 说明和 JavaScript MD5 implementation 完全不一样啊?是说明写错了吗?
未分類
19 4 月 2021

md5 padding 说明和 JavaScript MD5 implementation 完全不一样啊?是说明写错了吗?

md5 padding 说明和 JavaScript MD5 implementation 完全不一样啊?是说明写错了吗?

資深大佬 : quxinna 7

这是 blueimp javascript md5 https://github.com/blueimp/JavaScript-MD5 的 md5 padding

x[len >> 5] |= 0x80 << len % 32
x[(((len + 64) >>> 9) << 4) + 14] = len

四个字节一组
数组排序长度*8 右移 5 位,或十六进制 80 十进制 128 左移数组排序长度*8 模 32 数组
数组排序长度*8 加 64 右移 9 位,左移 4 位,加 14,赋值长度

这是网上的 md5 padding 介绍

MD5 可以认为是基于 block 的算法:它要求每次处理的数据长度为 512bits 。但是实际中要处理的明文长度并不一定是 512 的整数倍,怎么办呢?参考 AES 的做法,做数据补齐 /填充( Padding )。假设原始明文消息的长度为 K,MD5 的 Padding 可以细分为 2 个子步骤:

附加填充位( Append Padding Bits ):从原始明文消息的 K 位之后补 100…一直到 512-64=448 位,填充位的规则是:只有第一个 bit 是 1,之后都是 0 。这里有个问题:如果 K%512 正巧等于 448 怎么办呢?再者,如果 K%512 在[448,512(模运算得到的是 0)]之间怎么办呢?答案:Append Padding Bits 要求至少填充 1 位,如果长度正好是 448,那么就索性再增加一个 block,填充 512bits ;如果模超过 448,也再增加一个 block,填充 512-( K%512-448 );同理,如果模不到 448,就填充 448-K%512 即可。
附加长度( Append Length ):这个时候,最后一个 block 只剩下 64bits 需要填充了,其内容是原始明文的长度。试想,64bits 可以表示最长的数据将近 2^30GB 的数据了!如果原始明文大于这个数值,那就只能对 2^64 取模,作者在原文中是这么写的:
In the unlikely event that b is greater than 2^64, then only the low-order 64 bits of b are used.
如果 b 大于 2^64,则仅使用 b 的低阶 64 位。

完全不一样啊,是说明写错了吗?

大佬有話說 (4)

  • 資深大佬 : Flymachine

    你对位运算的知识了解不够啊,我建议你学一下<深入理解计算机系统>的前两章。

    你给的是 binlMD5 函数实现的头两行,而它是这样被调用的:
    binl2rstr(binlMD5(rstr2binl(s), s.length * 8))

    binlMD5 的参数是 rstr2binl 函数的结果,而 rstr2binl 是这样实现的:
    function rstr2binl(input) {
    var i
    var output = []
    output[(input.length >> 2) – 1] = undefined // 设置数组最大长度(包含原始数据、填充和数据长度)
    for (i = 0; i < output.length; i += 1) {
    output[i] = 0 // 初始化 0x00, 注意此时实际上也把 00 填充都加上了
    }
    var length8 = input.length * 8
    for (i = 0; i < length8; i += 8) {
    output[i >> 5] |= (input.charCodeAt(i / 8) & 0xff) << i % 32 // 写入原始数据
    }
    return output // 返回此数组
    }
    已经开始设置填充了。
    也就是说 binlMD5 的头两行只是对其的补充:
    x[len >> 5] |= 0x80 << len % 32 // 补上填充字段开头一位的 1
    x[(((len + 64) >>> 9) << 4) + 14] = len // 补上原始数据的长度

  • 主 資深大佬 : quxinna

    @Flymachine

    output[(input.length >> 2) – 1] = undefined // 设置数组最大长度(包含原始数据、填充和数据长度)
    for (i = 0; i < output.length; i += 1) {
    output[i] = 0 // 初始化 0x00, 注意此时实际上也把 00 填充都加上了
    }

    //这段代码删除也不影响运行,应该不是初始化

    x[len >> 5] |= 0x80 << len % 32 // 补上填充字段开头一位的 1
    x[(((len + 64) >>> 9) << 4) + 14] = len // 补上原始数据的长度

    //len 取 1,0x80 << 8 结果赋值
    //len 取 56,数组排序长度(56*8+64)>>>9 即 1*16+14=30 赋值为数组排序长度
    //并不是补开头

  • 主 資深大佬 : quxinna

    len 取 1,x[len >> 5] |=0x80 << 8
    len 取 56,(((len + 64) >>> 9) << 4) + 14=(56*8+64)>>>9=1*16+14=30

  • 資深大佬 : Flymachine

    @quxinna
    1. “//这段代码删除也不影响运行,应该不是初始化”, 不能这么看,这是 Undefined Behavior (未定义行为),有些编译 /解释器是会把数组元素自动初始化为 0 的,特别是像 JS 这种解释型语言。但这并不一定是语言标准中规定的行为,所以可能存在不会把元素自动初始化的浏览器环境,所以为了防止 UB 导致的未知 BUG,广泛使用的开源库一般都尽量不使用 UB 。因此,你理解代码不能依赖运行结果,而应该理解程序员写这些代码的意图。

    建议你看几本喜欢用伪代码解释程序的编程书,你就知道靠运行结果来理解程序有多奇怪了。

    2. “//len 取 1,0x80 << 8 结果赋值”,我建议你好好理解

    binl2rstr(binlMD5(rstr2binl(s), s.length * 8)) 为什么字符串长度要*8——len 是字符串数组的位长度,所以不要把参数 len 和 s.length 搞混了。

    3. “//并不是补开头”,我建议你好好理解

    output[i >> 5] |= (input.charCodeAt(i / 8) & 0xff) << i % 32 // 写入原始数据

    这段代码,想象 i = len, 然后你就明白我为什么说“x[len >> 5] |= 0x80 << len % 32”是在补上填充字段开头一位的 1 了。

    这个 MD5 为了执行效率,output 并不是一个字节数组,加上耦合性极高的内部代码,所以理解上确实很困难。

    如果你真想理解 MD5 的实现,建议你先去学一下<深入理解计算机系统>的前两章,或者学一下 C 语言,看一下 C 语言下的 MD5 实现。

文章導覽

上一篇文章
下一篇文章

AD

其他操作

  • 登入
  • 訂閱網站內容的資訊提供
  • 訂閱留言的資訊提供
  • WordPress.org 台灣繁體中文

51la

4563博客

全新的繁體中文 WordPress 網站
返回頂端
本站採用 WordPress 建置 | 佈景主題採用 GretaThemes 所設計的 Memory
4563博客
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?
在這裡新增小工具