如何使用BouncyCastle实现Ed25519 pureEdDSA无哈希签名?
解决方案
BouncyCastle提供的标准"ed25519"签名算法严格遵循RFC 8032规范,会默认对消息执行SHA-512哈希后再进行签名。如果要匹配你的嵌入式控制器要求的无哈希pureEdDSA逻辑,需要绕过BouncyCastle的自动哈希流程,手动实现签名逻辑。
实现步骤
1. 转换私钥格式
首先将Java标准的Ed25519PrivateKey转换为BouncyCastle底层的Ed25519PrivateKeyParameters,以便调用底层签名API:
import org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters import java.security.KeyFactory import java.security.spec.PKCS8EncodedKeySpec // 转换Java私钥为BouncyCastle参数类 val keyFactory = KeyFactory.getInstance("Ed25519", "BC") val privateKeySpec = PKCS8EncodedKeySpec(privateKey.encoded) val bcPrivateKey = keyFactory.generatePrivate(privateKeySpec) as Ed25519PrivateKeyParameters
2. 自定义无哈希签名逻辑
由于BouncyCastle的Ed25519Signer硬编码了SHA-512哈希步骤,我们可以通过反射替换哈希实现,让签名器直接使用原始消息(填充至64字节,匹配SHA-512输出长度)进行计算:
import org.bouncycastle.crypto.Digest import org.bouncycastle.crypto.signers.Ed25519Signer import java.lang.reflect.Field import java.util.Arrays // 自定义Digest,直接返回原始消息(补零至64字节),跳过哈希 class NoHashDigest : Digest { private val buffer = ByteArray(64) private var position = 0 override fun getAlgorithmName(): String = "NoHash" override fun getDigestSize(): Int = 64 override fun update(inByte: Byte) { if (position < 64) { buffer[position++] = inByte } } override fun update(input: ByteArray, inOff: Int, length: Int) { val copyLength = minOf(length, 64 - position) System.arraycopy(input, inOff, buffer, position, copyLength) position += copyLength } override fun reset() { position = 0 Arrays.fill(buffer, 0x00) } override fun out(output: ByteArray, outOff: Int): Int { System.arraycopy(buffer, 0, output, outOff, 64) reset() return 64 } } // 实例化签名器并替换哈希实现 val signer = Ed25519Signer() val digestField: Field = Ed25519Signer::class.java.getDeclaredField("digest") digestField.isAccessible = true digestField.set(signer, NoHashDigest()) // 初始化签名器并生成签名 signer.init(true, bcPrivateKey) val message = byteArrayOf(...) // 你的32字节消息 signer.update(message, 0, message.size) val signature = signer.generateSignature() // 64字节签名
3. 注意事项
- 这种实现属于非标准Ed25519变种,仅为匹配嵌入式控制器逻辑,不兼容标准Ed25519验证。
- 如果控制器对消息的填充方式不是补零(比如重复消息至64字节),需要调整
NoHashDigest的逻辑以匹配。
内容的提问来源于stack exchange,提问作者Raynigon
相关产品推荐
相关产品推荐

