错误信息
java.security.InvalidAlgorithmParameterException: Curve not supported: secp256k1 (1.3.132.0.10)
也可能输出为
- Legacy SunEC curve disabled
根据曲线最先出现的位置,由 `KeyPairGenerator.initialize`、`KeyFactory.generatePublic/Private`(包装在 `InvalidKeySpecException` 中)或 `Signature.initVerify` 抛出。JDK 15 已默认禁用这些曲线(JDK-8237219),消息为“Legacy SunEC curve disabled”,可以用 `-Djdk.sunec.disableNative=false` 重新启用;JDK 14 及更早版本支持这些曲线。
Java (JDK 16+) — KeyPairGenerator / KeyFactory / Signature with the SunEC provider
含义
JDK 认得 secp256k1 这个名称(比特币和以太坊使用的曲线)——甚至能把它解析为 OID 1.3.132.0.10——但内置的 SunEC 提供程序已经不再实现它。JDK 16 移除了旧式曲线以及原生 EC 库(版本说明“Removal of Legacy Elliptic Curves”,JDK-8235710),只保留了有现代实现的曲线:P-256、P-384、P-521、X25519/X448 和 Ed25519/Ed448。在 Java 8 或 11 上能运行的代码,升级后会在这里失败。
原因
运行在 JDK 16 或更高版本上
常见SunEC 的曲线列表在 JDK 16 中缩减了。为区块链相关服务升级运行时,是最常见的触发原因。
ES256K JWT 或 secp256k1 JWK
偶见委托给 JCA 的 JOSE 库(例如 Nimbus)需要一个支持 secp256k1 的提供程序才能处理 `ES256K`(RFC 8812)。
从2021年以前的示例复制来的代码
偶见用默认提供程序调用 `ECGenParameterSpec("secp256k1")` 的示例,写于这些曲线被移除之前。
修复方法
- 1.
使用 Bouncy Castle 提供程序
Bouncy Castle 用纯 Java 实现了 secp256k1。注册它,并用 `"BC"` 显式指定它。
java import java.security.*; import java.security.spec.ECGenParameterSpec; import org.bouncycastle.jce.provider.BouncyCastleProvider; Security.addProvider(new BouncyCastleProvider()); KeyPairGenerator generator = KeyPairGenerator.getInstance("EC", "BC"); generator.initialize(new ECGenParameterSpec("secp256k1")); KeyPair pair = generator.generateKeyPair(); Signature signature = Signature.getInstance("SHA256withECDSA", "BC"); - 2.
以太坊开发使用专门的库
web3j 等库会替你处理 secp256k1、恢复 ID 和 EIP-191 前缀,而纯 JCA 做不到这些。
java // Ethereum signing/recovery: web3j implements secp256k1 itself (on top of Bouncy Castle). org.web3j.crypto.ECKeyPair keyPair = org.web3j.crypto.Keys.createEcKeyPair(); org.web3j.crypto.Sign.SignatureData sig = org.web3j.crypto.Sign.signPrefixedMessage(message, keyPair);