Azure Key Vault P-256 EC密钥本地签名验证失败求助
问题分析与解决方案
你的验证失败核心有两个错误:
- 错误将签名按UTF8字节解析,实际需要对签名做Base64URL解码
- Azure Key Vault返回的签名是ASN.1/DER编码格式,而.NET的
ECDsa.VerifyData默认期望原始的r-s拼接格式
修正后的代码
// x and y points from JWK string x = "melmeVA/KKt+kTRGljKubiohqcwD9A65dyX3nxqxUg8="; string y = "wSOw9N8jkoeMgdNMCeAAKop4kR9f8jrvDOZnpkc9Fw0="; ECDsa key = ECDsa.Create(new ECParameters { Curve = ECCurve.NamedCurves.nistP256, Q = new ECPoint { X = Base64UrlEncoder.DecodeBytes(x), Y = Base64UrlEncoder.DecodeBytes(y) } }); var header = "{\"alg\":\"ES256\"}"; var body = "{\"key\":\"value\"}"; var toBeSigned = Base64UrlEncoder.Encode(header) + "." + Base64UrlEncoder.Encode(body); // Sign API response (using the digest from above) var signature = "ZBPn3jJpccDPasbasOfocjSkHpRA0bmn2963IMzraa50H5v5ovtavtilwpu7zf_8McwfR9qCrkXMiXBOf4W8BQ"; // 修正1:对签名做Base64URL解码,而非UTF8解析 byte[] signatureBytes = Base64UrlEncoder.DecodeBytes(signature); // 修正2:指定签名格式为ASN.1 DER(.NET Core 3.0+/.NET 5+支持) bool result = key.VerifyData( Encoding.UTF8.GetBytes(toBeSigned), signatureBytes, HashAlgorithmName.SHA256, DSASignatureFormat.Rfc3279DerSequence); Console.WriteLine(result);
兼容旧版.NET的方案
如果你的项目使用不支持DSASignatureFormat的.NET版本,可以手动将ASN.1格式签名转换为r-s拼接格式:
private static byte[] ConvertDerToRs(byte[] derSignature) { // ASN.1 DER结构:SEQUENCE { r INTEGER, s INTEGER } using (var ms = new MemoryStream(derSignature)) using (var reader = new BinaryReader(ms)) { if (reader.ReadByte() != 0x30) throw new InvalidDataException("无效签名格式"); int length = reader.ReadByte(); if (length == 0x81) length = reader.ReadByte(); if (reader.ReadByte() != 0x02) throw new InvalidDataException("无效r字段"); int rLength = reader.ReadByte(); byte[] r = reader.ReadBytes(rLength).TrimLeadingZero(); if (reader.ReadByte() != 0x02) throw new InvalidDataException("无效s字段"); int sLength = reader.ReadByte(); byte[] s = reader.ReadBytes(sLength).TrimLeadingZero(); // P-256要求r/s均为32字节,补全长度 r = r.PadLeft(32); s = s.PadLeft(32); return r.Concat(s).ToArray(); } } private static byte[] TrimLeadingZero(this byte[] data) { int startIndex = 0; while (startIndex < data.Length && data[startIndex] == 0) startIndex++; return startIndex == 0 ? data : data[startIndex..]; } private static byte[] PadLeft(this byte[] data, int length) { if (data.Length >= length) return data; byte[] padded = new byte[length]; Array.Copy(data, 0, padded, length - data.Length, data.Length); return padded; }
使用时替换验证逻辑:
byte[] rsSignature = ConvertDerToRs(signatureBytes); bool result = key.VerifyData(Encoding.UTF8.GetBytes(toBeSigned), rsSignature, HashAlgorithmName.SHA256);
额外验证点
- 确认JWK的x/y值是从Azure Key Vault密钥属性中正确提取的(必须是Base64URL编码,而非标准Base64)
- 确认调用Sign API时使用的算法是
ES256,与代码中签名算法保持一致
内容的提问来源于stack exchange,提问作者Brânica
相关产品推荐
相关产品推荐

