Arm 汇编和字节顺序中的 MD5 哈希

The MD5 Hash in Arm Assembly and endianness

我是 Arm 汇编编程的新手。我正在尝试在执行 MD5 哈希算法的 arm cortex m4 程序集中编写一个函数。我正在按照此处 https://en.wikipedia.org/wiki/MD5.

找到的维基页面算法

维基页面声明了常量 A、B、C、D 以及数组 S 和 K。所有值均以小端格式显示。

关于小端:

我做了一些研究,似乎在内存中,整个字符串显示顺序,好像整个字符串都是大端。这是因为每个字符都是一个字节。维基中的值是以小端方式声明的,所以在我声明它们之后,它们在内存中显示为大端(正常顺序)。

我已经完成了 MD5 哈希的预处理。让我向您展示字符串 "The Quick Brown Fox Jumps Over The Lazy Dog":

在内存中的样子
 54686520 51756963 6B204272 6F776E20 466F7820 4A756D70 73204F76 65722054 
 6865204C 617A7920 446F672E 80000000 00000000 00000000 00000000 00006001

所以 54=T, 68, =h,...等等...

下面是我的困惑所在。

在消息之后,附加一个 1 位。这是字节 0x80。之后,其余 512 位用零填充,直到最后 64 位,即消息的长度。如图所示,消息的长度为 0x160 位。但是长度在内存中是小端的,所以它显示为 6001.

所以长度在内存中是小端

但是根据 wiki,常量 A、B、C、D 和数组 K 最初 声明为小端。

所以当我在内存中查看它们时,它们显示正常。

所以现在我很困惑!我的长度在内存中是小端,常量和K数组在内存中是大端

在内存中查看示例的正确方法是什么?

如果我要这样做,我会找到一个 MD5 库或 class,写一个简单的例子来获取我想要散列的文本,然后让编译器为 ARM 部分生成程序集我需要

您可以考虑 mbed [1] 或 Arduino [2] 版本。

[1] https://os.mbed.com/users/hlipka/code/MD5/
[2] https://github.com/tzikis/ArduinoMD5

将 ASCII 字符串描述为 big-endian 是不正确的。字节序仅适用于多字节值,因此 ASCII 字符串没有字节序,因为它们只是字节数组。例如,如果您有一个 16 位数字的数组,那么字节顺序将单独应用于数组中的每个值,但不适用于元素的顺序。

您问题的真正答案是,以这种方式组织时,没有简单的方法来查看 'raw' 内存数据。大多数调试器都有变量监视,可用于以类型感知的方式查看内存位置的内容,这通常更容易;因此,例如,您可以告诉手表 window K 指向一个 64 字节的字符串,而 K+56 指向一个 little-endian 64 位无符号整数,然后这些值将得到正确解释和报告。

更一般地说,在小端系统中解释 'raw' 内存数据通常很困难,因为知道要交换哪些字节以将值放入易于人类阅读的顺序取决于知道每个字节有多长值是,并且此信息在运行时不存在。这是小端系统的缺点,优点是转换指针不会改变它们的绝对值,因为无论数据类型有多大,指针总是指向最低有效字节。

编程语言和体系结构与此无关。您正在尝试从字符串准备 32 位值。

"The Quick Brown Fox Jumps Over The Lazy Dog."

作为 ASCII 字符串,字节在十六进制中看起来像这样:

54 68 65 20 51 75 69 63 6B 20 42 72 6F 77 6E 20 46 6F 78 20 4A 75 6D 70 73 20 4F 76 65 72 20 54 68 65 20 4C 61 7A 79 20 44 6F 67 2E

但是 md5 是关于数据而不是字符串正确的吗?稍后会详细介绍。

你必须小心字节顺序。通常人们谈论的是字节交换更大的数量(字节的地址从顶部或底部开始,大端或小端)。 16 或 32 或 64 等位。最初谈论长度的 64 位数量:

0x1122334455667788

当以递增地址顺序查看字节列表时,小端(就一般理解而言)是

88 77 66 55 44 33 22 11

所以

0x0000000000000160

会是

60 01 00 00 00 00 00 00

下一个问题是你的字符串。它应该以 0x54686520 开头还是应该以 0x20656854 或 0x63697551 开头?

我相信维基百科中的文字

The MD5 hash is calculated according to this algorithm. All values are in little-endian.

//Note: All variables are unsigned 32 bit and wrap modulo 2^32 when calculating

那么你的最后一个(唯一的)块应该看起来像

0x20656854
0x63697551
0x7242206B
0x206E776F
0x20786F46
0x706D754A
0x764F2073
0x54207265
0x4C206568
0x20797A61
0x2E676F44
0x00000080
0x00000000
0x00000000
0x00000160
0x00000000

使用我在网上找到的 md5 源程序,并使用我的 Linux 发行版附带的

ec60fd67aab1c782cd3f690702b21527

作为两种情况下的散列,last/only 块的准备数据从该程序的 0x20656854 开始。该程序还正确计算了维基百科上字符串的结果。

所以从 wikipedia 文章来看,它应该更好地处理 64 位长度。您的数据(不是字符串)需要从 512 位以 32 位小端数量进行处理。

54 68 65 20 becomes 0x20656854 0x000000000000160 becomes 0x00000160, 0x00000000.