当我输入命令行时openssl dhparam -text 1024
,生成的安全素数是 1032 位而不是 1024 位。似乎第一个字节总是 0。这是为什么呢?
当我请求 1024 位时,OpenSSL 生成 1032 位
试试这个:
openssl genrsa | openssl rsa -text
查看每个字段;素数,指数,所有这些。现在再试一次,一次又一次。您会注意到关于是否存在初始零字节的一些不一致之处。有时是,有时不是。模式是这样的:如果第一个“真实”字节的第一位被设置——也就是说,如果第一个十六进制字符小于 8——那么将不会显示(或存储)初始零,但是如果它是 8 或更高,那么将添加一个零字节。
这清楚地表明他们正在解决的问题是符号解释。对于有符号值,第一位是数字的符号;添加初始零可以消除任何歧义。
要查看实际存储(未显示)的内容,请查看:
openssl genrsa | openssl asn1parse
您会看到虽然只显示了 64 或 32 个字节,但您会看到l= 33
或 l= 65
指示实际存储了一个额外的字节。那是您之前看到的初始零字节。
至于 32 位 DH 密钥,看这个:
$ openssl dhparam 32 -text
Generating DH parameters, 32 bit long safe prime, generator 2
This is going to take a long time
PKCS#3 DH Parameters: (32 bit)
prime: 2714658203 (0xa1ce659b)
generator: 2 (0x2)
因此,即使设置了初始位,它看起来也只有 4 个字节。但是让我们看一下 asn1parse:
0:d=0 hl=2 l= 10 cons: SEQUENCE
2:d=1 hl=2 l= 5 prim: INTEGER :A1CE659B
9:d=1 hl=2 l= 1 prim: INTEGER :02
因此,对于这个 32 位素数,即使您只看到显示 4 个字节,也会存储 5 个字节。
这次你没有看到零字节的原因是因为存储的值只有 32 位,它可以显示为一个简单的无符号整数,因此 OpenSSL 的显示库相应地显示了十进制值和十六进制值parens 而不是只显示一串由冒号分隔的十六进制字节。但是最初的零仍然存在,正如我们在 asn1 输出中看到的那样。
你真的得到一个 1024 位素数:1024 位素数是一个整数,其值大于 2 1023但小于 2 1024。这就是 OpenSSL 给你的回报。但是,当将该整数存储到文件中时,必须使用一些编码约定将该整数转换为字节。OpenSSL 使用ASN.1和 DER(可分辨编码规则)。
在 ASN.1 中,类型是INTEGER
,这是一个可能为负数的通用整数值。DER 规则规定INTEGER
将编码为标记(02
,标准标记INTEGER
)然后是长度(81 81
,意思是“129”:值将是一个 129 字节的序列),然后是值本身,具有大端符号解释. 这里重要的词是“有符号的”:因为 anINTEGER
可能是负数,但你的素数是正数,它的编码必须以一个值 0 开始。如果素数被编码超过 128 个字节,第一个字节的第一位将为 1,并且INTEGER
将被视为负数。因此,一个额外的字节00
添加(根据 DER 规则,如果第一位与预期符号匹配,则编码必须具有最小长度,因此只能添加单个字节00
)。带有标头的总长度为 132 字节。这样编码的数学整数仍然是 1024 位素数,而不是 1032 位或 1056 位整数。
如果设置了 1024 位值中的最高位,则会在前面添加一个 0 字节,因为如果没有该位,该数字将被解释为负数。