我正在编写自己的RSA实现。我发现很难找到正确的方法来选择要加密的数据块的大小。我已经实现了正确的密钥生成,唯一剩下的就是加密(好吧,它已经实现但是它无法正常工作)。
这是我的代码:
template
<
typename NumberType,
typename EncryptionResultType,
typename DecryptionResultType,
typename DataProvider,
typename RandomNumberProvider
>
EncryptionResultType RSAAlgorithm
<
NumberType,
EncryptionResultType,
DecryptionResultType,
DataProvider,
RandomNumberProvider
>
::Encrypt(DataProvider * provider)
{
char * data = provider->ProvideData();
long size = strlen(data);
size_t chunkSize = sizeof(NumberType);
char * result = new char[size];
for(NumberType i=0;i < size;i+=chunkSize)
{
NumberType dataChunkAsNumber = 0;
memcpy(&dataChunkAsNumber,data+i,chunkSize);
NumberType value = ModularPower<NumberType>(dataChunkAsNumber, publicKey, modulus);
memcpy(result+i,&value,chunkSize);
}
return result;
}
将实现任何必要的静态检查(关于隐式转换,DataProvider类型接口的正确性等),但这不是重点:) 关键是 - 给定NumberType(可以是long,或者某些BigNumber库)并且具有NumberType类型的publicKey,我如何计算,或者只是告诉最佳/最有效的数据块大小的算法大小?/ p>
我做了这个尝试。 在我的unerstanding中 - 我们使用memcpy来获取可以在NumberType中保存的一大块文本并使用二进制表示来创建具有相同二进制表示的NumberType(让它称之为Mi)。我们使用模块化电源对其进行加密 - &gt;我们得到另一个NumberType(让我们称之为Ci),在解密后应该给我Mi回来。当我们获取结果的二进制表示并将其memcpy为char *时,我们应该返回文本。但它不会起作用。 任何人都知道我在做什么/理解错误?
编辑::对于测试,我使用了char *,其大小是sizeof(NumberType)的乘法
答案 0 :(得分:2)
简而言之,RSA加密公式为:m^e mod n
,使用公共密钥m
和0 <= m < n
加密(e,n)
邮件n=p*q
。素数p
,q
†。为了实现合理的安全性n
通常具有2048位(即2^2047 < n < 2^2048
)到8192位(即2^8191 < n < 2^8192
)的大小。因此,结果m^e mod n
的位大小为2048位= 256字节或更多。对于解密(c^d mod n
‡),您需要m^e mod n
的完整输出。你不能把它减少到只有一个字节。所以解决问题的一种天真的方法就是炸掉输出大小。
pow(data[i], publicKey)
将创造一个巨大的中间结果。如果e
不小,它将比你的主内存大。相反,fast modular exponentiation methods to a modular operation after each multiplication。在大多数语言和BigNum库中都有一个pow
函数,有三个参数(基数,指数,模数)。
分别加密每个字节是一个坏主意。考虑此攻击:对于每个可能的字节0 <= j < 256
,计算密文c
j
= j^e mod n
。现在您有一个反向加密的查找表。
通常RSA不适合直接加密数据,因为它的确定性加密意味着你总是可以根据给定的密文测试值,还有一些其他不需要的代数属性,RSA本身也很慢。相反,RSA通常用于混合加密方案,其中只有AES(或Salsa20等)的对称密钥通过RSA交换¶,并且使用数据是对称加密的
Cryptography Enginnering中描述了迄今为止我发现的最简单的交换对称密钥的方法。 加密:
b
为n
的位长。通常这意味着b>=2048
。m
区间内选择0,1,2,...,2^(b-1)-1
作为随机数。这比在0,1,2,n-1
区间中选择它更方便,因为您可以采样b
随机位,将最高值位设置为零并将结果解释为BigNum m
。m
(结果为c
)。m
,例如SHA256,用于获取对称密钥k
,并使用k
对称地加密和验证§数据。 c
。)解密:
c
以取回m
。m
是否在0,1,2,...,2^(b-1)-1
区间内。这将为您的方案引入oracle攻击,Bleichenbacher attack。m
以获取对称密钥k
,并使用k
对称地解密和验证您的数据。实施加密技术非常困难并且包含许多隐藏的陷阱,因此您只想自己动手来学习这些概念。 不要在生产代码中使用自己的实现。而是使用Sodium等高级库来让您的生活更轻松,更安全。
†以及0 < e < phi(n)=(p-1)*(q-1)
和gcd(e,phi(n)=1
,但这对于这个问题来说并不是那么重要。
‡其中c=m^e mod n
是密文,0 < d < phi(n)
是e*d ≡ 1 mod phi(n)
。
§身份验证是每个加密协议的重要步骤。解释为什么超出了这个答案的范围。 GCM分组密码模式是一种经过验证的良好加密方案,可以并行加密和验证。
¶请注意,对称密钥未直接加密。在这里,我们从一个随机值中推导出来,该值是从数字0,1,2,...,n-1
的一个大子集中选择的。请参阅答案中的进一步说明。更常用的替代方法是使用OAEP嵌入密钥。但是,我不鼓励OAEP用于新协议,因为它是high susceptibility to side channel attacks。