Java 中的确定性 RSA 加密

发布于 2024-10-28 00:59:34 字数 2827 浏览 7 评论 0原文

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

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

从本质上讲,我的问题是我希望能够为某人提供审计员的角色:

  • 一个字节数组(要加密的明文)
  • 一个RSA公钥文件
  • 一个“目的地< /em>" 字节数组,这是我自己计算给定明文和公钥的密文数据的结果,

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

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

无论如何,我发现在 Java 中, using

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:数据必须从零开始

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

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

  • 明文是选民在选举中的投票。
  • 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 列中的条目。
  • 总而言之,这提供了端到端-最终可验证性。

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

This is my first question on this site, and I only have a basic mathematical understanding of RSA, so please bear with me! :)

I'm writing a Java web application for my final year project at university. It's a web-based implementation of "Pret-a-voter", a secure voting system, for those who have heard of it.

Essentially my problem is that I want to be able to give someone performing the role of an auditor:

  • a source byte array (the plaintext to be encrypted)
  • an RSA public key file
  • a "destination" byte array, which is the result of my own computation of the cipherdata given the plaintext and the public key

I then want the auditor to be able to perform encryption using the first two items, and be satisfied that the third is the result. I therefore need the encryption to be deterministic, i.e. generate the same cipherdata each time encryption with the same plaintext and public key are repeated.

(Note - I'm working with very small blocks of data in this project - there is no symmetric encryption involved at all... I'm aware this is an "interesting" use of RSA!)

Anyway I found that in Java, using

cipher = Cipher.getInstance("RSA");

uses the default random padding scheme, at a cost of 11 bytes (so with a 2048-bit key pair, it's possible to encrypt 2048/8-11 = 245 bytes). Repeated encryptions of the same plaintext generate different ciphertexts, which is obviously not the ECB mode that I want.

My question is - should I use the following?

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

I've read in lots of places that RSA is insecure without padding. Is that simply because an attacker can build a dictionary of plaintexts/ciphertexts? This is a side-effect of the deterministic encryption I require in order to allow auditors to verify my encryption, and in my scheme auditors are trusted, so that would be OK.

Part two of my question is more java-related. If I do use RSA/ECB/NoPadding as above, I believe I'm able to provide a source byte array of (say) length 128 (for a 1024-bit RSA key pair) and encrypt that to get another byte array of length 128. If I then try to encrypt that again, with a different 1024-length public key, I get

javax.crypto.BadPaddingException: Message is larger than modulus

Does anyone know why?

EDIT - encryption with NoPadding doesn't always generate this exception - it's temperamental. However, even when encryption does not generate this exception, decryption generates this:

javax.crypto.BadPaddingException: Data must start with zero

Many thanks for reading through this! Any help would be greatly appreciated.

EDIT - sorry, my original question wasn't very clear about what it is I want to do, so here's an [attempt at an] explanation:

  • The plaintext is a voter's vote in an election.
  • Pret-a-voter aims to be end-to-end verifiable without sacrificing voter confidentiality (etc). After voting, the voter is provided with a receipt that they can use to verify that their vote has been recorded correctly, and which will later show them that their vote has not been tampered with. The voter performs a comparison of the information on their receipt with an identical copy posted on the web.
  • However, it should not be possible for any voter to prove how he/she voted (as that could lead to coercion) so the information is not the plaintext, but an encrypted copy of the vote.
  • In fact, the plaintext is encrypted four times, with four different asymmetric keys - held by two different tellers, each holding two of the keys. So, a vote (plaintext) is provided to one teller, who encrypts it using public key #1, and then encrypts THAT ciphertext with his second public key, gives THAT ciphertext to the second teller who encrypts it with his two keys in the same way. The resulting ciphertext (result of four sequential encryptions) is what is posted to the web (made public). The tellers are trusted.
  • Each encrypted vote can be visualised as an "onion" where the centre is the vote and there are several layers of encryption. In order to get to the vote, each layer must be removed in turn, meaning the corresponding private keys (held by the tellers) must be applied in the reverse sequence. This is key to the security - all tellers must work cooperatively in order to decrypt the votes.
  • The web bulletin board can be visualised as a table with 5 columns - the first (on the left) holds the fully-encrypted votes (also shown on each voter's receipt), and is the only visible column during the vote-casting stage. The second column contains the same set of votes, but with the outer layer removed - teller 2 populates this column and column 3 by decrypting the votes using its private keys during the tallying stage. At the end of the tallying stage, column 5 contains the fully-decrypted votes that can then be tallied.
  • Each voter gets a receipt that links them to an encrypted vote in column 1. This doesn't show how they voted, but allows them to verify that their vote has not been tampered with as throughout the election process they can verify that their encrypted vote is still there in column 1, untouched. This is only half of the "end-to-end verification", of course, since voters are unable to verify that the decryptions have been done correctly, i.e. that there's an entry in column 2 which is their vote minus the outer layer of encryption. Each voter is responsible only for the verification UP TO the point of column 1.
  • Thereafter, it is the auditors' responsibility to check that the entries in column 1 decrypt to column 2, and so on. The way they do this is by relying on deterministic encryption and the public keys used for the encryption being public.
  • Since public keys are public, you don't want people to simply draw lines from column 5 to column 1, joining up someone's vote as it becomes repeatedly encrypted - that way, a receipt that ties you to an encrypted vote actually ties you to an unencrypted, readable vote --> coercion! So, only columns 1, 3 and 5 are public (this is why each teller performs TWO encryptions), and for each entry in column 3, only ONE of the corresponding entries in {2,4} are revealed to auditors. This prevents anyone (even auditors) from linking an encrypted vote to an unencrypted vote.
  • Auditors therefore need to take an entry in column 3, be given the corresponding entry in column 2 and the public key, and perform the same encryption to verify that they do indeed get the entry in column 2.
  • Put together, this offers end-to-end verifiability.

Sorry that was so lengthy - I hope it describes my need for deterministic encryptions. I've missed out a lot of fundamental details (I've modified this scheme heavily) but hopefully the core principles are all there. Thank you so much for reading - I really appreciate it.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

怪我闹别瞎闹 2024-11-04 00:59:34

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

随机填充可以阻止这种情况,因为攻击者不知道要添加什么填充。

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


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

Removing the padding makes the system insecure. If the public keys are indeed public, as you say, then an attacker can simply go to column 5, take the plaintexts, and encrypt them with the 4 public keys in the proper sequence. They can then match up the resulting ciphertexts with that from the reciepts, compromising the "no coercion" property.

Random padding stops this, because the attacker doesn't know what padding to add.

You will need to use normal padding, but reveal a subset of the private keys to a subset of the auditors (usually called "scrutineers" in electoral systems). This means that one scrutineer can confirm that column 1 matches column 2, another can confirm that column 2 matches column 3, and so on. An individual scrutineer can't match a voter to a ballot, only co-operating ones.


The reason that you're getting the "Message is larger than modulus" error is because each modulus is different, so the ciphertext from one encryption may be outside the allowable range for the next encryption.

筑梦 2024-11-04 00:59:34

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

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

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

The padding is there precisely to avoid a given plain text being encrypted to a single cyphertext. So if you want a deterministic (single) result for any given plain text your only option is to turn it off.

辞别 2024-11-04 00:59:34

因此,在我看来,您尝试使用确定性 RSA 来解决两个主要要求:

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

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

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

您可能要考虑的下一件事是通过对投票或类似的东西。据我了解您的架构,看起来如果我以某种方式访问​​您存储投票的位置(或进入任何通信的中间),我基本上可以通过重播或复制我已经拥有的数据来欺骗或垃圾邮件假投票看到(确定性的另一个问题)。

So it seems to me that you have 2 main requirements that you are attempting to use deterministic RSA to solve:

  1. Allowing voters to ensure the integrity of their vote
  2. Allowing auditors to ensure the integrity of all votes

Digital Signatures should solve this problem. You can take your ciphertext from column 1, hash it, and encrypt the hash with a private key. That encrypted hash can then be placed in column 2. To verify the integrity of column 1, simply use the corresponding public key to decrypt the hash in column 2, hash column 1, and compare those 2 values. If they are equal, the data has not been tampered with. Only parties that have the private key could possibly tamper with the data in these columns, because only they can make a matching pair. This is similar to an HMAC, but has the advantage of using public/private keys rather than a secret shared key. Thus anybody can verify, but only trusted parties can modify.

One thing to note about deterministic schema is that it will leak information in many ways. Let's assume that I know I voted for Blue as my favorite color. I can see that the resulting ciphertext of my vote is 0x12345678. If the schema is completely deterministic, I know that anybody else that has a corresponding ciphertext of 0x12345678 also voted for Blue. Also, since you will typically have a finite set of vote choices, a chosen plaintext attack is incredibly easy. Thus you really want to let RSA do its job and use the intended padding scheme.

The next thing you may want to consider is protecting the system from a form of Replay Attack by numbering the votes or something like that. As I understand your schema, it looks like if I somehow got access to where you store your votes (or got in the middle of any communication), I could essentially spoof or spam fake votes just by replaying or copying data that I've already seen (another problem with being deterministic).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文