繁体   English   中英

如何为 ASN.1 DER 生成两个 RSA 对其模数进行编码,带和不带填充(示例代码中的错误?)

[英]How to generate two RSA for ASN.1 DER encoding their modulus with and without padding (bug in sample code?)

我的问题基本上如下:

如何生成两种 2048 位 RSA 密钥,以便它们的无符号大端模数在进行 ASN.1 DER 编码时需要前缀为0x00而另一种不需要?

我有代码片段和解释我在下面尝试做的事情。 所以,我尝试这样做的原因和我使用的方法。

我把它作为一个上下文,因为我在生成这样的一对时遇到了问题,可能是我误解了一些东西。 也可能是这种情况下,对0x00前缀的要求非常罕见,我没有设法通过随机生成来做到这一点(我不这么认为,但我不知道如何计算/估计它,我也不知道在网上找到了这样的例子)。

所以,我在考虑编码 2048 位 RSA 模数的 ASN.1 DER。 在 .NET(和许多其他框架)中,序列被编码为无符号大端字节数组。

这样做的一个实际结果似乎是,如果模数的第一个字节介于 0x00(十进制:0)和 0x7F(十进制:127)之间,那么在 DER“标题”之后将不会添加零字节。 否则添加一个 0x00 字节。 这样做是因为在 ASN.1 DER 编码中发生有符号整数,否则字节将被解释为负数(并且模数是无符号大端整数)。

一般来说,关于这个逻辑有一些很好的解释

https://crypto.stackexchange.com/questions/1795/how-can-i-convert-a-der-ecdsa-signature-to-asn-1

并且在

.net 中 RSA 公钥模数和指数的格式是什么?

dumpasn1 / asn1playground稍加修改,以 crypto.stackexchange 中提供的示例并在此处修改从 ECDSA 到 RSA 的解释,我收集前缀为0x00的模数情况的序列如下:

  1. 序列开始:0x30
  2. 序列长度:0x82 0x01 0x0a
  3. 整数标签:0x02
  4. 模整数长度:0x82 0x01 0x01
  5. 模数前导零的整数:0x00
  6. [插入 RSA 模数字节]
  7. 其他一些 DER 编码字节来结束序列

这里第5.点是关键。 只有在设置了无符号模数数组的 MSB 时才会添加它。

或者,用代码术语来说,这就是我的样子

var key = RSA.Create(2048);
var parameters = key.ExportParameters(includePrivateParameters: false);
var modulus = parameters.Modulus!;

// See this check here assuming MSB is in first byte in the array and this checks if the MSB bit is set.
bool isModulusMsbSet = (modulus[0] & 0x80) != 0;

// See here choosing the first version of the same array and concatenating a leading 0x00
// if the MSB is set on unsigned, big endian modulus.
var prefix = isModulusMsbSet ? new byte[] { 0x30, 0x82, 0x01, 0xa, 0x02, 0x82, 0x01, 0x01 }.Concat(new byte[] { 0x0 }).ToArray() : new byte[] { 0x30, 0x82, 0x1, 0xa, 0x2, 0x82, 0x1, 0x1 };

为了更接近我的问题和问题的原因,我尝试生成非填充案例的代码:

RSA? key = null;
do
{
   var testKey = RSA.Create(2048);
   var parameters = testKey.ExportParameters(includePrivateParameters: false);
   var modulusBytes = parameters.Modulus!;

   // See here the checking of MSB is inverted from != to ==.
   // I.e. accept this key only if 0x00 padding is not needed.   
   if((modulusBytes[0] & 0x80) == 0)
   {
      key = testKey;
   }

} while(key == null);

但是这个循环永远不会停止! 在我看来,这似乎表明 MSB 总是设置的! 但不应该RSA.Create(2048); 偶尔创建一个可接受的密钥? 是否有另一个很好的案例来为填充案例生成测试材料?

我也部分地询问,因为我不确定是否应该在 ASN.1 DER 编码序言序列中考虑条件0x00

目前尚不清楚您要解决什么问题。 对我来说,您似乎正在尝试解决 XY 问题。

我不是最好的解释这些事情,我会尝试解释:

在我看来,这似乎表明 MSB 总是设置的!

这是意料之中的。 RSA 公钥大小除以 8,无需提醒(例如 512、1024、2048 等)。 结果,模数将消耗KeySizeInBits / 8个字节,并且该整数中的所有位都表示模数。 由于整数忽略前导零(如十进制, 1001表示相同的数字1 ),模数的第一位(或 MSB)必须为 1。否则它被忽略,然后你的模数将不是 2048 位,它将是 2047 甚至更少,最长可达 2040 位。 这些是 RSA 公钥模数的无效长度(在没有提醒的情况下不会除以 8)。 将 RSA 模数想象成一个长位字符串,其中长度计数从设置为 1 的第一位开始。

只是一个非常说明性的例子。 这个位串需要多少位?

0 1 0 1 0 1 0 1

答案是 7,前导零位被忽略,计数从第一位开始1 并且 7 不会在没有提醒的情况下除以 8。 和这个:

1 0 0 0 0 0 0 0

正好是 8 位。 在 ASN.1 中,整数是两个补码值,当字节中的第一位为 0 时,整数为正,否则为负。 由于 RSA 模数中的 MSB 为 1,并且该数字是正数,因此作为编码的一部分,它在前面用零字节填充。 然而,这个零字节不是公钥的一部分,它是编码的一部分。

此外,模数是两个素数的乘积: N = p*q 并且产品总是奇数。 这意味着 RSA 模数的最后一位也将以 1 结尾。 所以对于 RSA 公钥,模数中的第一位和最后一位都设置为 1。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM