<p>DSA签名被定义为一对整数(分别称为<em>r</em>和<em>s</em>)。<a href="http://csrc.nist.gov/publications/fips/fips186-3/fips_186-3.pdf" rel="nofollow">DSA standard</a>不强制将此类签名的特定编码转换为字节序列。因此,使用DSA签名的每个协议都必须定义自己的编码。在</p>
<p>有两种常用的DSA签名编码;一种是直接串联<em>r</em>和<em>s</em>值的大端无符号编码,它们都规范化为公钥中的<em>q</em>参数的长度(以字节为单位)(“子组大小”,通常是一个160位素数整数,从而产生一个40字节的签名)。M2文件加密DSA非常简洁,但我猜它会分别返回<em>r</em>和<em>s</em>,但已经是这种格式了。在</p>
<p>Java使用另一种基于ASN.1的编码。这是贯穿X.509和基于它的任何东西(包括SSL/TLS中的签名)使用的编码。ASN.1是结构化数据表示和序列化的通用标准。在这种情况下,签名应该是包含两个<code>INTEGER</code>值的ASN.1<code>SEQUENCE</code>的序列化(按顺序为<em>r</em>和<em>s</em>)。根据ASN.1和DER编码规则,签名应具有以下格式:</p>
<p>0x30<em>A</em>0x02<em>B R</em>0x02<em>C S</em></p>
<p>其中:</p>
<ul>
<li><p><em>R</em>是最小长度的大端有符号</em>编码:这意味着第一个字节的值应该在0到127之间,只有第二个字节的值在128到255之间时,它才有值0。换句话说,将<em>r</em>编码为big-endian约定的字节序列(最重要的字节排在第一位),确保您有尽可能少的前导零位,前提是您至少保留一位(这就是“有符号”编码的意思:因为<em>r</em>是正的,它的最高有效位必须是0)。由于<em>r</em>是一个介于<em>0</em>和<em>q-1</em>之间的整数,<em>r</em>的长度最多比<em>q</em>的长度多1个字节,但可以更小。</p></li>
<li><p><em>S</em>是<em>S</em>的大端有符号编码(与<em>r</em>的处理相同;注:<em>r</em>和<em>S</em>可能有不同的长度)。</p></li>
<li><p><em>B</em>是包含<em>R</em>长度的单个字节(以字节为单位)。</p></li>
<li><p><em>C</em>是包含<em>S</em>长度的单个字节(以字节为单位)。</p></li>
<li><p><em>A</em>是包含<em>B+C+2</em>的单个字节(即字节<em>A</em>后面的长度)。</p></li>
</ul>
<p>为基于ASN.1的DSA签名编写专门的编码和解码函数有点乏味,但并不困难;只需注意生成大小合适的<em>R</em>和<em>S</em>序列。或者,您也可以使用现有的ASN.1编码/解码库,这是一种过激的做法,但可能更容易,具体取决于您的情况。在</p>