.NET中ECDSA签名从DER格式转换为RS格式的实现方案
AWS KMS DER格式签名转JWT兼容的RS格式(.NET实现)
JWT要求的RSASSA-PKCS1-v1_5签名是PKCS#1 raw格式(即直接拼接签名的R、S整数分量,无ASN.1编码结构),而AWS KMS返回的签名是DER编码的ASN.1结构,需要提取R、S分量后重新拼接。以下是两种可行的实现方式:
1. 使用.NET内置API手动转换
无需额外NuGet包,利用System.Formats.Asn1命名空间解析DER结构:
using System.Formats.Asn1; public static byte[] ConvertDerToRawRSASignature(byte[] derSignature) { // 解析ASN.1 DER格式的签名序列 var reader = new AsnReader(derSignature, AsnEncodingRules.DER); var sequenceReader = reader.ReadSequence(); // 读取R和S两个整数的字节数组 byte[] r = sequenceReader.ReadIntegerBytes(); byte[] s = sequenceReader.ReadIntegerBytes(); // 根据密钥长度调整R、S为固定字节数(2048位密钥对应256字节,3072位对应384字节) int keySizeBytes = 256; r = PadToFixedLength(r, keySizeBytes); s = PadToFixedLength(s, keySizeBytes); // 拼接R和S得到JWT所需的raw签名 byte[] rawSignature = new byte[keySizeBytes * 2]; Buffer.BlockCopy(r, 0, rawSignature, 0, keySizeBytes); Buffer.BlockCopy(s, 0, rawSignature, keySizeBytes, keySizeBytes); return rawSignature; } private static byte[] PadToFixedLength(byte[] data, int targetLength) { if (data.Length == targetLength) return data; byte[] padded = new byte[targetLength]; // 处理ASN.1整数可能带的前导0,确保最终是固定长度的无符号整数字节 int copyStart = data.Length > targetLength ? data.Length - targetLength : 0; int copyLength = Math.Min(data.Length, targetLength); Buffer.BlockCopy(data, copyStart, padded, targetLength - copyLength, copyLength); return padded; }
转换后的raw签名可直接用于JWT的Base64Url编码(Convert.ToBase64String(rawSignature).Replace('+', '-').Replace('/', '_').TrimEnd('=')),或传入JwtSecurityTokenHandler完成JWT生成。
2. 使用BouncyCastle NuGet包简化操作
如果不想手动处理ASN.1解析,可引入BouncyCastle.Cryptography NuGet包:
using Org.BouncyCastle.Asn1.Pkcs; public static byte[] ConvertDerToRawRSASignature(byte[] derSignature) { var rsaSig = RsaSignature.FromDerEncoded(derSignature); int keySizeBytes = (rsaSig.ModulusBitLength + 7) / 8; byte[] r = rsaSig.R.ToByteArrayUnsigned(); byte[] s = rsaSig.S.ToByteArrayUnsigned(); r = PadToFixedLength(r, keySizeBytes); s = PadToFixedLength(s, keySizeBytes); byte[] rawSignature = new byte[keySizeBytes * 2]; Buffer.BlockCopy(r, 0, rawSignature, 0, keySizeBytes); Buffer.BlockCopy(s, 0, rawSignature, keySizeBytes, keySizeBytes); return rawSignature; } // 复用前面的PadToFixedLength方法
关键注意事项
- 需根据实际使用的KMS密钥长度调整
keySizeBytes值,避免签名长度不匹配导致JWT验证失败。 - 若直接生成JWT,可自定义
ISecurityTokenSigningKeyProvider,在签名逻辑中调用上述转换方法,替代本地私钥签名流程。
内容的提问来源于stack exchange,提问作者busch-dk
相关产品推荐
相关产品推荐

