有谁能为我10岁的儿子正在尝试的Python项目提供一些广泛的指导呢?我不太想寻找具体的编码解决方案,但我希望这是一个问这个问题的好地方。我想知道的是,我的儿子是否对他的编码项目有所了解,以及是否有一个相对简单的方法让他学习正确的步骤。或者,对于一个10岁喜欢阅读和尝试各种编码项目只是为了好玩的人来说,这是不可能的吗?正如你所看到的,我不是一个程序员,对这类项目知之甚少,所以我会感激你的耐心和善意!
我儿子对密码学很感兴趣,他告诉我他尝试了下面的Python代码。他希望建立一个类似海绵的功能来加密按摩,使其无法解密。这是受他的著作“严肃密码学”(J.Aumasson)中的一个章节的启发,标题为“基于排列的散列函数:海绵函数”。当他运行他编写的代码时,他会得到错误消息"TypeError:<<:'str‘和’int‘的不受支持的操作数类型(参见代码下面终端中的交互)。
非常感谢!亚历山大
这是他的密码:
import math
import textwrap
plaintext = raw_input("The value to be hashed: ") # Get the user to input the data to be hashed
nonce = raw_input("The nonce to be used: ") # Get the user to input the nonce to be used
key = raw_input("The key to be used: ") # Get the user to input the key to be used
blocks = textwrap.wrap(plaintext, 16) # Split the string into 128-bit blocks
if len(blocks[len(blocks)-1]) < 16: # Check if the last block is less than 128 bits
while len(blocks[len(blocks)-1]) < 16: # Keep iterating the following code
blocks[len(blocks)-1] += "." # Add padding to the end of the block to make it 128-bit
sponge = nonce # Set the sponge's initial state to that of the nonce
for j in blocks: # Absorb all of the blocks
sponge = (sponge << 128) + j # Concatenate the current sponge value and the block
sponge = textwrap.wrap(sponge, 128) # Convert the sponge into 128-bit blocks
for z in sponge: # Keep iterating the following code
z = z^j # XOR the sponge block with the message block
sponge = join(sponge) # Convert the blocks back into a string
sponge = textwrap.wrap(sponge, len(key)*8) # Convert the sponge into blocks with the same length of the key
output = sponge # Create a new variable to save space
del nonce, blocks # Delete variables to save space
while len(output) > 1: # Keep iterating the following code
output[1] = output[1]^output[0] >> output[0] # XOR the second element with the first, then shift forward
del output[0] # Delete the first element, so it can repeat again
tag = ((output^plaintext) <<< sponge) + output # Generate an authentication tag. That's not overkill, is it?
print output # Oh yeah, just print it in hexadecimal, I dunno how to当他在终端中运行脚本时,这就是交互:
要散列的值: abcioagdsbvasizfuvbosuif
例外情况:
Traceback (most recent call last):
File "DarkKnight-Sponge.py", line 13, in <module>
sponge = (sponge << 128) + j # Concatenate the current sponge value and the block
TypeError: unsupported operand type(s) for <<: 'str' and 'int'发布于 2020-09-02 11:25:13
恭喜你儿子!这个项目在我看来很现实。我唯一能想到的野心勃勃的事情就是直接钻研像<<和^这样的位运算符,而不是尝试对字符序列实现相应的操作。位运算符有时看起来像算术黑魔法,因为它们操纵数字的内部二进制表示,我们不像数字的十进制表示法或文本那样熟悉它。
理解错误信息
TypeError: unsupported operand type(s) for <<: 'str' and 'int'这个错误非常简单:它说不能执行sponge << 128操作,因为sponge是一个str,即(字符)字符串,即它的文本,而128是一个int,即一个整数。
想象一下,如果您要求计算机计算"three" + 2。它将返回一个错误,因为+需要两个数字,但是"three"是一个字符串,而不是数字。类似地,如果您要求计算机计算"327" + 173,它将返回一个错误,因为"327"是文本,而不是数字。
了解发生错误的行
运算符<<是左位移位运算符。它将一个数字向左移动一定数量的位。计算机以二进制表示形式存储数字;我们人类更习惯于十进制表示,所以让我们用“左转数字移位”操作来进行分析。“向左移动一个数字”将意味着将其乘以10的幂。例如,138个移到左边的数字将是13800。我们在右边用零填充。在二进制表示中,位移位的工作原理是相同的,但是它的乘幂为2。在二进制表示中,1110110是138个;将它向左移动两次会给出111011000,这与将其乘以100 (即4)相同。
如果sponge和j都是数字,且j小于2^128,则行:
sponge = (sponge << 128) + j # Concatenate the current sponge value and the block将sponge向左移动128位,然后将小于128位的数字添加到结果中。实际上,这是将sponge的比特与j的比特连接起来。回到我们的十进制类比:如果x是一个数字,而y是一个小于100的数字,那么数字x * 100 + y就是将x和y的数字连在一起得到的数字。例如,1374 * 100 + 56 = 137456。
解决问题
我还没有读过启发这段代码的密码学书,所以我只是从现在开始猜测。
我的理解是,这本书期望plaintext、nonce和key是数字。然而,在你儿子的代码中,它们都是文本。这两种类型的对象之间的区别并非不可调和。在计算机的内存中,一切都是以位序列的形式存储的。数字是位的序列;字符串是字符的序列,每个字符本身是位的短序列。
我看到了三种可能性:(1)在执行操作之前将所有文本转换为数字;(2)调整操作,使它们可以应用于字符串而不是ints;(3)将所有文本转换为仅包含字符0和1的字符串,并对操作进行调整,以便将它们应用于这些序列。在现实世界中,密码算法的高效实现无疑都选择了第二种方案。第三种选择显然是这三种方法中效率较低的,但就学习目的而言,这是一种可能的选择。
查看您的代码,我注意到所有使用的操作都是关于对序列的操作,而不是关于算术操作。正如我所提到的,(sponge << 128) + j是两个位序列的级联。代码中稍后使用的按位xor操作需要两个相同长度的位序列,并在两个序列具有不同比特的每个位置返回与1相同长度的序列,在两个序列具有相同比特的每个位置返回0。例如,00010110 ^ 00110111 = 00100001,因为第三位和第八位是不同的,但是所有其他位都是相等的。
将文本转换为int
要将文本转换为数字(我称之为选项2),可以用以下行替换代码的前三行:
plaintext_string = raw_input("The value to be hashed: ") # Get the user to input the data to be hashed
nonce_string = raw_input("The nonce to be used: ") # Get the user to input the nonce to be used
key_string = raw_input("The key to be used: ") # Get the user to input the key to be used
def string_to_int(txt):
number = 0
for c in txt:
number = (number << 8) + ord(c)
return number
plaintext = string_to_int(plaintext_string)
nonce = string_to_int(plaintext_string)
key = string_to_int(key_string)如何工作:每个ascii字符c都由python函数ord映射到一个8位数字。使用公式number = (number << 8) + ord(c)连接8位块,您可以从上面的讨论中认识到这一点。
这不足以使您的代码正常工作,因为随后直接使用的textwrap.wrap()函数需要字符串,而不是int。一种可能性是将textwrap.wrap()函数替换为自定义函数text_to_intblocks()
def string_to_intblocks(txt, blocksize):
blocks = []
block_number = 0
for i,c in enumerate(txt):
block_number = (block_number << 8) + ord(c)
if i % blocksize == 0:
blocks.append(block_number)
block_number = 0
return blocks然后将blocks = textwrap.wrap(plaintext, 16)替换为blocks = string_to_intblocks(plaintext_string, 16)。
这仍然不足以修复你儿子的代码。我确信在以下六行中存在逻辑错误,尽管修复它需要比我目前更好地理解算法:
sponge = nonce # Set the sponge's initial state to that of the nonce
for j in blocks: # Absorb all of the blocks
sponge = (sponge << 128) + j # Concatenate the current sponge value and the block
sponge = textwrap.wrap(sponge, 128) # Convert the sponge into 128-bit blocks
for z in sponge: # Keep iterating the following code
z = z^j # XOR the sponge block with the message block
sponge = join(sponge)https://stackoverflow.com/questions/63703737
复制相似问题