袖手无策:P256 安全曲线

本文探讨了椭圆曲线密码学(ECC)中P256曲线的安全问题,特别是关于美国国家安全局(NSA)可能存在的后门。文章介绍了Baby Jubjub曲线的设计,并讨论了secp256k1曲线的安全性。此外,文章还提到了针对NIST椭圆曲线种子信息的悬赏活动,以及在量子计算时代向后量子密码学(PQC)迁移的必要性。

没有幕后交易:安全曲线

互联网上最伟大的黑客行为会是什么?也许是破解 TLS 连接的密钥交换?如果 NSA 能够破解这些,几乎每一个 Web 连接都可能被暴露。这些连接要么使用 RSA 来封装用于加密隧道的密钥,要么更常见地使用 ECDH 方法。用于 ECDH 最常见的曲线是 NIST 定义的 P256 曲线。那么,它能安全地躲过 NSA 的窥探吗?正如温斯顿·丘吉尔曾经评价俄罗斯时所说:

它是一个谜语,包裹在一个谜团之中,又包含在一个谜之中;但或许那里

有一把钥匙 — 温斯顿·丘吉尔

阿桑奇、斯诺登和陷阱门

但是,关于最常用的曲线 (P256) 存在 NSA 后门的另一个阴谋论又如何呢?如果确实存在后门,那么数十亿的网络连接将面临风险,因为 P256 是密钥交换最常用的方法。

许多人认为 NSA 已经攻破了该曲线,并指向了这个页面 [这里]:

但是,P256 (secp256r1) 不安全并不能证明它已经被攻破。我们可以看到 secp256k1 曲线(用于比特币和以太坊)也被标记为不安全。

P-256 的基本原理是它使用以下形式的参数:

y² =x²+ax+b (mod p)

然后我们选择曲线上的一个基点 G。以下是参数 [这里]:

在这种情况下,我们有 G、a 和 b,其中 N 是曲线的阶数(基本上是可以选择的可能点的数量)。

设计一个安全曲线

创建 Baby Jubjub 是为了满足使用 Fr 算术电路的椭圆曲线的要求(其中我们有一个大小为 r 的有限域 ( Fr))。选择扭曲爱德华兹曲线是因为它具有用于在曲线上添加两个点的单个完整公式 —— 这对于电路内的计算非常有效。

除此之外,扭曲爱德华兹曲线可以转换为等效的 Montgomery 曲线。这允许在电路外部的 Montgomery 曲线中进行点加法和倍乘。

总的来说,设计是取一个素数 p = 1 (mod 4),然后找到 A 的最小值,使得 A-2 是 4 的倍数。选择的素数是:

r=21888242871839275222246405745257275088548364400416034343698204186575808495617

这实际上是 BN128 的阶数(因此具有等效的安全级别)。结果是:

a=168,700
d=168,696

然后我们有一个生成器点和一个基点,它们提供对两个点的循环群的访问。

然后我们可以使用生成器点执行标量乘法。在 Baby Jubjub 中,生成器点 ( G) 是:

Gx=995203441582195749578291179787384436505546430278305826713579947235728471134
Gy=5472060717959818805561601436314318772137091100104008585924551046643952123905

在 Go 中,我们可以使用 Big Integers 通过 [这里]设置生成器点:

// 生成器点 (G)
x,_ := new(big.Int).SetString("995203441582195749578291179787384436505546430278305826713579947235728471134",10 )
y,_ := new(big.Int).SetString("5472060717959818805561601436314318772137091100104008585924551046643952123905",10)
G := &babyjub.Point{X: x, Y: y}

如果我们选择生成器点,我们将生成曲线的所有 n 个点 (21888242871839275222246405745257275088614511777268538073601725287587578984328)。我们也可以有一个基点 ( B) [这里]:

x = 5299619240641551281634865583518297030282874472190772894086521144482721001553
y = 16950150798460657717958625567821834550301663161624707787222815936182638968203

这将生成满足 l × P 的点子群 P — 并且我们得到 l 个点的子群。基点是 8. G [这里]:

package main
import (
 "fmt"
 "github.com/iden3/go-iden3-crypto/v2/babyjub"
 "math/big"
)
func main() {
 x_g,_ := new(big.Int).SetString("995203441582195749578291179787384436505546430278305826713579947235728471134",10 )
 y_g,_ := new(big.Int).SetString("5472060717959818805561601436314318772137091100104008585924551046643952123905",10)

 x_b,_ := new(big.Int).SetString("5299619240641551281634865583518297030282874472190772894086521144482721001553",10 )
 y_b,_ := new(big.Int).SetString("16950150798460657717958625567821834550301663161624707787222815936182638968203",10)

 G := &babyjub.Point{X: x_g, Y: y_g}
 B := &babyjub.Point{X: x_b, Y: y_b}

 fmt.Printf("G (%s, %s)\n",G.X.String(),G.Y.String())
 fmt.Printf("B (%s, %s)\n",B.X.String(),B.Y.String())

  s:=new(big.Int).SetInt64(8)
  sG := babyjub.NewPoint().Mul(s, G)
  fmt.Printf("(%d).G 点 (%s, %s)\n",s,sG.X.String(),sG.Y.String())
}

一个示例运行表明 B =8. G:

G (995203441582195749578291179787384436505546430278305826713579947235728471134, 5472060717959818805561601436314318772137091100104008585924551046643952123905)
B (5299619240641551281634865583518297030282874472190772894086521144482721001553, 16950150798460657717958625567821834550301663161624707787222815936182638968203)
(8).G 点 (5299619240641551281634865583518297030282874472190772894086521144482721001553, 16950150798460657717958625567821834550301663161624707787222815936182638968203)

这个设计中没有幕后交易。

那么 secp256k1 是否已被破解?

应该记住的是,在大多数情况下,网络安全中的一切都可以被破解,这完全取决于某人愿意投入的资源。但是,一般来说,对于当前时间的 128 位安全性,需要耗尽地球上所有海洋的能量,甚至更多倍,才能破解单个椭圆曲线密钥。由于 P256 具有 128 位安全性,因此通常被认为是免受暴力破解的。然而,随着量子计算机的出现,情况不太可能如此。

总的来说,目前它可能是安全的,但我们不能保证。这就是它不能被标记为安全的原因。页面上的“不安全”标记只是表明有一些事情可以帮助证明它在当前时间是完全安全的,并且该曲线没有得到完全优化。应该记住的是,P256 的使用次数可能比许多标记为安全的曲线多数万亿次。

关于 P256 的大辩论来自用于生成其参数的种子。此种子值为 0xc49d360886e70493 6a6678e1139d26b7819f7e90。辩论的核心是该曲线最初由 Jerry Solinas 定义,他一度为 NSA 工作 [这里]。选择如此大的随机值使得检查曲线的安全性变得困难,并且可能发现种子值具有后门。

总的来说,在生成椭圆曲线参数时,我们可以采用随机生成的参数或专门选择的参数。Curve 25519 具有专门为性能和安全性选择的参数,而 Brainpool 的参数是随机生成的。生成随机曲线的方法有据可查,包括使用的种子值。这样做的一个问题是,我们可能会生成一些违反现有专利的东西。这种方法是“没有幕后交易”,并且可以证明随机种子来自随机源。这就像经销商将牌交给机械洗牌机,然后洗牌机使用真正的随机源作为其种子随机洗牌,然后将牌交还给经销商。因此,不幸的是,我们没有 P256 的原始随机值证明,因为它的来源已经丢失。没有人知道 NIST 是否是实际生成曲线种子的机构。

在你的收件箱中获取 Prof Bill Buchanan OBE FRSE 的故事

免费加入 Medium 以获取来自这位作者的更新。

因此,我们不太可能证明 P256 是否安全,但从概率平衡来看,它可能是安全的。可以肯定的一件事是,随着量子计算机 (QC) 的猛攻,ECC 将首先崩溃,因此我们或许应该考虑在不久的将来摆脱它。然而,对于 QC 来说,RSA 将是一块更难啃的骨头,并且可能能够坚持更长时间。

Matthew Green 的一篇精彩文章:

https://blog.cryptographyengineering.com/2015/10/22/a-riddle-wrapped-in-curve/?source=post_page-----75c1dd63fc79---------------------------------------

在这篇文章中,Matthew 概述了来自 ECC 联合创始人(Koblitz)和最具知识的密码学作者之一(Menezes)关于 NSA 猜测的论文[1]:

在论文中,作者概述说,如果有人相信阴谋论,他们或许应该完全避免使用 ECC,而改用 RSA 进行数字签名。

曲线会面

有许多不同类型的标准椭圆曲线,最常见的有 Brainpool、SEC 和 NIST。两种最常见的曲线是 secp256k1(用于比特币和以太坊)和 NIST (FIPS) P-256(用于 TLS)。这些曲线为我们提供了大约 128 位的安全性。众所周知,secp256k1 具有以下曲线参数:

G=(79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8,1,0), N=115792089237316195423570985008687907852837564279074904382605163141518161494337, H=1
A =0
B=7
Field size=256

但还有许多其他曲线,包括 Brainpool256r1:

G=(8bd2aeb9cb7e57cb2c4b482ffc81b7afb9de27e1e3bd23c23a4453bd9ace3262,547ef835c3dac4fd97f8461a14611dc9c27745132ded8e545c1d54c72f046997,1,7d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6ce94a4b44f330b5d9), N=76884956397045344220809746629001649092737531784414529538755519063063536359079, H=1
A =7d5a0975fc2c3057eef67530417affe7fb8055c126dc5c6ce94a4b44f330b5d9
B=26dc5c6ce94a4b44f330b5d9bbd77cbf958416295cf7e1ce6bccdc18ff8c07b6
Field size=256

使用椭圆曲线密码学,我们首先定义曲线,例如:

y ²= x ³+ ax + b(mod p)

这定义了 abp 的值。接下来,我们在曲线上选择一个基点 ( G),并生成一个随机标量值 ( D)。这是私钥,公钥由以下点乘法生成:

Q = D. G

这会在曲线上产生一个 ( x, y) 点。

编码

首先,我们创建一个名为 "bc_ec02" 的文件夹,然后进入该文件夹。我们可以使用以下命令为 .NET 8.0 创建一个 Dotnet 控制台项目:

dotnet new console --framework net8.0

接下来,我们可以使用以下命令安装 Bouncy Castle 库:

dotnet add package BouncyCastle.Crypto.dll --version 1.8.1

接下来是一些代码 [这里]:

namespace ECCurves
{
    using Org.BouncyCastle.Asn1.X9;
    using Org.BouncyCastle.Security;
    using Org.BouncyCastle.Crypto.Parameters;
class Program
    {

        static void Main(string[] args)
        {

            var curvename="secp256k1";

if (args.Length >0) curvename=args[0];

            try {
            X9ECParameters ecParams = ECNamedCurveTable.GetByName(curvename);
            var curveparam = new ECDomainParameters(ecParams.Curve, ecParams.G, ecParams.N, ecParams.H, ecParams.GetSeed());

            Org.BouncyCastle.Crypto.Parameters.ECKeyGenerationParameters keygenParams = new Org.BouncyCastle.Crypto.Parameters.ECKeyGenerationParameters (curveparam, new SecureRandom());
            Org.BouncyCastle.Crypto.Generators.ECKeyPairGenerator generator = new  Org.BouncyCastle.Crypto.Generators.ECKeyPairGenerator();
            generator.Init(keygenParams);
            var keyPair = generator.GenerateKeyPair();
            var privateKey = (ECPrivateKeyParameters) keyPair.Private;
            var publicKey = (ECPublicKeyParameters) keyPair.Public;
            Console.WriteLine("== 曲线: {0} ",curvename);
            Console.WriteLine("\n== 私钥 === ");
            Console.WriteLine("== D ==={0} ",privateKey.D.ToString());
            Console.WriteLine("\n== 公钥 === ");
            Console.WriteLine("== Q_x ==={0} ",publicKey.Q.XCoord);
            Console.WriteLine("== Q_t ==={0} ",publicKey.Q.YCoord);
            Console.WriteLine("\n\n曲线细节: G={0}, N={1}, H={2}", ecParams.G, ecParams.N, ecParams.H);
            Console.WriteLine("A={0}\nB={1}\n字段大小={2}",ecParams.Curve.A,ecParams.Curve.B,ecParams.Curve.FieldSize);
    } catch (Exception e) {
    Console.WriteLine("错误: {0}",e.Message);
    }
    }
    }
}

现在我们应该能够为几乎所有可能的标准曲线生成密钥对:

secp2561 的示例运行给出 [这里]:

== 曲线:secp256k1
== 私钥 ===
== D ===31064867539724903891960137032820676127521229242105362809544430719991795260503
== 公钥 ===
== Q_x ===8c65b935e0fd6e174c7b180f5d1db7cda52bf8222d11f7abc924067c40e11de8
== Q_t ===6e4602ae3c8f42683f4d7269c4abf55a28bcd69ff84060118f327d25c1074a1e
曲线细节:G=(79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798,483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8,1,0), N=115792089237316195423570985008687907852837564279074904382605163141518161494337, H=1
A =0
B=7
字段大小=256

对于 NIST (FIPS) P-256 [这里]:

== 曲线:P-256
== 私钥 ===
== D ===36520681454922814890347386938615718499728808447933454325466265828246263851321
== 公钥 ===
== Q_x ===d52722849984ff0a89d50de91877f66377ba4065c5802adc169c235ad37d1eea
== Q_t ===7fc6d99095fe7712f5ec1f5b5f9d5425cf7ae9de4f2d77d4022f67d6f8aa3f75
曲线细节:G=(6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296,4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5,1,ffffffff00000001000000000000000000000000fffffffffffffffffffffffc), N=115792089210356248762697446949407573529996955224135760342422259061068512044369, H=1
A =ffffffff00000001000000000000000000000000fffffffffffffffffffffffc
B=5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b
字段大小=256

这是使用 Microsoft Code 的创建:

赏金

2023 年 10 月,为任何人发现 P-192、P-224、P-256、P-384 和 P-521 定义的 NIST 椭圆曲线的种子定义了赏金:

https://www.redpacketsecurity.com/bounty-offered-for-secret-nsa-seeds-behind-nist-elliptic-curves-algo/?source=post_page-----75c1dd63fc79---------------------------------------

有些人认为它可能是由一个短语或一组单词生成的。当曲线发布时,Mike Scott 写道:

现在,如果我们的想法是增加我们对这些曲线是因此从大量可能的椭圆曲线中完全随机选择的,因此可能是安全的,我认为此过程失败了。基本假设是绝大多数曲线都是“好的”。现在考虑这样一种可能性,即所有曲线中百万分之一的曲线具有“他们”知道但我们不知道的可利用结构……然后“他们”只需生成一百万个随机种子,直到找到一个生成“他们”其中一条曲线。然后他们让我们使用它们。请记住,标准的偏执假设适用 —— “他们”拥有远远超出我们所能拥有的计算能力。所以也许可能是 10 亿

结论

使用 ECC 的时代即将结束,我们必须在未来几年内迁移到 PQC(后量子密码学)方法。希望这些都具有可证明的安全技术和“没有幕后交易”。如果你确实认为 NSA 已经破解了 P256,那么或许可以将你的签名和密钥交换切换到 RSA 或 PQC 方法。

参考文献

[1] Koblitz, N., & Menezes, A. (2016). A riddle wrapped in an enigma. IEEE Security & Privacy, 14(6), 34–42.

  • 原文链接: medium.com/asecuritysite...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
asecuritysite
asecuritysite
江湖只有他的大名,没有他的介绍。