我正在使用此链接上给出的 RSA 加密代码来使用 128 字节公钥加密字符串,例如以下内容:
[7998725336653383203658644639673805448553730986337128386926545744008381384348409264866333582258561179132241508936069720871865895053632019929236743348039021, 1993938860438750843589842757968313427718259534664174282914852335272086243792497573680387148722647412680490224484736059954284097163105446004304579443902885]
由于字符串太长,
RSA_public_encrypt
函数返回-1
和null
字符串。我知道 RSA 应该用于小尺寸文本,有没有同样的方法?
我使用
ERR_error_string()
检查错误代码,它返回了以下错误代码字符串:error:0406D06E:lib(4):func(109):reason(110)
。
既然这个问题已被标记为可能重复,那么请让我解释一下,我只需要使用 RSA 来完成它,因为 AES-RSA 组合将使我正在编写的 chrome 扩展的整个系统设计变得更加复杂比现在更。我想尽可能简化它。
上面的答案已经提到了 RSA-AES。 这是正确的做法。 您使用 RSA 来交易一条小消息(对称密钥),然后您可以使用该会话密钥来进行任何您想要的交谈。
您知道,RSA 的限制是数学上的限制。 我曾经看到有人抱怨 MS 不允许他们的 RSA 为他们的目的加密足够大的消息。 问题是,一旦消息的数字长度达到密钥的 1/2 左右,它就会在数学函数中“翻转”到零以上——超过数字字段的上限——并且不会解密到与开始时的编号相同。 因此,除非在有限的意义上使用更大的 RSA 密钥,否则无法克服此限制。 或者通过对消息进行分块并以 RSA 形式单独发送所有消息,但不鼓励使用相同的公钥/私钥对进行多重加密。
我真的建议您使用 RSA/AES 混合算法。 通过这种方式,您将获得比我能想到的任何其他方式更好的性能。
构建某种 RSA 分块方案将比解密对称密钥并使用该密钥执行简单的 AES 解密要复杂得多,并且可能不安全。
就效率而言,RSA 将比 AES 慢几个数量级,因此您所做的权衡是放弃简单性(即放弃使用 AES 的简单性,转而使用某些 RSA”分块”),但性能较差(RSA 性能较慢。)
我会采用混合 AES-RSA 方法的老路,而不是尝试一些仅 RSA 的方案。
如果必须严格使用 RSA,则需要将消息分割成等于 RSA 密钥大小的块,并多次应用 RSA。 但请注意,这样做意味着每个加密块都有自己的填充,并且 RSA 的计算成本比 AES 高得多。
如果您要加密的消息足够大,不仅需要更多时间来处理,而且 RSA 加密的消息可能比 RSA 加密的 AES 密钥加上 AES 加密的消息更大。
使用 OAEP 填充块
用于加密:
def encrypt(self, plaintext):
if not hasattr(self, 'n') or not hasattr(self, 'e'):
raise AttributeError("Public key not imported")
block_size = self.key_size // 8 - 11 # OAEP padding requires at least 11 bytes
encrypted_blocks = []
for i in range(0, len(plaintext), block_size):
block = plaintext[i:i+block_size]
m = int.from_bytes(block.encode(), 'big')
c = pow(m, self.e, self.n)
encrypted_blocks.append(str(c))
return b64encode(','.join(encrypted_blocks).encode())
对于解密,您可以使用 ProcessPoolExecutor 对于 4096 以上的密钥(假设是 8192),解密速度会更快
def decrypt(self, ciphertext):
if not hasattr(self, 'n') or not hasattr(self, 'd'):
raise AttributeError("Private key not imported")
ciphertext = b64decode(ciphertext).decode().split(',')
if self.n.bit_length() < 4100:
decrypted_blocks = []
for c in ciphertext:
m = pow(int(c), self.d, self.n)
decrypted_block = m.to_bytes((m.bit_length() + 7) // 8, 'big').decode('utf-8', errors='ignore')
decrypted_blocks.append(decrypted_block)
return "".join(decrypted_blocks)
else:
# Convert d and n to gmpy2 objects for faster calculations
d = gmpy2.mpz(self.d)
n = gmpy2.mpz(self.n)
# Use multiprocessing to parallelize decryption
with ProcessPoolExecutor(max_workers=os.cpu_count()) as executor:
# Include indices to preserve order
futures = {executor.submit(decrypt_block, (c, d, n)): i for i, c in enumerate(ciphertext)}
# Collect results in order of their original blocks
decrypted_blocks = [None] * len(ciphertext)
for future in as_completed(futures):
decrypted_blocks[futures[future]] = future.result()
return ''.join(decrypted_blocks)
我在 Windows 上,所以我使用了 as_completed 你可以在 Unix 系统上使用普通的 ProcessPoolExecutor