【问题标题】:Signing a json document or string with x509 certificate使用 x509 证书签署 json 文档或字符串
【发布时间】:2016-11-06 09:09:59
【问题描述】:

如何使用 x509 证书签署 json 文档或字符串?

public static void fund()
{
    string filePath = @"C:\Users\VIKAS\Desktop\Data.xml";
    //Read the file    

    XmlDocument xmlDoc = new XmlDocument();
    XElement ele = XElement.Load(filePath);
    String Xml = ele.ToString();
    xmlDoc.LoadXml(Xml);
    string signature = SignedXMLCert(xmlDoc);
    bool verified = ValidateSignature(signature);
}

public static string SignedXMLCert(XmlDocument xmlDoc)
{
    string startupPath = AppDomain.CurrentDomain.BaseDirectory + @"Certificates\unidesk.p12";
    //  startupPath = AppDomain.CurrentDomain.BaseDirectory + @"\Certificates\BBPS_enc.cer";

    //X509Certificate2 cert = new X509Certificate2(@"D:\Sonal\AXISOU_TEST.P12", "axisbank", X509KeyStorageFlags.Exportable);
    X509Certificate2 cert = new X509Certificate2(startupPath, "axisbank", X509KeyStorageFlags.Exportable);
    //  string PrivateKey = GetRSAPrivateKeyBase64(cert);

    var privateKey = cert.PrivateKey as RSACryptoServiceProvider;
    SignedXml signedXml = new SignedXml(xmlDoc);
    signedXml.SigningKey = privateKey;

    // Create a reference to be signed.
    Reference reference = new Reference();
    reference.Uri = "";

    KeyInfo keyInfo = new KeyInfo();
    //startupPath = AppDomain.CurrentDomain.BaseDirectory + @"\Certificates\BBPS_enc.cer";
    X509Certificate MSCert = new X509Certificate(startupPath, "axisbank", X509KeyStorageFlags.Exportable);
    // X509Certificate MSCert = X509Certificate.CreateFromCertFile(startupPath);

    keyInfo.AddClause(new KeyInfoX509Data(MSCert));
    signedXml.KeyInfo = keyInfo;


    // Add an enveloped transformation to the reference.
    XmlDsigEnvelopedSignatureTransform env = new XmlDsigEnvelopedSignatureTransform();
    reference.AddTransform(env);

    // Add the reference to the SignedXml object.
    signedXml.AddReference(reference);

    // Compute the signature.
    signedXml.ComputeSignature();

    // Get the XML representation of the signature and save
    // it to an XmlElement object.
    XmlElement xmlDigitalSignature = signedXml.GetXml();

    // Append the element to the XML document.
  xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));

    return xmlDoc.InnerXml.ToString();
}

public static bool ValidateSignature(String signedServiceMetadataContent)
{
    bool result = false;

    X509Certificate2 cert = GetCertificate();

    //Load the key
    CspParameters csp = new CspParameters();
    csp.KeyContainerName = cert.PublicKey.Key.ToString();

    RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(csp);

    //Load XML document
    XmlDocument xmlDocument = new XmlDocument();
    xmlDocument.PreserveWhitespace = true;
    xmlDocument.LoadXml(signedServiceMetadataContent);

    //create a SignedXml and load the xml document
    SignedXml signedXml = new SignedXml(xmlDocument);

    //find signature and create signature node list
    XmlNodeList xmlNodeList = xmlDocument.GetElementsByTagName("Signature");

    if (xmlNodeList.Count <= 0)
    {
        throw new CryptographicException("Verification failed: No Signature was found in the document.");
    }
    // if more than one signature was found.
    if (xmlNodeList.Count >= 2)
    {
        throw new CryptographicException("Verification failed: More that one signature was found for the document.");
    }

    //Load signature into SignedXml
    signedXml.LoadXml((XmlElement)xmlNodeList[0]);

    //check the signature
    result = signedXml.CheckSignature(cert, true);
    //result = signedXml.CheckSignature(rsa);


    return result;
}
private static X509Certificate2 GetCertificate()
{
    string startupPath = AppDomain.CurrentDomain.BaseDirectory + @"Certificates\unidesk.p12";
    X509Certificate2 cert = new X509Certificate2(startupPath, "axisbank", X509KeyStorageFlags.Exportable);
    return new X509Certificate2(cert);
}

【问题讨论】:

  • 此代码适用于 XML,但如何签署 json 字符串请帮助我最近几天卡住了
  • Xmldsig 签名格式仅适用于 XML 文档。您可以应用专为 JSON 文档或 CMS 等二进制格式设计的 JSON Web 签名 (JWS)
  • 感谢您的回复,您在 C# 中使用 (RSA ,X509Certificate2) 作为 json 字符串的示例代码
  • 我无法提供完整的示例,但应该不难。 JWS 也是一个 Json 文档,它嵌入您的 Json 并应用例如您正在使用的 RSA 签名。如果您解释签名的目的或预期用途,我可以帮助您了解您需要的属性
  • 这是我的示例 json 字符串 {"updateSRReq": { "incidentID": "", "createdBy": "037022000042048", "description": "037022000042048", "isVisibleToCustomer": "3", “updateType”:“2”,“activityType”:“2”,“createdOn”:“2016-09-08 17:57”,“lastUpdate”:“2016-09-08 17:57”,“status”: “2”,“closeTime”:“”},“subHeader”:{“value”:{“requestUUID”:“123”,“ServiceRequestId”:“AE.MAPS.UDK.SSTP”,“ServiceRequestVersion”:“1.0 ", "ChannelId": "MAPS"}}} 如何对 json 字符串进行签名和验证 json 签名。

标签: c# json xml digital-signature x509certificate2


【解决方案1】:

XMLDsig 签名格式仅适用于 XML 文档。您可以应用专为 JSON 文档设计的 JSON Web 签名 (JWS)。

JWS 签名

具有紧凑序列化的 JWS 表示为(参见 RFC7515

BASE64URL(UTF8(JWS Protected Header)) || '.' ||
BASE64URL(JWS Payload) || '.' ||
BASE64URL(JWS Signature)

JWS 保护标头

最简单的标题由alg组成。 RS256 表示使用 SHA-256 的算法 RSA

{"alg":"RS256"}

您可以添加其他参数,例如x5c(X.509 证书链)或cty(内容类型)

JWS 有效负载

有效负载是编码为 base64url 的 JSON 对象

eyJ1cGRhdGVTUlJlcSI6IHsgImluY2lkZW50SUQiOiAiIiwgImNyZWF0ZWRCeSI6ICIwMzcwMjIwMDAwNDIwNDgiLCAiZGVzY3JpcHRpb24iOiAiMDM3MDIyMDAwMDQyMDQ4IiwgImlzVmlzaWJsZVRvQ3VzdG9tZXIiOiAiMyIsICJ1cGRhdGVUeXBlIjogIjIiLCAiYWN0aXZpdHlUeXBlIjogIjIiLCAiY3JlYXRlZE9uIjogIjIwMTYtMDktMDggMTc6NTciLCAibGFzdFVwZGF0ZSI6ICIyMDE2LTA5LTA4IDE3OjU3IiwgInN0YXR1cyI6ICIyIiwgImNsb3NlZFRpbWUiOiAiIiB9LCAic3ViSGVhZGVyIjogeyAidmFsdWUiOiB7ICJyZXF1ZXN0VVVJRCI6ICIxMjMiLCAiU2VydmljZVJlcXVlc3RJZCI6ICJBRS5NQVBTLlVESy5TU1RQIiwgIlNlcnZpY2VSZXF1ZXN0VmVyc2lvbiI6ICIxLjAiLCAiQ2hhbm5lbElkIjogIk1BUFMifX19

JWS 签名

JWS 签名计算在

BASE64URL(UTF8(JWS Protected Header)) || '.' || BASE64URL(JWS Payload))

构建以下字符串并使用证书的私钥应用 RSA 数字签名算法

eyJhbGciOiJSUzI1NiJ9.eyJ1cGRhdGVTUlJlcSI6IHsgImluY2lkZW50SUQiOiAiIiwgImNyZWF0ZWRCeSI6ICIwMzcwMjIwMDAwNDIwNDgiLCAiZGVzY3JpcHRpb24iOiAiMDM3MDIyMDAwMDQyMDQ4IiwgImlzVmlzaWJsZVRvQ3VzdG9tZXIiOiAiMyIsICJ1cGRhdGVUeXBlIjogIjIiLCAiYWN0aXZpdHlUeXBlIjogIjIiLCAiY3JlYXRlZE9uIjogIjIwMTYtMDktMDggMTc6NTciLCAibGFzdFVwZGF0ZSI6ICIyMDE2LTA5LTA4IDE3OjU3IiwgInN0YXR1cyI6ICIyIiwgImNsb3NlZFRpbWUiOiAiIiB9LCAic3ViSGVhZGVyIjogeyAidmFsdWUiOiB7ICJyZXF1ZXN0VVVJRCI6ICIxMjMiLCAiU2VydmljZVJlcXVlc3RJZCI6ICJBRS5NQVBTLlVESy5TU1RQIiwgIlNlcnZpY2VSZXF1ZXN0VmVyc2lvbiI6ICIxLjAiLCAiQ2hhbm5lbElkIjogIk1BUFMifX19 

最后将签名编码为base64url,并将结果附加到之前要签名的数据中。您将获得类似 hhhhh.ppppp.sssss 的 JWS,其中 hhhhh 是标头 ppppp 有效负载,sssss 是签名

使用以下链接

JWS 验证

从压缩格式hhhhh.ppppp.sssss验证签名,base64url解码签名sssss,并使用签名数据hhhhh.ppppp和使用的证书验证签名

【讨论】:

  • 替代方案:JSON 文件上的(分离的)XML 或 CMS 签名。请注意,在这种情况下,JSON 表示不应在签名和验证之间发生变化。 JSON 签名当然是更优雅的解决方案。
  • 签名是否取决于 JSON 中的字段顺序?
  • @AndrewSneck,JWS 签名是在原始负载上执行的,因此字段、空格、字符或 JSON 的任何变体的顺序将使签名无效。这在 XMLDsig 中并非完全如此,因为有一个预先的规范化过程,它允许某种类型的可变性,但同时使 XML 签名在实践中更难以使用。
猜你喜欢
  • 2014-06-17
  • 2018-07-19
  • 2014-10-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-28
  • 2011-06-01
  • 2013-08-07
相关资源
最近更新 更多