Java中的确定性RSA加密

这是我在这个网站上的第一个问题,我对RSA只有基本的数学理解,所以请耐心等待! 🙂

我正在为大学的最后一年项目编写一个Java Web应用程序。 这是一个基于网络的“Pret-a-voter”实施,这是一个安全的投票系统,适用于那些听过它的人。

基本上我的问题是我希望能够给某人履行审计员的角色:

  • 字节数组(要加密的明文)
  • RSA公钥文件
  • 一个“ 目标 ”字节数组,这是我自己计算明文和公钥的密码数据的结果

然后,我希望审计员能够使用前两项执行加密,并确信第三项是结果。 因此,我需要加密是确定性的 ,即每次重复使用相同的明文和公钥加密时生成相同的密码数据。

(注意 – 我正在使用这个项目中的非常小的数据块 – 根本没有涉及对称加密……我知道这是RSA的“有趣”使用!)

无论如何,我发现在Java中,使用

cipher = Cipher.getInstance("RSA"); 

使用默认的随机填充方案,成本为11个字节(因此,对于2048位密钥对,可以加密2048 / 8-11 = 245个字节)。 对同一明文的重复加密会产生不同的密文,这显然不是我想要的ECB模式。

我的问题是 – 我应该使用以下内容吗?

 cipher = Cipher.getInstance("RSA/ECB/NoPadding"); 

我已经在很多地方看到RSA没有填充而不安全。 这仅仅是因为攻击者可以建立明文/密文字典吗? 这是我需要的确定性加密的副作用,以便允许审核员validation我的加密,并且在我的方案中,审核员是可信的 ,这样就可以了。

我的问题的第二部分是与java相关的。 如果我确实如上所述使用RSA / ECB / NoPadding,我相信我能够提供(例如)长度128(对于1024位RSA密钥对)的源字节数组并加密以获得另一个长度的字节数组128.如果我再次尝试使用不同的1024长度公钥加密,我得到

javax.crypto.BadPaddingException:消息大于模数

有谁知道为什么?

编辑 – 使用NoPadding加密并不总是会产生这种exception – 这是一种性情。 但是,即使加密不会生成此exception,解密也会生成:

javax.crypto.BadPaddingException:数据必须以零开头

非常感谢您阅读本文! 任何帮助将不胜感激。

编辑 – 对不起,我原来的问题不是很清楚我想做什么,所以这是一个[尝试]解释:

  • 明文是选举中投票人的投票。
  • 选民之前的目的是在不牺牲选民保密性的情况下进行端到端的可核实(等)。 投票后,选民可获得一张收据,他们可以用来核实他们的投票是否被正确记录,以及后来会告诉他们投票没有被篡改。 选民将收据上的信息与网上发布的相同副本进行比较。
  • 但是,任何选民都不应该certificate他/她投票的方式(因为这可能导致强制),因此信息不是明文,而是加密的投票副本。
  • 事实上,明文被加密了四次,有四个不同的非对称密钥 – 由两个不同的柜员持有,每个柜员拿着两把钥匙。 因此,投票(明文)被提供给一个柜员,他使用公钥#1加密它,然后用他的第二个公钥加密THAT密文,给那个用他的两个密钥加密它的第二个出纳员提供密文。办法。 生成的密文(四个连续加密的结果)是发布到Web(公开)的内容。 出纳员是值得信赖的。
  • 每个加密的投票都可以看作是一个“洋葱”,其中心是投票,并且有几层加密。 为了进行投票,必须依次删除每一层,这意味着必须以相反的顺序应用相应的私钥(由出纳员持有)。 这是安全的关键 – 所有出纳员必须合作才能解密投票。
  • 网络公告板可以显示为一个包含5列的表格 – 第一列(左侧)包含完全加密的投票(也显示在每个选民的收据上),并且是投票阶段唯一可见的列。 第二列包含相同的投票集,但删除了外层 – 柜员2通过在统计阶段使用其私钥解密投票来填充此列和第3列。 在计数阶段结束时,第5列包含完全解密的投票,然后可以计算。
  • 每个选民都会得到一张收据,将收据与第1栏中的加密投票联系起来。这并未显示他们如何投票,但允许他们核实他们的投票未被篡改,因为在整个选举过程中他们可以validation他们的加密投票第1栏仍然存在,未触动过。 当然,这只是“端到端validation”的一半,因为选民无法validation解密是否已正确完成,即第2列中有一个条目是他们的投票减去外层加密。 每个选民只负责validation到第1栏的点。
  • 此后,审核员有责任检查第1列中的条目是否解密到第2列,依此类推。 他们这样做的方式是依靠确定性加密和用于加密的公钥是公开的。
  • 由于公钥是公开的,你不希望人们只是简单地从第5列到第1列画线,加入某人的投票,因为它变得反复加密 – 这样,将你绑定到加密投票的收据实际上将你绑定到未加密,可读的投票 – >强制! 因此,只有第1,3和5列是公共的(这就是每个出纳员执行两次加密的原因),对于第3列中的每个条目,{2,4}中只有一个相应的条目被透露给审计员。 这可以防止任何人(甚至是审计员)将加密的投票链接到未加密的投票。
  • 因此,审计人员需要在第3列中输入一个条目,在第2列和公钥中给出相应的条目,并执行相同的加密以validation它们确实在第2列中获得了条目。
  • 总而言之,这提供了端到端的可validation性。

很抱歉这是如此冗长 – 我希望它描述了我对确定性加密的需求。 我错过了很多基本细节(我已经大量修改了这个方案),但希望核心原则都存在。 非常感谢你阅读 – 我真的很感激。

删除填充会使系统不安全。 如果公钥真的是公共的,正如你所说的那样,那么攻击者可以简单地进入第5列,获取明文,然后按照正确的顺序用4个公钥对它们进行加密。 然后,他们可以将得到的密文与来自接收的密文进行匹配,从而损害“无强制”属性。

随机填充会阻止此操作,因为攻击者不知道要添加什么填充。

您将需要使用普通填充,但将一部分私钥显示给审核员的子集(通常在选举系统中称为“监督员”)。 这意味着一个监督员可以确认第1列与第2列匹配,另一个可以确认第2列与第3列匹配,依此类推。 个人监票人无法将选民与选票相匹配,只能与合作者进行合作。


您收到“消息大于模数”错误的原因是因为每个模数不同,因此来自一个加密的密文可能超出下一次加密的允许范围。

https://en.wikipedia.org/wiki/RSA_(cryptosystem)#Padding

填充正是为了避免将给定的纯文本加密为单个密文。 因此,如果您想要任何给定纯文本的确定性(单个)结果,您唯一的选择是将其关闭。

因此,在我看来,您有两个主要要求,即您尝试使用deterministic RSA来解决:

  1. 允许选民确保投票的完整性
  2. 允许审计员确保所有投票的完整性

数字签名应该可以解决这个问题。 您可以从第1列获取密文,对其进行哈希处理,并使用私钥加密哈希。 然后可以将加密的哈希放在第2列中。要validation第1列的完整性,只需使用相应的公钥解密第2列哈希列1中的哈希值,然后比较这2个值。 如果它们相等,则数据未被篡改。 只有拥有私钥的各方才有可能篡改这些列中的数据,因为只有他们才能建立匹配对。 这类似于HMAC,但具有使用公钥/私钥而不是秘密共享密钥的优点。 因此任何人都可以validation,但只有受信任方可以修改。

有关确定性模式的一点需要注意的是,它会以多种方式泄露信息。 让我们假设我知道我投了Blue作为我最喜欢的颜色。 我可以看到我投票的结果密文是0x12345678。 如果模式是完全确定的,我知道任何拥有相应密文0x12345678的人也投票给Blue 。 此外,由于您通常会有一组有限的投票选择,因此选择的明文攻击非常容易。 因此,您真的希望让RSA完成其工作并使用预期的填充方案。

您可能想要考虑的下一件事是通过对投票或类似事件进行编号来保护系统免受重播攻击的影响。 正如我理解你的架构,看起来如果我以某种方式访问​​你存储你的投票的地方(或进入任何通信的中间),我本可以通过重播或复制我已经已经存在的数据来欺骗或发送虚假投票看到了(确定性的另一个问题)。