试图理解 RSA 及其术语?

信息安全 RSA 术语
2021-08-12 23:02:24

我了解了 RSA 的要点,但我主要是自学成才,所以有时我用来描述某事的短语与广泛接受的术语不符。我正在努力解决这个问题。

我正在使用一个名为node-rsa的 NodeJS 库。加载密钥后,它基本上具有 4 个功能:加密、解密、签名和验证。

我的理解是以下陈述是正确的,尽管我并不肯定。我还假设图书馆知道并遵循正确的术语,并且没有以任何异常的方式实现事物。

  1. Encrypt 使用提供的(或从私钥生成的)公钥来加密数据。

  2. Decrypt 使用提供的私钥解密数据。

  3. Sign 使用提供的私钥加密数据,输出称为“签名”。

  4. Verify 使用提供的(或从私钥生成的)公钥来解密签名。

  5. 对相同的数据进行两次不同的加密可能会导致两个不同的输出,具体取决于填充。签名不使用填充,并且将为匹配的输入产生相同的输出。

  6. 如果我签署了某些内容,我需要将已签署的输入以及签名发送给消息的收件人。

  7. 签名的输入通常是要发送的消息的哈希值,以验证消息没有被更改。

我走上正轨还是这都是胡说八道?

编辑:

我觉得这些是显而易见的,但如果我相信它们如此根本并且对它们是错误的,那我真的会对自己造成伤害。

  1. 当加密我发送的东西时,我使用对方的公钥。

  2. 在解密我收到的东西时,我使用我的私钥。

  3. 签署我要发送的内容时,我使用我的私钥。

  4. 在验证我收到的东西时,我使用对方的公钥。

还有一些细节我有疑问,例如消息中是否包含签名,或者它是否在未加密的情况下与有效负载一起传输?然而,这些问题可能需要在网站上提出独特的问题。

2个回答

您混淆的根源是 RSA 签名的历史“解释”为“用私钥加密哈希”。这种解释令人困惑,并且在许多方面存在缺陷。它仅适用于 RSA。实际上它也不适用于 RSA。

让我们正确定义事物:

  • 一个非对称加密系统定义了两个功能:

    • Encrypt: 将消息(字节序列,长度可能有限)和公钥作为输入。它在给定的可能值空间中输出一个值(在 RSA 的情况下,这是一个大整数,不超过模数)。
    • Decrypt: 将加密消息(的输出Encrypt)和私钥作为输入,并返回原始消息(当然,前提是私钥与用于加密的公钥匹配)。
  • 签名算法定义了两个函数:

    • Sign: 将消息(字节序列,通常不限制长度)和私钥作为输入。它在给定的可能值空间中输出一个值。
    • Verify: 将消息、签名值( 的输出Sign)和公钥作为输入,并输出布尔值(匹配时为“true”,否则为“false”)。

由于这四个函数采用不同类型的输入并产生不同类型的输出,因此它们不能互换。

一般来说,非对称加密算法和签名算法存在于不同的世界中。碰巧有一种非对称加密算法称为“RSA”,还有一种签名算法也称为“RSA”。此外,它们都使用相同类型的公钥/私钥对。但是,一般来说,加密密钥和签名密钥应该是不同的

如果我们查看PKCS#1中定义的 RSA(两种算法)的内部结构,那么我们可能会发现一些共同的元素,而另一些则是不同的。

对于非对称加密,消息必须比模数小(至少 11 个字节)。要加密的消息被“填充”如下:

0x00 0x02 rr rr ... rr 0x00 mm...

mm...消息在哪里,rr是随机的非零字节。调整字节数,rr使总长度等于模数的长度,并且必须至少有八个这样的非零字节(因此对消息长度进行了限制)。生成的字节序列被解释为整数模N(公钥/私钥对的“模”部分),并提高到公共指数N。结果是加密的消息:它是一个模数N的整数(惯例是以大端序对该消息进行编码,产生与模数长度相同的字节序列)。

给出一些数字:如果您使用 1024 位 RSA 密钥,则模数的大小为 128 字节。可加密的消息不得超过 117 个字节。加密结果是一个 128 字节的序列。

对于签名,要签名的消息首先使用合适的哈希函数(如 SHA-256)进行哈希处理。因此,可以处理任意长的消息(SHA-256 对输入长度没有实际限制)。然后填充哈希值,填充看起来像这样:

0x00 0x01 0xFF 0xFF ... 0xFF 0x00 ii... hh...

其中ii...是指定散列函数的常规标头,hh...是散列值。再次调整 0xFF 字节的数量,以使总长度与模数的长度相匹配。结果序列再次被解释为整数,并以N为模取幂,但这次使用的是私有指数。此外,大多数 RSA 实现实际上通过使用中国剩余定理通过他们对N因子的了解(这些因子是私钥的一部分)来优化该操作。

因此,虽然加密和签名生成都依赖于某种填充,然后是求幂,但它们在显着方面有所不同:

  • 对于加密,消息“按原样”获取,并且长度有限。对于签名,消息首先经过哈希处理,并且没有长度限制。

  • 填充物不同。加密中使用的填充包括足够多的随机字节对安全性很重要。签名中使用的填充包括足够多的非随机字节对于安全性同样重要。不太明显的是,填充字节出现在大端约定中的“左侧”非常重要。

  • 指数不同。对于加密,您使用通常很短的公共指数(可能下降到 e = 3,尽管值 e = 65537 是传统的)(碰巧,使用 65537 根本没有充分的理由,但是嘿,传统是传统)。对于签名生成,使用私有指数,但操作很少“按原样”使用该指数;事实上,两个次幂运算是以pqN的主要因数)为模完成的,总加速约为 4 倍。

事实上,唯一真正的共同点是 RSA 加密的消息和 RSA 签名都是模N的整数,并且使用大端约定进行编码。其他一切都不同。而且,正如我之前所说,无论如何您都不应该使用相同的密钥对进行签名和加密;这两种密钥对都需要不同的管理和生命周期。


签名生成/验证的一些实现接受预散列值作为输入。哈希函数仍然是整个过程的重要组成部分。即使给定的一段代码接受散列值作为输入,散列仍然必须在某个时候发生。

RSA签名验证算法的一些实现实际上“只是”签名和公钥;它们不是简单的布尔结果(匹配/不匹配),而是自己产生哈希值;然后,调用者负责将该哈希值与声称要签名的消息进行匹配。从签名+公钥中恢复散列消息的能力是 RSA 的一个特性(据说 RSA 是一种带有恢复的签名算法)。并非所有其他签名算法都可以做到这一点。而且,再次发生散列很重要。不要让它让你相信你可以做“没有散列的 RSA 签名”。

传统上,SSL 中使用的 RSA 签名依赖于一个稍微不同的过程:填充缺少识别标头(ii...在我的符号中),哈希值实际上是 MD5 和 SHA-1 的串联,两者都是通过消息计算得出的签署。这是过去 PKCS#1 标准不像今天那样牢固根深蒂固的遗留问题。

保持简单。RSA 有两个主要目的 1. 密钥交换 您将与其他人共享密钥,因此使用接收者的公钥加密/包装密钥。接收者将使用他的私钥解密/解包。2. 数字签名您将提供一些数据以保持完整性。该机制将散列数据并结合使用您的私钥加密的散列算法。验证者将使用您的公钥解密并通过比较哈希进行检查。

现在考虑一些考虑 问:为什么我们说密钥交换,而不是加密/解密?答:使用 RSA 进行加密和解密的成本很高,对于大数据,这样做是不可行的。所以,通常我们做混合。使用会话密钥加密并加密/包装该会话密钥以共享。通常会话密钥是对称分组密码算法的密钥。

问:密钥交换/数字签名哪个更需要保密?A:任何人都可以解密签名数据。但是没有人应该得到关键值。

所以,PKCS 1 有一些填充机制来保持更多的秘密。它使用至少 8 个字节的随机数据和 3 个指示符字节来填充密钥交换。为了简单起见,它以相同的方式填充数字签名并通过放置“FF”字节来避免随机数。由于数字签名不需要额外的安全性,它适用于相同的技术来取消密钥交换和数字签名。

请记住,使用算法是可以的。但是,了解它的目的更重要。

这是示例填充 KE:00 02(表示随机数)[至少 8 个字节的随机数,没有任何字节值 '00'] 00 [Data] DS:00 01(表示'FF;)[至少 8 个字节'FF '] 00 [数据]

现在随机数字节或“FF 字节取决于数据长度和密钥模数长度(1024/2048/.. 位)”

1024 位又名 128 字节的简单数学运算。假设数据长度为 34 字节,因此随机数据或“FF”字节的长度将为 128 - 2 (00 [indicator]) - 1 - 34

希望它会有所帮助