RSA私钥加密

4

有没有办法在C#中执行私钥加密

我知道标准的System.Security.Cryptography中的RSACryptoServiceProvider,但这些类仅提供公钥加密私钥解密。此外,它们提供数字签名功能,该功能内部使用私钥加密,但没有任何公开可访问的函数来执行私钥加密公钥解密

我找到了this article on codeproject,这是执行此类加密的非常好的起点,但是,我正在寻找一些现成的代码,因为文章中的代码几乎无法加密包含随机值(即任何值,包括零)的任意长字节数组。

您知道一些好的组件(最好是免费的)来执行私钥加密吗?
我使用.NET 3.5

注意:我知道使用非对称加密(使用私钥加密和使用公钥解密)通常被认为是不好的方式,但我只需要以这种方式使用它。

额外说明

假设你有

var bytes = new byte[30] { /* ... */ };

如果您想使用 2048位RSA 来确保没有人更改了这个数组中的任何内容。

通常,您会使用数字签名(即 RIPEMD160),然后将其附加到原始字节并发送给接收者。

因此,您有 30个字节 的原始数据和 额外的256个字节 的数字签名(因为它是 2048位RSA),总共是 286个字节。但是,其中只有 256个字节 中的 160位 实际上是哈希值,因此还有 1888位236个字节)未使用。

所以,我的想法是:

取出 30个字节 的原始数据,将哈希值(20个字节)附加到其中,现在加密这些 50个字节。您将得到一个长度为 256个字节 的消息,比 286个字节 短得多,因为“您能够将实际数据推入数字签名中”。

ECDSA 资源

[MSDN](https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.ecdsacng?view=net-7.0) [Eggheadcafe.com](http://www.eggheadcafe.com/software/aspnet/31670677/ecdsacng-elliptic-curve-c.aspx) [c-plusplus.de](https://www-c--plusplus-net.translate.goog/forum/topic/205305/ecdsa-private-key-exportieren?_x_tr_sl=de&_x_tr_tl=en&_x_tr_hl=en) [MSDN Blog](https://learn.microsoft.com/en-us/archive/blogs/shawnfa/elliptic-curve-dsa) [Wiki](https://en.wikipedia.org/wiki/Elliptic_Curve_DSA)

DSA 资源

CodeProject
MSDN 1
MSDN 2
MSDN 3

最终解决方案

如果有人对我是如何解决这个问题感兴趣,我将使用 1024位DSASHA1,这在许多不同版本的Windows(Windows 2000及更高版本)上得到广泛支持,安全性足够好(我不签署订单,我只需要确保某些孩子无法破解他的iPhone上的签名(:-D)),而签名大小仅为40字节

3
使用私钥进行加密是用于签名的。其思想是任何人都可以解密它(因为他们拥有你的公钥),但只有你才能加密它。通常,你只会加密一个哈希值。 - Steven Sudit
1
如果你只是想签署一个文件,不要重新发明轮子。在http://msdn.microsoft.com/en-us/library/ms229745(v=VS.85).aspx上有.NET指令。 - Steven Sudit
@Steven Sudit:我知道这一切,这就是为什么我写了“注意:...”。但我需要使用私钥加密来加密任意长度的字节数组(不仅仅是哈希值),你不需要知道为什么。 :-) - Paya
@AaronLS:随机值指的是任何值,包括零值。 - Paya
事实上,不使用纯公钥加密有一个很好的理由,那就是它容易受到中间人攻击的影响,而混合方法(仅使用 PKC 作为会话密钥)则不会。 - Steven Sudit
显示剩余11条评论
4个回答

3
你正在尝试设计的是一种“具有消息恢复功能的签名方案”。设计新的签名方案很困难,设计具有消息恢复功能的签名方案更加困难。我不知道你的设计细节,但很可能容易受到选择消息攻击的影响。
一种提议的具有消息恢复功能的签名方案是RSA PSS-R。但不幸的是,这个提议被专利覆盖。
IEEE P1363标准化组曾经讨论过添加具有消息恢复功能的签名方案。然而,我不确定这项工作的当前状态,但值得了解一下。

1
+1,唯一一个回答正确的人。有一个现有的标准ISO 9796-3,可以做到这件事。如果我没记错的话,它并不是非常直观。 - President James K. Polk
有没有 ISO 9796-3 的 C# 实现?如果没有,那我就不能使用它了。 :-( 而且自己实现也不可能,因为我没有实现加密标准的经验。 - Paya
据我所知,以及我相信早期版本存在攻击。Bouncycastle似乎有一个9796-2的实现,但是你已经有一个不错的解决方案了。 - President James K. Polk
哇,这是“唯一一个做对了”的人,但 Paja 将会选择 DSA,这是我提出的选项。他们忘得真快。 - Steven Sudit
在我看来,Paja正在做正确的事情。第一步是探索所有选项。将消息的一部分打包到签名中是一种选择。而探索这个选择的可行性就是问题所在。一旦所有选项都在桌面上,人们就可以做出决定。对于Paja来说,支持似乎是最重要的因素。对于其他面临类似问题的读者来说,更快的RSA签名验证可能更为重要。 - Accipitridae
@GregS 为什么Paja的解决方案还不错,因为我不相信DSA能做ISO 9796-2所做的事情。我可能是错的。 - Jon

2
你的公钥是私钥的子集。可以使用私钥作为公钥,因为它只会使用所需的完整密钥的组件。
在.NET中,你的私钥和公钥都存储在RSAParameters结构中。该结构包含以下字段:
D DP DQ Exponent InverseQ Modulus P Q

在被擦除的答案中,我提到您可能可以将私钥传递给该方法,而不是公钥,反之亦然。尽管如此,我仍然不建议这样做。 - Steven Sudit
如果您传入您的公钥,它会要求使用您的私钥还是公钥进行解密? - Steven Sudit
是的,但我如何使用私钥进行加密?我不想使用私钥的公共部分,而是使用私钥本身。也就是说 - (data ^ D) % Modulus,而不是(data ^ Exponent)% Modulus。 - Paya

2
如果数据很小,数字签名相对庞大,那么就存在过多的签名。解决方案不是自己编写算法,而是减少已有内容。绝不能试图以业余方式将密钥与哈希组合在一起:这已经被攻破了,这就是为什么我们需要HMAC的原因。
因此,基本思路如下:
1. 使用密码学强RNG创建会话密钥。 2. 通过PKE传输它。 3. 使用会话密钥生成HMAC-SHA1(或HMAC-RIPEMD160等)。 4. 如果哈希值大小与给定数据荒谬地大,则通过异或顶部和底部将其减半。必要时重复此过程。 5. 发送数据和(可能被缩小的)哈希值。 6. 接收方使用数据和会话密钥重新生成哈希值,然后将其与传输的哈希值进行比较(可能在首次缩小之后)。 7. 经常更换会话密钥。
这是在自己编写系统和使用不适合的系统之间的折衷方案。
我非常乐意接受建设性的批评...

我其实不太理解HMAC的工作原理,但我需要尽可能地缩小整个客户端-服务器对话的大小。但你说要使用PKE来传输会话密钥。如果我使用2048位RSA来传输该密钥,那么我又会浪费很多空间。(正如我所说,我真的不知道HMAC是如何工作的,所以请原谅我如果我没有理解它。) - Paya
看,会话密钥是可重复使用的,因此必须将其大小除以使用次数以计算它的开销。您在开始时传输会话密钥,并在传输另一个之前使用它来处理一些固定数量的数据包。至于HMAC,它只是一种安全地加密哈希的方法。 HMAC提供了签名机制,PKE则安全地传输(可重复使用的)会话密钥。您可以调整每个部分的大小以获得适当的速度和大小平衡。 - Steven Sudit
如果数据本身非常短,则必须预期签名会更大。如果不是这样,那么它将容易受到暴力攻击,因为明文的可能性很少。我唯一能想到的解决方法是不对每个数据包进行签名,而是发送整天流量的确认。 - Steven Sudit
我认为HMAC不适合我的需求,因为我需要数字签名的非对称属性。如果我正确理解HMAC,那么另一方将能够使用相同的密钥以相同的方式“签署”消息,因此他将能够创建看起来像是由我创建的消息。顺便说一下,160位或256位对我来说还可以,但2048位就太多了。 :-( - Paya
正确,HMAC是对称的,这就是为什么它与通过非对称传输的会话密钥配对。它存在的原因是通过非对称加密哈希算法对每个数据包进行签名过于昂贵。 - Steven Sudit
显示剩余6条评论

1

我现在明白了,在阅读评论后。

答案是:不要这样做。

加密签名算法不是你可以挑选或修改步骤的算法。特别是,假设一个签名sig看起来像encrypt(hash)orig + sig并不等同于encrypt(orig + hash)。此外,即使是过时的签名算法,如PKCS v1.5,也不像第一眼看起来那么简单,只是encrypt(hash)

像你描述的这种技术为了聪明而牺牲了安全性。如果你没有256字节签名的带宽,那么你需要以下之一:

  1. 不同的算法,
  2. 更多的带宽,或者
  3. 更小的密钥。

如果你选择(1),请确保它不是你自己编造的算法!事实上,加密很难


据我所知,数字签名只是加密哈希。如果您使用256位SHA,则浪费了1792位。或者这些位中存储了什么? - Paya
我建议选择选项1,以便允许选项3。 - Steven Sudit
1
你有什么算法建议吗?我需要非常强的安全性,而我认为512位RSA密钥太小了。.NET是否有一些额外的非对称加密实现,不同于RSA,即使使用较小的密钥也足够安全? - Paya
1
@Paja:你需要在这里下定决心。如果你想要非常强大的安全性,那么你必须愿意在大小和速度上付出代价。.NET提供RSA、DSA和椭圆曲线Diffie-Hellman的支持。请注意,DSA用于签名,“支持512位到1024位,每次增加64位的密钥长度”。这里是链接:http://msdn.microsoft.com/en-us/library/92f9ye3s.aspx - Steven Sudit
@Steven Sudit:阅读有关DSA的文章,他们建议使用至少2048位的对数密钥。如果我能够将实际消息的一部分放入签名中,我愿意使用如此长的代码。我仍然不明白,如果我将我的数据放入签名中的浪费空间中,我会失去什么额外的安全性。 - Paya
@Paja:与对称加密相比,公钥加密速度更慢,需要更多的位数来防止暴力破解。这是灵活性的代价,这就是为什么我们使用带有会话密钥的混合加密。我甚至不愿意建议通过这种方式篡改签名会带来什么危害,因此我不会推荐这样做。 - Steven Sudit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接