【发布时间】:2021-06-10 22:20:57
【问题描述】:
简介
作为 SHA-256 散列算法的一部分,为了方便起见,有一个函数通常被称为 σ1 或 sigma0。基本上,它将 X 作为输入,其中 X 是 32 位无符号值。然后像这样转换它:
ROTATE_RIGHT(X, 7) ^ ROTATE_RIGHT(X, 18) ^ SHIFT_RIGHT(X, 3)
一点解释,如果需要的话:
- ROTATE_RIGHT(X, Y) - 将 X 的位向右旋转 Y
- SHIFT_RIGHT(X, Y) - 将 X 的位向右移动 Y,因此结果的前 Y 位始终为 0
另外,如果您需要代码,这里是 Python 的完整版本:
def rotate_right(x, y):
return (((x & 0xffffffff) >> (y & 31)) | (x << (32 - (y & 31)))) & 0xffffffff
def shift_right(x, n):
return (x & 0xffffffff) >> n
def sigma0(x):
return rotate_right(x, 7) ^ rotate_right(x, 18) ^ shift_right(x, 3)
反转功能
我开始怀疑那个东西是否可逆,令我惊讶的是,很快就编写了一个函数,通过给定sigma0 的输出,返回该函数的输入,或者简单地说,反转sigma0 函数。我不会把代码放在这里,因为它是用 Node.js 编写的,并且由于通过掩码搜索特定 sigma0 输入的更复杂的需求进行了很多修改,但我想给你一个关于我如何解决的基本概念它,所以也许你可以启发我一些关于如何实现我需要的新想法。
我的解决方案很简单,但也是递归的。我们知道每个输出的位都是两个或三个输入位的异或运算的结果。所以我做了一个依赖表,这样我就可以看到输出的位是如何受到输入的影响的:
I: 00,01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
R7 25,26,27,28,29,30,31,00,01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24
R18 14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,00,01,02,03,04,05,06,07,08,09,10,11,12,13
S3 zz,zz,zz,00,01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28
---------------------------------------------------------------------------------------------------
O: 00,01,02,03,04,05,06,07,08,09,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31
这是怎么回事?比如说,在输出的第一位我们有 1。为方便起见,我将其写为O[0],O[1],...O[31],所以O[x] 是输出的第 (x+1) 位.输入相同,标记为I。
所以,O[0] == 1。在上表中,我们看到O[0] 是I[25] 和I[14] 异或运算的结果。这意味着只有一个输入位必须为 1。所以此时我们可以说我们可以为输入创建两个合适的掩码:
##############0#########1#######
##############1#########0#######
这些面具至少对我来说是解决方案的关键。 # 表示任何值(0 或 1)。当我们创建掩码时,我们为下一位调用递归函数,但保留掩码。如果我们没有可能适合先前掩码的掩码,则先前的掩码没有解决方案,如果我们达到第 32 位,则保证掩码中没有锐利,这就是答案。
首先,我需要告诉你这个东西是有效的。但是在 Node.js 上,它会计算大约 100 毫秒的每个值,我不知道我的递归算法的最差复杂度是什么,因为它很难测量。它不满足我,我想尽办法解决这个 O(n)。
问题
我想知道是否有可能在 O(n) 的复杂度内编写一个反转 sigma0 的函数,其中 n 是输入/输出中的位数,它等于 32,没有递归,掩码或树木,简单而快速。
我还没有为我的陈述得出任何数学证明,但是我测试了很多不同的值,我可以自信地声称输入值的数量等于这个函数的输出值的数量,并且两者都等于2^32 - 1。换句话说,对于每个输出,sigma0 函数的可能输入只有一个。
这让我想到,sigma0 原始函数产生的结果复杂度为 O(n),这意味着反向函数必须有一个也适用于 O(n) 的解决方案。
如果你在数学上证明我这是不可能的,我也会接受这个答案,但我没有发现任何表明这项任务不可能的东西。
消耗资源的解决方法
如果我有 16gb 的空闲内存,我可以将所有可能的值预先计算到文件中,然后将它作为一个巨大的数组加载到内存中。但这不是一个解决方案,因为还有其他 3 个类似的功能,要为所有这些功能做到这一点,我需要 64gb 的内存,这对于这个简单的任务来说太贵了。
UPD:高斯消元法
感谢 Artjom B. 的评论,我找到了一种通过高斯消元法求解 XOR 方程的好方法。目前我正在尝试解决这样的矩阵:
Input: 00000000100110101000111011101001
Output: 01110001101010000010010011100110
0: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 | 0
1: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 | 1
2: 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 | 1
3: 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 | 1
4: 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 | 0
5: 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 | 0
6: 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 | 0
7: 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 | 1
8: 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 | 1
9: 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 | 0
10: 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 | 1
11: 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 | 0
12: 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 | 1
13: 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 | 0
14: 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 | 0
15: 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 | 0
16: 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 | 0
17: 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 | 0
18: 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | 1
19: 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | 0
20: 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 | 0
21: 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 | 1
22: 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 | 0
23: 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 | 0
24: 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 | 1
25: 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 0 | 1
26: 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 0 | 1
27: 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 | 0
28: 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 | 0
29: 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 | 1
30: 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 | 1
31: 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 | 0
发布了矩阵,这样您就可以看到它的外观,而不会浪费您自己的时间来创建它。解决与否后,我会更新我的问题。
【问题讨论】:
-
“这让我想到 sigma0 原始函数产生复杂度为 O(n) 的结果这一事实意味着反向函数必须有一个也适用于 O(n) 的解。”这根本不是真的。有许多函数在一个方向上是简单的,但它们的逆函数却不是。这是大多数现代密码学的基础。您正在陈述 P = NP 的更具侵略性的版本,就好像它是给定的,而不是复杂性理论的重大问题之一。没有已知有效逆的加密哈希的全部意义。
-
无论如何,这个问题与 Stack Overflow 无关,因为它与特定的实现无关。它可能与 crypto.stackexchange.com 相关,但如果您认为您已经设计了 SHA-256 的有效反转,假设您还没有。回顾您的工作,您似乎已经证明,您可以在给定任意时间或任意内存的情况下找到散列的原像(这是众所周知的事实,并且对于任何散列函数都得到了简单的证明)。
-
你似乎已经发现是什么让它如此不可逆转。扭转各个阶段是非常困难的。目前没有证据表明不可能逆转这些阶段。每个人都希望找到这样的证据。没有人知道如何扭转它,但人们普遍认为它是不可逆转的。 (至于为什么离题,StackOverflow 与编程问题有关。您所描述的内容与编程的任何特定方面无关。这是密码学的一般问题。)请参阅stackoverflow.com/help/on-topic
-
您是否真的尝试过在 GF(2) 上使用高斯消元法? math.stackexchange.com/questions/169921/…
-
@orlp 感谢您的回答。虽然 IMO 这个问题最初并不适合 Stack Overflow,但我认为以详细而强大的实现形式给出的答案不仅仅是将其引向主题(并暗示这个问题也可能很好)。撤回接近投票。
标签: algorithm hash cryptography reverse-engineering