10

这是我在这个网站上的第一个问题,我对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 在没有填充的情况下是不安全的。这仅仅是因为攻击者可以构建明文/密文字典吗?这是我需要的确定性加密的副作用,以允许审核员验证我的加密,并且在我的方案中,审核员是受信任的,所以可以。

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

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

有谁知道为什么?

编辑 - 使用 NoPadding 加密并不总是产生这个异常 - 它是喜怒无常的。然而,即使加密没有产生这个异常,解密也会产生这个:

javax.crypto.BadPaddingException:数据必须从零开始

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

编辑 - 抱歉,我最初的问题不是很清楚我想要做什么,所以这里有一个 [attempt at an] 解释:

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

抱歉,太长了——我希望它描述了我对确定性加密的需求。我错过了很多基本细节(我已经对这个方案进行了大量修改),但希望核心原则都在那里。非常感谢您阅读 - 我真的很感激。

4

3 回答 3

5

移除填充物会使系统不安全。如果公钥确实是公开的,如您所说,那么攻击者可以简单地转到第 5 列,获取明文,并使用 4 个公钥以正确的顺序对其进行加密。然后,他们可以将生成的密文与接收者的密文进行匹配,从而损害“无强制”属性。

随机填充阻止了这一点,因为攻击者不知道要添加什么填充。

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


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

于 2011-03-31T06:55:35.303 回答
3

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

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

于 2011-03-30T16:03:02.370 回答
1

因此,在我看来,您有 2 个主要要求试图用来deterministic RSA解决:

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

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

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

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

于 2011-03-30T21:19:01.457 回答