You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

关于HashiCorp Vault Transit SHA256withECDSA签名支持及Java验证异常的问询

Vault Transit ECDSA-P256 签名在Java中验证失败:Invalid encoding for signature

核心结论

Transit引擎完全支持ecdsa-p256密钥搭配SHA256withECDSA算法——ecdsa-p256(NIST P-256)本身就是与SHA-256配对的椭圆曲线密钥体系,验证失败的问题出在签名格式不兼容,而非算法支持问题。

原因分析

Vault Transit API返回的ECDSA签名默认采用ASN.1 DER编码格式,而Java的SHA256withECDSA签名验证逻辑(基于SunEC等主流provider)默认期望的是IEEE P1363格式(即直接拼接签名的r、s分量,形成64字节的二进制数据),格式不匹配导致抛出SignatureException: Invalid encoding for signature。

解决方案

有两种可行的解决方式,推荐第一种更直接的方案:

方案1:让Vault返回IEEE P1363格式的签名

调用/v1/transit/sign/ API时,添加signature_algorithm: "raw"参数,让Vault直接输出r+s拼接的原始格式签名,Java可直接验证。

修改后的curl命令:

curl --location 'http://localhost:8200/v1/transit/sign/test' \
--header 'X-Vault-Token: hvs.GJjDLDxW1iikrJfjK9PJgXTa' \
--header 'Content-Type: application/json' \
--data '{ 
  "input": "c2FtcGxlIHRleHQ=",
  "signature_algorithm": "raw"
}'

注意:原请求的Content-Type设为text/plain是错误的,请求体为JSON时需改为application/json。

对应的Java验证示例:

import java.security.*;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;

public class ECDSAValidation {
    public static void main(String[] args) throws Exception {
        // 从Vault获取的公钥(Base64编码)
        String publicKeyB64 = "替换为你的公钥Base64字符串";
        // 从Vault获取的raw格式签名(Base64编码)
        String signatureB64 = "替换为获取到的raw签名Base64字符串";
        // 原始输入文本
        String input = "sample text";

        // 加载公钥
        byte[] pubKeyBytes = Base64.getDecoder().decode(publicKeyB64);
        KeyFactory keyFactory = KeyFactory.getInstance("EC");
        PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(pubKeyBytes));

        // 初始化签名验证
        Signature sig = Signature.getInstance("SHA256withECDSA");
        sig.initVerify(pubKey);
        sig.update(input.getBytes());

        // 验证签名
        boolean isValid = sig.verify(Base64.getDecoder().decode(signatureB64));
        System.out.println("签名验证结果:" + isValid);
    }
}

方案2:在Java中转换DER格式为IEEE P1363格式

如果无法修改Vault请求参数,可在Java中解析DER编码的签名,提取r、s分量后拼接成所需格式。需要引入BouncyCastle库来处理ASN.1解析:

import org.bouncycastle.asn1.ASN1InputStream;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Sequence;
import java.util.Base64;

public static byte[] convertDerToRaw(byte[] derSignature) throws Exception {
    try (ASN1InputStream asn1In = new ASN1InputStream(derSignature)) {
        ASN1Sequence seq = (ASN1Sequence) asn1In.readObject();
        ASN1Integer r = (ASN1Integer) seq.getObjectAt(0);
        ASN1Integer s = (ASN1Integer) seq.getObjectAt(1);

        byte[] rBytes = r.getPositiveValue().toByteArray();
        byte[] sBytes = s.getPositiveValue().toByteArray();

        // 补全为32字节(P-256固定长度)
        byte[] rPadded = new byte[32];
        System.arraycopy(rBytes, rBytes.length > 32 ? 1 : 0, rPadded, 32 - rBytes.length, Math.min(rBytes.length, 32));
        byte[] sPadded = new byte[32];
        System.arraycopy(sBytes, sBytes.length > 32 ? 1 : 0, sPadded, 32 - sBytes.length, Math.min(sBytes.length, 32));

        // 拼接r和s
        byte[] rawSig = new byte[64];
        System.arraycopy(rPadded, 0, rawSig, 0, 32);
        System.arraycopy(sPadded, 0, rawSig, 32, 32);
        return rawSig;
    }
}

使用时,先将Vault返回的DER签名转换为raw格式,再传入Signature.verify()方法即可。


内容的提问来源于stack exchange,提问作者yash srivastava

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 04:07:03