跳到主要内容

RFC 6979 - Deterministic Usage of the Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA) (数字签名算法和椭圆曲线数字签名算法的确定性使用)

  • 状态: Informational
  • 发布日期: August 2013
  • Stream: INDEPENDENT
  • 勘误: 无勘误

Abstract (摘要)​

本文档定义了一个确定性数字签名生成过程.这种签名与标准的 Digital Signature Algorithm (数字签名算法, DSA) 和 Elliptic Curve Digital Signature Algorithm (椭圆曲线数字签名算法, ECDSA) 数字签名兼容, 并且可以使用未经修改的验证器进行处理, 验证器无需了解本文档中描述的过程.确定性签名保留了与数字签名相关的密码学安全特性, 但可以更容易地在各种环境中实现, 因为它们不需要访问高质量的随机性来源.

Status of This Memo (本备忘录状态)​

本文档不是互联网标准跟踪规范, 它的发布是为了提供信息.

这是对 RFC 系列的贡献, 独立于任何其他 RFC 流.RFC 编辑器已选择自行发布本文档, 并且不对其实施或部署价值做出任何声明.由 RFC 编辑器批准发布的文档不是任何级别的互联网标准的候选文档, 参见 RFC 5741 的第 2 节.

有关本文档当前状态,任何勘误以及如何提供反馈的信息可以在 http://www.rfc-editor.org/info/rfc6979 获得.

Copyright (c) 2013 IETF Trust 和确定为文档作者的人员.保留所有权利.

本文档受 BCP 78 和 IETF Trust 关于 IETF 文档的法律规定 (http://trustee.ietf.org/license-info) 的约束, 这些规定在本文档发布之日生效.请仔细审阅这些文档, 因为它们描述了您对本文档的权利和限制.

Contents​


本文档定义了一个确定性过程, 用于在数字签名算法 (DSA) 和椭圆曲线数字签名算法 (ECDSA) 中生成签名所需的随机值 k.这使得签名生成成为确定性的, 同时保持与标准 DSA 和 ECDSA 的完全兼容性.


1. Introduction (简介)​

DSA [FIPS-186-4] 和 ECDSA [X9.62] 是两种标准的数字签名方案.它们在各种协议中提供数据完整性和可验证的真实性.

DSA 和 ECDSA 的一个特点是, 它们需要为每次签名生成产生一个新的随机值 (以下称为 k).为了实现有效的安全性, k 必须使用密码学安全的过程从一组模整数中随机且均匀地选择.该过程中即使是轻微的偏差也可能被转化为对签名方案的攻击.

对密码学安全随机性来源的需求被证明是在某些架构中部署 DSA 和 ECDSA 签名方案的障碍, 特别是在安全随机数生成具有挑战性的架构中, 尤其是嵌入式系统 (例如智能卡).在这些系统中, 通常更倾向于使用 RSA 签名算法, 按照 Public-Key Cryptography Standards (公钥密码学标准, PKCS) #1 [RFC3447] (使用 "type 1" 填充, 而不是 Probabilistic Signature Scheme (概率签名方案, PSS)) 和 ISO 9796-2 [ISO-9796-2] 中的规定使用, 尽管 RSA 在计算上更加昂贵, 因为 RSA (使用这种填充方案) 是确定性的, 因此不需要随机性来源.

DSA 和 ECDSA 的随机化特性也使得实现更难测试.自动化测试无法可靠地检测实现是否使用了足够高质量的随机性来源.这使得实现过程更容易遭受灾难性失败, 这些失败通常在系统部署并成功被攻击后才被发现.

可以通过使用确定性过程生成 "随机" 值 k 来将 DSA 和 ECDSA 转变为确定性方案.该过程必须满足某些密码学特性, 以维持签名方案预期的可验证性和不可伪造性属性; 也就是说, 对于不知道签名私钥的任何人来说, 从输入消息到相应 k 值的映射必须在计算上与随机均匀选择的函数 (从消息集到可能的 k 值集) 返回的结果无法区分.

本文档描述了这样一个过程.它具有以下特性:

  • 生成的签名与普通的 DSA 和 ECDSA 完全兼容.验证签名的实体无需更改甚至无需了解用于生成 k 的过程.

  • 密钥对生成不会改变.现有的私钥可以与确定性 DSA 和 ECDSA 一起使用.

  • 使用确定性 DSA 和 ECDSA 不会产生对任何秘密或公共值的额外存储要求.

  • 确定性 DSA 和 ECDSA 可以应用于与普通 DSA 和 ECDSA 相同的输入, 即使用密码学安全哈希函数计算的消息哈希值.

在本文档中指定的确定性 (EC)DSA 的定义中采取了一些相对任意的选择; 这样做是为了使其尽可能普遍适用, 从而最大化所包含测试向量的实用性.有关一些可能的变体的讨论, 请参见第 3.6 节.

需要注意的是, 密钥对生成仍然需要随机性来源.在随机性质量成问题的嵌入式系统中, 通常可以安排在更受控的条件下进行密钥对生成 (例如, 在特殊的智能卡初始化过程中或在宣誓代理的物理控制下), 或者密钥甚至可以在其他地方生成并导入到设备中.确定性 DSA 和 ECDSA 仅处理签名生成时对随机性的需求.


2. DSA and ECDSA Notations (DSA 和 ECDSA 表示法)​

在本节中, 我们简要描述 DSA 和 ECDSA 并定义我们的表示法.DSA 和 ECDSA 的完整规范可以分别在 [FIPS-186-4] 和 [X9.62] 中找到.


2.1. Key Parameters (密钥参数)​

DSA 和 ECDSA 在素数大小的大群上工作, 其中群运算易于计算, 但使用现有和可预见的技术计算离散对数在计算上是不可行的.该群的定义称为 "密钥参数".密钥参数可以在不同的密钥对之间共享, 对安全性没有不良影响; 这在 ECDSA 中尤其常见.

DSA 使用以下密钥参数:

p
一个大素数 (至少 1024 位)

q
一个足够大的素数 (至少 160 位), 它也是 p-1 的除数

g
整数模 p 的 q 阶乘法子群的生成元

将在其上计算 DSA 的群由值 g^j mod p 组成, 其中 ^ 表示幂运算, j 的范围从 0 到 q-1 (含).该群的大小为 q.

ECDSA 使用以下密钥参数:

E
在给定有限域上定义的椭圆曲线

q
一个足够大的素数 (至少 160 位), 它是曲线阶的除数

G
E 的一个点, 阶为 q

将在其上计算 ECDSA 的群由曲线点 jG (点 G 乘以整数 j) 组成, 其中 j 的范围从 0 到 q-1.G 使得 qG = 0 (曲线 E 上的 "无穷远点").该群的大小为 q.请注意, 这些表示法与 [X9.62] 中描述的略有不同; 我们使用它们是为了与 DSA 使用的表示法匹配.


2.2. Key Pairs (密钥对)​

DSA 或 ECDSA 私钥是一个整数 x, 取模 q.相关标准规定 x 不应为 0; 因此, x 是范围 [1, q-1] 内的整数.

DSA 或 ECDSA 公钥是从私钥 x 和密钥参数计算得出的:

  • 对于 DSA, 公钥是整数: y = g^x mod p

  • 对于 ECDSA, 公钥是曲线点: U = xG


2.3. Integer Conversions (整数转换)​

令 qlen 为 q 的二进制长度.qlen 是使得 q 小于 2^qlen 的最小整数.这是 q 的二进制表示的大小, 不包含符号位 (注意 q 作为一个大素数, 是奇数, 因此避免了关于任何等于 2 的幂的整数长度的歧义).我们定义五个转换函数, 它们作用于位串,字节串和模 q 的整数.qlen 是这些转换的主要参数.

在以下小节中, 我们使用另外两个长度, 称为 blen 和 rlen.rlen 等于 qlen, 向上舍入到 8 的下一个倍数 (如果 qlen 已经是 8 的倍数, 则 rlen 等于 qlen; 否则, rlen 略大, 最多为 qlen+7).注意 rlen 与值 r (生成的签名的前半部分) 无关.blen 是输入位序列的长度 (以位为单位), 在不同调用之间可能会变化.blen 可能小于,等于或大于 qlen.


2.3.1. Bits and Octets (位和字节)​

形式上, 所有操作都是在位序列上定义的.序列是有序的; 第一位被称为最左侧的, 而最后一位是最右侧的.

在大多数软件系统上, 位被分组为字节 (八位序列).二进制数据, 例如哈希函数的输出, 可作为字节序列使用.在适用的情况下, 我们认为字节内的位从最高有效位到最低有效位排序: 字节内的第一位 (最左侧) 具有数值 128, 而最后一位 (最右侧) 具有数值 1.


2.3.2. Bit String to Integer (位串到整数)​

bits2int 转换接受一个 blen 位的序列作为输入, 并输出一个小于 2^qlen 的非负整数.它由以下步骤组成:

  1. 首先将序列截断或扩展到长度 qlen:

    • 如果 qlen < blen, 则保留 qlen 个最左侧的位, 并丢弃后续位;

    • 否则, 将 qlen-blen 个位 (值为零) 添加到序列的左侧 (即, 在序列顺序中的输入位之前).

  2. 然后使用大端约定将结果序列转换为整数值: 如果输入位被称为 b_0 (最左侧) 到 b_(qlen-1) (最右侧), 则结果值为:

    b_0*2^(qlen-1) + b_1*2^(qlen-2) + ... + b_(qlen-1)*2^0

bits2int 转换也可以用以下方式描述: 使用大端约定将输入位序列 (长度为 blen) 转换为整数.然后, 如果 blen 大于 qlen, 则将结果整数除以 2 的 blen-qlen 次方 (欧几里德除法: 丢弃余数); 在大整数算术的许多软件实现中, 该除法等效于向右移位 blen-qlen 位.


2.3.4. Bit String to Octet String (位串到字节串)​

bits2octets 转换接受一个 blen 位的序列作为输入, 并输出一个 rlen 位的序列.它由以下步骤组成:

  1. 通过 bits2int 转换将输入序列 b 转换为整数值 z1:

    z1 = bits2int(b)
  2. 将 z1 对 q 取模, 得到 z2 (一个在 0 和 q-1 之间的整数, 包含边界):

    z2 = z1 mod q

    请注意, 由于 z1 小于 2^qlen, 该模运算可以通过简单的条件减法实现: 如果该值非负, 则 z2 = z1-q; 否则, z2 = z1.

  3. 通过应用 int2octets 将 z2 转换为字节序列 (rlen 位的序列).


2.3.5. Usage (使用)​

值得注意的是, int2octets 不是 bits2int 的逆运算, 即使对于长度为 qlen 的输入序列也是如此: int2octets 将在左侧添加一些位, 而 bits2int 将在右侧丢弃一些位.只有当 qlen 是 8 的倍数且位序列已经具有长度 qlen 时, int2octets 才是 bits2int 的逆运算.

在标准 DSA 和 ECDSA 的签名生成和验证过程中使用 bits2int 将哈希值 (在输入消息上计算) 转换为模 q 的整数.也就是说, 通过 bits2int 获得的整数进一步对 q 取模; 由于该整数小于 2^qlen, 该归约最多可以通过一次减法执行.

int2octets 在 SEC 1 [SEC1] 的第 2.3.7 节中以名称 "Integer-to-OctetString" 定义.它用于在基于 ASN.1 的结构中对 ECDSA 私钥 (x) 进行编码的规范中.

bits2octets 在标准 DSA 或 ECDSA 中未使用.我们将在确定性 (EC)DSA 的规范中使用它.


2.4. Signature Generation (签名生成)​

签名生成使用密码学哈希函数 H 和输入消息 m.消息首先由 H 处理, 产生值 H(m), 这是长度为 hlen 的位序列.通常, H 的选择使得其输出长度 hlen 大致等于 qlen, 因为签名方案的整体安全性将取决于 hlen 和 qlen 中较小的一个; 然而, 相关标准支持 hlen 和 qlen 的所有组合.

然后应用以下步骤:

  1. 使用 bits2int 转换和额外的模归约将 H(m) 转换为模 q 的整数:

    h = bits2int(H(m)) mod q

    如 bits2octets 描述中所述, 额外的模归约不过是一次条件减法.

  2. 生成一个模 q 的随机值, 称为 k.该值不应为 0; 因此, 它位于 [1, q-1] 范围内.本文档的大部分内容将围绕用于生成 k 的过程展开.在普通 DSA 或 ECDSA 中, k 应该通过随机选择来选择, 该选择以均匀概率从 q-1 个可能值中选择一个值.

  3. 从 k 和密钥参数计算值 r (模 q):

    • 对于 DSA:

      r = g^k mod p mod q

      (幂运算在模 p 下执行, 产生一个介于 0 和 p-1 之间的数字, 然后进一步对 q 取模.)

    • 对于 ECDSA: 计算点 kG; 其 X 坐标 (定义 E 的域的成员) 转换为整数, 然后对 q 取模, 产生 r.

    如果 r 结果为零, 则应选择新的 k 并再次计算 r (这是一个极其不可能发生的事件).

  4. 计算值 s (模 q):

    s = (h+x*r)/k mod q

    对 (r, s) 是签名.DSA 和 ECDSA 标准本身不涵盖签名的编码方式; 一种常见的方式是使用 DER 编码的 ASN.1 结构 (按顺序排列的两个 INTEGER 的 SEQUENCE, 分别为 r 和 s).


3. Deterministic DSA and ECDSA (确定性 DSA 和 ECDSA)​

确定性 (EC)DSA 是通过使用标准 (EC)DSA 签名生成过程 (在上一节中讨论) 在输入消息 m 上生成 (EC)DSA 签名的过程, 除了值 k 不是随机生成的, 而是通过本节中描述的过程获得的.

我们使用第 2 节中描述的表示法.


3.2. Generation of k (k 的生成)​

给定输入消息 m, 应用以下过程:

a. 通过哈希函数 H 处理 m, 产生:

h1 = H(m)

(h1 是长度为 hlen 的位序列).

b. 设置:

V = 0x01 0x01 0x01 ... 0x01

使得 V 的长度 (以位为单位) 等于 8*ceil(hlen/8).例如, 在基于字节的系统上, 如果 H 是 SHA-256, 则 V 被设置为 32 个值为 1 的字节序列.请注意, 在此步骤和所有后续步骤中, 我们使用与步骤 'a' 中用于处理输入消息的相同 H 函数; 此选择将在第 3.6 节中更详细地讨论.

c. 设置:

K = 0x00 0x00 0x00 ... 0x00

使得 K 的长度 (以位为单位) 等于 8*ceil(hlen/8).

d. 设置:

K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1))

其中 '||' 表示连接.换句话说, 我们使用密钥 K 计算 HMAC, 对以下内容按顺序进行连接: V 的当前值,一个值为 0 的八位序列,(EC)DSA 私钥 x 的编码, 以及哈希消息 (可能由 bits2octets 转换截断和扩展).HMAC 结果是 K 的新值.请注意, 私钥 x 在 [1, q-1] 范围内, 因此是 int2octets 的适当输入, 产生 rlen 位的输出, 即整数个字节 (rlen 是 8 的倍数).

e. 设置:

V = HMAC_K(V)

f. 设置:

K = HMAC_K(V || 0x01 || int2octets(x) || bits2octets(h1))

请注意, 这次 "内部字节" 是 0x01.

g. 设置:

V = HMAC_K(V)

h. 应用以下算法, 直到找到 k 的适当值:

  1. 将 T 设置为空序列.T 的长度 (以位为单位) 表示为 tlen; 因此, 此时 tlen = 0.

  2. 当 tlen < qlen 时, 执行以下操作:

    V = HMAC_K(V)
    T = T || V
  3. 计算:

    k = bits2int(T)

    如果 k 的值在 [1,q-1] 范围内, 并且适合 DSA 或 ECDSA (即, 它导致的 r 值不为 0; 参见第 3.4 节), 则 k 的生成完成.获得的 k 值用于 DSA 或 ECDSA.否则, 计算:

    K = HMAC_K(V || 0x00)
    V = HMAC_K(V)

    并循环 (尝试生成新的 T, 依此类推).

请注意, 当从 T 生成 k 时, bits2int 的结果与 q 进行比较, 而不是对 q 取模.如果该值不在 1 和 q-1 之间, 则过程循环.执行简单的模归约会引入偏差, 这将对签名安全性造成损害.


3.3. Alternate Description of the Generation of k (k 生成的替代描述)​

上一节中描述的过程实际上是从 "HMAC_DRBG" 伪随机数生成器派生的, 该生成器在 [SP800-90A] 和 [X9.62] 的附录 D 中描述.使用 [SP800-90A] 的术语, k 的生成可以这样描述:

a. 使用 HMAC 参数化的 HMAC_DRBG 实例化, 使用与用于处理要签名的消息的相同哈希函数 H.实例化参数为:

requested_instantiation_security_strength
将此参数设置为 HMAC_DRBG 实现在使用 H 作为基础哈希函数时将接受的任何值.

prediction_resistance_flag
将此参数设置为 "false".

personalization_string
将此参数设置为 "Null" (空位序列).

entropy_input
使用 int2octets(x) 作为熵字符串.

nonce
使用 bits2octets(H(m)) 作为 nonce.

请注意, 最后两个参数本身不是 HMAC_DRBG 实例化函数的参数; 相反, 这些值在实例化期间从内部 Get_entropy_input 函数请求.对于确定性 (EC)DSA, 我们希望 HMAC_DRBG 使用我们指定的熵字符串和 nonce 运行, 而不访问实际的熵源.

b. 通过从 HMAC_DRBG 请求 qlen 位并使用 bits2int 转换将结果位转换为整数来生成 k 的候选值.重复此步骤, 直到获得非零,小于 q 且适合 (EC)DSA 的值 (参见第 3.4 节).

请注意, 我们为每个签名生成过程实例化一个新的 HMAC_DRBG 实例.生成位时没有 "个性化字符串" 和 "附加输入".HMAC_DRBG 的重新播种功能从未被调用, 无论是外部调用还是作为内部 HMAC_DRBG 处理的结果.

如上所示, 我们使用私钥的编码作为 "熵字符串", 并使用哈希消息 (由 bits2octets 截断和扩展) 作为 "nonce".在 HMAC_DRBG 中, 熵字符串和 nonce 简单地连接到初始种子中; 因此, "熵" 和 "nonce" 之间的分割是相当任意的.为每个使用 qlen 位应该与大多数 HMAC_DRBG 实现输入要求兼容.


3.4. Usage Notes (使用说明)​

使用 DSA 或 ECDSA 时, 值 k 用于计算签名的前半部分, 称为 r (参见第 2.4 节).DSA 和 ECDSA 标准要求, 如果 r 为零, 则应选择新的 k.在这种情况下, 本文档规定值 k 是 "不合适的", 并且生成过程应继续循环.

这种情况的发生是极其不可能的.实际上, 找到导致 r 为零值的私钥和消息需要相当大的计算工作量 (类似于破坏哈希函数的原像抗性); 因此, 纯粹偶然地遇到这种情况被认为是不可能的, 并且攻击者无法通过精心设计的消息强制实现它.在实践中, 这样的代码路径不会被触发, 因此可以以很少的优化来实现.


3.5. Rationale (原理)​

前面几节中描述的过程模仿了 [X9.62] 附录 D 中描述的 k 的 "批准" 生成过程, 使用 "HMAC_DRBG" 伪随机数生成器.主要区别在于我们使用私钥 x 和哈希消息 H(m) 的连接作为伪随机数生成器 (PRNG) 种子.如果使用 n 位的 "安全级别", 则 HMAC_DRBG 应使用至少 n+64 位的种子熵; 但是, 密钥 x 也应该使用那么多熵生成, 并且 x 的长度是 qlen, 它至少等于 2*n, 因此大于 n+64 (DSA 和 ECDSA, 如标准所指定, 要求 qlen >= 160).因此可以认为确定性 ECDSA 满足 [X9.62] 附录 D 的熵要求.

我们使用 bits2octets(H(m)) 而不是 H(m) 是为了简化集成.实际上, 许多现有的签名系统将消息哈希卸载; 签名引擎 (可以访问私钥) 仅接收 H(m).在某些应用中, 数据带宽受到限制, 仅将 H(m) 的前 qlen 位传输到签名引擎, 基于 bits2int 转换无论如何都会忽略后续位.可能在某些系统中, 截断的 H(m) 可以在外部对 q 取模, 因为这是 (EC)DSA 对哈希消息执行的第一件事.通过 bits2octets 的定义, 确定性 (EC)DSA 可以使用相同的输入应用.


3.6. Variants (变体)​

确定性 (EC)DSA 规范的许多部分是相当任意的.可以定义不是 "确定性 (EC)DSA" 但在某些上下文中可能仍然有用的变体:

  • 可以直接使用 H(m), 而不是 bits2octets(H(m)), 作为 HMAC 输入的一部分.如第 3.5 节所述, 我们使用 bits2octets(H(m)) 是为了简化集成到已经使用 (EC)DSA 签名引擎的系统中, 通过向其发送已截断的哈希值.使用整个 H(m) 不会引入任何漏洞.

  • 可以将附加数据添加到 HMAC 的输入中, 连接在 bits2octets(H(m)) 之后:

    K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1) || k')

    一个用例可能是在没有访问高质量随机源的系统上需要非确定性签名算法的协议.只要附加数据 k' 是非重复的 (例如, 签名计数器或单调时钟), 就足以确保 "看起来随机" 的签名在密码学方式上与普通 (EC)DSA 签名无法区分.在 [SP800-90A] 术语中, k' 是可以在生成伪随机位时设置为参数的 "附加输入".此变体可以被认为是对附加数据 k' 来源的随机性的 "增强".

  • 可以使用附加的秘密数据作为 HMAC 的输入, 而不是使用 x (私钥), 这些秘密数据与私钥一起存储并具有相同的安全措施.该附加数据的熵应至少为 n 位, 最好为 n+64 位或更多, 其中 n 是目标安全级别.拥有与私钥本身不同的附加秘密数据可以通过防止侧信道泄漏私钥的 "重放" 来帮助防御此类攻击.但是, 使用附加秘密数据会产生额外的存储要求, 并且必须保证该数据具有足够的熵.

  • 可以使用与用于处理消息的哈希函数 H 不同的哈希函数来参数化 HMAC.这在某些上下文中可能很有用, 例如, 当签名引擎必须支持多个哈希函数但只想实现一个 HMAC 实例时.但是, 这可能会降低安全性, 因为 HMAC 使用的哈希函数的强度应该至少与用于处理消息的哈希函数一样强.


4. Security Considerations (安全考虑)​

密码学签名算法的正确实现和使用需要考虑许多参数.特别是, 私钥生成,存储,访问控制和处置都是敏感操作, 本文档不以任何方式处理这些问题.确定性 (EC)DSA 展示了如何在移除签名生成期间对强随机性来源或甚至任何随机性来源的需求的同时, 实现标准 DSA 或 ECDSA 签名方案的安全特性.

然而, 私钥生成绝对需要这样一个强随机源.在由于缺乏适当的随机性来源而要使用确定性 (EC)DSA 的情况下, 必须假设私钥是在外部生成并导入到签名生成系统中的, 或者是在随机性可用的上下文中生成的.例如, 可以想象一张智能卡在工厂中仍处于受控环境条件下时生成其私钥, 但一旦部署到现场, 在潜在攻击者手中时, 无法保证随机数据生成.

移除随机源要求和针对测试向量测试实现的能力增强了 DSA 和 ECDSA 签名者实现的安全性, 因为它们有助于避免难以测试的故障条件.确定性签名方案在其他情况下也可能有所帮助, 例如, 当使用相同密钥多次签名相同数据元素时避免虚假重复: 使用确定性签名方案, 每次都会生成相同的签名, 使重复检测变得更加容易.

相反, 缺乏随机化在某些高级协议中可能会产生不利影响, 例如, 在某些投票方案中与匿名性相关的协议.作为一个经验法则, 如果整体协议能够容忍另一个确定性签名方案, 特别是 PKCS #1 [RFC3447] (使用 "type 1" 填充, 而不是 PSS) 或 ISO 9796-2 [ISO-9796-2] 中指定的 RSA, 则确定性 DSA 或 ECDSA 可以代替真正的 DSA 或 ECDSA 使用, 而不会产生额外的安全问题.确定性 DSA 或 ECDSA 适用的协议列表包括 Transport Layer Security (传输层安全, TLS) [RFC5246], Secure SHell (安全外壳, SSH) Protocol [RFC4251], Cryptographic Message Syntax (加密消息语法, CMS) [RFC5652] 及其衍生产品, X.509 公钥基础设施 [RFC5280] 以及许多其他协议.

本文档中描述的构造被称为 "去随机化".这已被提议用于各种签名方案.安全性取决于 k 的生成是否与随机预言机的输出无法区分.粗略地说, HMAC_DRBG 在该角色中是安全的, 只要 HMAC 表现为 PRF (伪随机函数).有关 HMAC 和 HMAC_DRBG 安全性的详细信息, 请参阅 [H2008] 和 [B2006].有关去随机化的更正式处理, 请参见 [LN2009].

本文档中提出的确定性 (EC)DSA 的一个遗留问题是私钥 x 的 "双重使用", 既作为签名生成算法本身中的私钥, 又作为基于 HMAC_DRBG 的伪随机预言机的输入以生成 k 值.这要求 HMAC_DRBG 保持作为随机预言机, 即使当公钥 (从 x 计算得出) 也已知时.鉴于 HMAC 和离散对数之间缺乏共同结构, 这似乎是一个合理的假设.

每当攻击者可以准确测量实现的某些方面时, 例如执行签名操作所需的时间长度或签名操作的每个点所消耗的功率时, 侧信道攻击都是一个重要的考虑因素.本说明中描述的算法的确定性在某些形式的侧信道攻击中可能对攻击者有用, 因此实现应该使用防御措施以避免通过侧信道泄漏私钥.


5. Intellectual Property Status (知识产权状态)​

据我们所知, 确定性 (EC)DSA 没有受到任何有效专利的保护.论文 [BDLSY2011] 指出了 Barwood 和 Wigley 在 1997 年初对去随机化思想的两个独立出版物, 并且还指出了几个月后 Naccache,M'Raihi 和 Levy-dit-Vehel 的专利申请 [NML1997], 但该申请于 2003 年被撤回.我们不知道该主题的任何其他专利.


Appendix A. 示例 (Examples)​

本附录汇集 RFC 6979 的确定性 DSA/ECDSA 示例和测试向量. 这些示例用于验证 k 生成过程、哈希函数选择、私钥输入和签名输出是否与规范一致. 具体数值应保持原始十六进制格式.


A.1.2. Generation of k (k 的生成)​

在此示例中, 我们使用哈希函数 SHA-256 [FIPS-180-4].输入消息是字符串 "sample" 的 UTF-8 编码 (6 个字节, 即 48 位).

哈希输入消息 h1 = SHA-256(m) 是:

h1
AF 2B DB E1 AA 9B 6E C1 E2 AD E1 D6 94 F4 1F C7
1A 83 1D 02 68 E9 89 15 62 11 3D 8A 62 AD D1 BF

(32 个字节; 每个字节值以十六进制表示法列出).

我们使用 int2octets 转换将私钥 x 转换为字节序列:

int2octets(x)
00 9A 4D 67 92 29 5A 7F 73 0F C3 F2 B4 9C BC 0F
62 E8 62 27 2F

注意: 尽管 x 的特定值在数值上可以容纳在 160 位即 20 个字节中, 但我们仍将 x 编码为 21 个字节, 因为编码长度由 q 的长度驱动, q 为 163 位.

我们还使用 bits2octets 截断和/或扩展哈希消息:

bits2octets(h1)
01 79 5E DF 0D 54 DB 76 0F 15 6D 0D AC 04 C0 32
2B 3A 20 42 24

步骤 b 到 g (参见第 3.2 节) 然后计算 K 和 V 变量的值.这些变量是 256 位的序列 (哈希函数输出长度, 向上舍入到 8 的倍数).我们在此重现连续的值:

步骤 b 后的 V:
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01

步骤 c 后的 K:
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

步骤 d 后的 K:
09 99 9A 9B FE F9 72 D3 34 69 11 88 3F AD 79 51
D2 3F 2C 8B 47 F4 20 22 2D 11 71 EE EE AC 5A B8

步骤 e 后的 V:
D5 F4 03 0F 75 5E E8 6A A1 0B BA 8C 09 DF 11 4F
F6 B6 11 1C 23 85 00 D1 3C 73 43 A8 C0 1B EC F7

步骤 f 后的 K:
0C F2 FE 96 D5 61 9C 9E F5 3C B7 41 7D 49 D3 7E
A6 8A 4F FE D0 D7 E6 23 E3 86 89 28 99 11 BD 57

步骤 g 后的 V:
78 34 57 C1 CF 31 48 A8 F2 A9 AE 73 ED 47 2F A9
8E D9 CD 92 5D 8E 96 4C E0 76 4D EF 3F 84 2B 9A

在步骤 h 中, 我们执行最终循环.由于我们使用 HMAC 与 SHA-256, 它产生 256 位的输出, 而我们只需要 163 位的 T, 因此单次 HMAC 调用会产生以下 T:

T (第一次尝试)
93 05 A4 6D E7 FF 8E B1 07 19 4D EB D3 FD 48 AA
20 D5 E7 65 6C BE 0E A6 9D 2A 8D 4E 7C 67 31 4A

当使用 bits2int 转换为整数时, 产生 k 的第一个候选值:

k1 = 0x4982D236F3FFC758838CA6F5E9FEA455106AF3B2B

由于该值大于 q-1, 我们必须循环.这首先需要计算 K 和 V 的新值:

新 K
75 CB 5C 05 B2 A7 8C 3D 81 DF 12 D7 4D 7B E0 A0
E9 4A B1 98 15 78 1D 4D 8E 29 02 A7 9D 0A 66 99

新 V
DC B9 CA 12 61 07 A9 C2 7C E7 7B A5 8E A8 71 C8
C9 12 D8 35 EA DD C3 05 F2 44 5D 88 F6 6C 4C 43

然后是新的 T:

T (第二次尝试)
C7 0C 78 60 8A 3B 5B E9 28 9B E9 0E F6 E8 1A 9E
2C 15 16 D5 75 1D 2F 75 F5 00 33 E4 5F 73 BD EB

以及 k 的新候选值:

k2 = 0x63863C30451DADF4944DF4877B740D4F160A8B6AB

由于 k2 也大于 q-1, 我们再次循环:

新 K (2)
0A 5A 64 B9 9C 05 95 20 10 36 86 CB 6F 36 BC FC
A7 88 EB 3B CF 69 BA 66 A5 BB 08 0B 05 93 BA 53

新 V (2)
0B 3B 19 68 11 B1 9F 6C 6F 72 9C 43 F3 5B CF 0D
FD 72 5F 17 CA 34 30 E8 72 14 53 E5 55 50 A1 8F

T (第三次尝试)
47 5E 80 E9 92 14 05 67 FC C3 A5 0D AB 90 FE 84
BC D7 BB 03 63 8E 9C 46 56 A0 6F 37 F6 50 8A 7C

我们最终得到 k 的可接受值:

k = 0x23AF4074C90A02B3FE61D286D5C87F425E6BDD81B

A.2. Test Vectors (测试向量)​

在以下小节中, 我们为 DSA 和 ECDSA 提供了各种密钥大小和哈希函数的测试向量.

测试向量包括:

  • A.2.1. DSA, 1024 Bits
  • A.2.2. DSA, 2048 Bits
  • A.2.3. ECDSA, 192 Bits (Prime Field)
  • A.2.4. ECDSA, 224 Bits (Prime Field)
  • A.2.5. ECDSA, 256 Bits (Prime Field)
  • A.2.6. ECDSA, 384 Bits (Prime Field)
  • A.2.7. ECDSA, 521 Bits (Prime Field)
  • A.2.8. ECDSA, 163 Bits (Binary Field, Koblitz Curve)
  • A.2.9. ECDSA, 233 Bits (Binary Field, Koblitz Curve)
  • A.2.10. ECDSA, 283 Bits (Binary Field, Koblitz Curve)
  • A.2.11. ECDSA, 409 Bits (Binary Field, Koblitz Curve)
  • A.2.12. ECDSA, 571 Bits (Binary Field, Koblitz Curve)
  • A.2.13. ECDSA, 163 Bits (Binary Field, Pseudorandom Curve)
  • A.2.14. ECDSA, 233 Bits (Binary Field, Pseudorandom Curve)
  • A.2.15. ECDSA, 283 Bits (Binary Field, Pseudorandom Curve)
  • A.2.16. ECDSA, 409 Bits (Binary Field, Pseudorandom Curve)
  • A.2.17. ECDSA, 571 Bits (Binary Field, Pseudorandom Curve)

每个测试向量包含:

  • 密钥参数
  • 私钥和公钥
  • 使用不同哈希函数 (SHA-1, SHA-224, SHA-256, SHA-384, SHA-512) 对示例消息 "sample" 和 "test" 的签名

这些测试向量可用于验证确定性 (EC)DSA 实现的正确性.

注意: 由于测试向量内容非常冗长 (包含大量十六进制数据), 完整的测试向量数据应参考原始 RFC 6979 文档的附录 A.2 各小节.


A.3. Sample Code (示例代码)​

本节应包含实现确定性 (EC)DSA 的示例代码.示例代码演示了如何实现本文档中描述的算法.

注意: 完整的示例代码应参考原始 RFC 6979 文档的附录 A.3.示例代码通常包括:

  • k 生成函数的实现
  • HMAC_DRBG 的使用
  • 整数转换函数 (bits2int, int2octets, bits2octets) 的实现
  • 与标准 DSA/ECDSA 签名生成的集成

实现者应确保其代码符合本文档中的规范, 并且可以使用附录 A.2 中的测试向量进行验证.