(对于学校)我正在尝试进行简单的 RSA 加密,将字符串加密为三个字母的块。 我可以更改什么以使数学能够使用字符串而不仅仅是整数?
import math
message = str(input("Enter Plaintext: "))
p = 521
q = 757
e = 11
n = p*q
def encrypt(me):
en = math.pow(me, e)
c = en % n
print("Encrypted Message is: ", c)
return c
print("Original Message is: ", message)
c = encrypt(message)
Enter Plaintext: zallaboardty
Original Message is: zallaboardty
line 18, in <module>
c = encrypt(message)
line 11, in encrypt
en = math.pow(me, e)
TypeError: must be real number, not str
Process finished with exit code 1
教科书RSA中的消息大小是由模数的大小决定的。因此,模数 n 为 521 x 757。这允许 log_2(521 x 757) / 3 = 每个字符约 6.19 位。因此每个字符只能占用 6 位,即它的范围是 [0..2^6) = [0..64) 个字符。 ASCII 是每个字符 7 位,所以这有点烦人,因为我们不能直接使用它。
让我们简单一点,用小数来计算。我们可以计算出 n 为 521 x 757 = 394397。这意味着我们可以通过连接三个两位数来构造一个低于 n 的数字,只要该数字低于 394397。如果我们使用 39 或以下的数字,这将始终有效。我们现在可以创建最多 40 个字符的字母表(因为我们可以包含零个字符)。
让我们为包含 ABC 的 28 个字符的字母表定义一个字母表 SPACE=0、A=1...Z=26 和 DOT=27。太好了,现在我们只需首先将消息转换为索引,例如: “你好世界。”可分为“HEL”、“LO”、“WOR”和“LD”。所以你取H=“08”,E=“05”en L=“12”,所以我们得到的数字是“080512”或080512。太好了,你现在有了一个可以由RSA处理的数字。请注意,数字必须在左侧填充零才能使该方案发挥作用。
现在小数使用基数 10。您还可以使用基数 2^6(记住上面每个字符 ~6.19 位)并从二进制创建一个数字。然而,对于初学者来说,使用小数和字符串更容易。
如您所知,尝试对字符串而不是数字使用 math.pow 将导致类型错误。要解决此问题,您可以将字符串转换为实数,方法是首先在
encode
(在您的函数中)上使用 me
将其转换为字节,然后使用 int.frombytes
将字节转换为整数。您可以这样做:
me = int.from_bytes(me.encode('utf-8'), byteorder="big")
RSA 没有明确要求使用 UTF-8 或特定的字节顺序(如 big-endian)。这样做只是为了遵循通用标准并确保兼容性,但选择权在您。
另一个小问题是您使用的是 math.pow,这在处理大整数时可能会导致精度错误。相反,您应该使用 pow(内置 Python 函数)采用模幂方法,该方法针对此类操作进行了优化。您更正后的代码将是:
c = pow(me, e, n)
现在,你的函数应该看起来像这样:
def encrypt(me):
me = int.from_bytes(me.encode('utf-8'), byteorder="big")
c = pow(me, e, n)
print("Encrypted Message is: ", c)
return c