如何将 HSM 中存储的私钥转换为 C# 中的 SignedXml.SigningKey

2023-12-05

我正在尝试使用存储在 HSM 中的证书来实现一些 XML 签名演示。

我从此链接中找到了一些有趣的示例:使用 X509Certificate2 签署 XML 文档并将其修改为使用带有 PKCS11Interop 包装器的 HSM 内的证书和密钥。

但任何人都可以给我一个建议或例子将 ObjectHandle privateKey 从 HSM 转换为 SignedXML.SigningKey

private static void SignXmlWithCertificate(XmlDocument xmlDoc, X509Certificate2 cert, Session session, String alias)
        {
            SignedXml signedXml = new SignedXml(xmlDoc);

            List<ObjectAttribute> template = new List<ObjectAttribute>();
            template.Add(new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_PRIVATE_KEY));
            template.Add(new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_RSA));
            template.Add(new ObjectAttribute(CKA.CKA_LABEL, alias));
            List<ObjectHandle> foundObjects = session.FindAllObjects(template);
            ObjectHandle privateKey = foundObjects[0];

            signedXml.SigningKey = privateKey; //Here is where I stuck.

在上面外部链接的示例中。他们使用结合了私钥的证书。然后他们就可以这样使用。

signedXml.SigningKey = cert.PrivateKey;

但我使用的证书里面没有私钥的内容。请给我一些建议。


您需要实现继承自的自定义类System.Security.Cryptography.Xml.SignedXml像这样

public class CustomSignedXml: SignedXml
    {
    public CustomSignedXml(XmlDocument xmlDoc):base(xmlDoc)
    {
    }
    internal void ComputeSignature(ISignerProvider signerProvider)
    {
        var methodInfo = typeof (SignedXml).GetMethod("BuildDigestedReferences",
            BindingFlags.Instance | BindingFlags.NonPublic);
        methodInfo.Invoke(this, null);
        SignedInfo.SignatureMethod = XmlDsigRSASHA1Url;
        // See if there is a signature description class defined in the Config file
        SignatureDescription signatureDescription =
            CryptoConfig.CreateFromName(SignedInfo.SignatureMethod) as SignatureDescription;
        if (signatureDescription == null)
            throw new CryptographicException("Cryptography_Xml_SignatureDescriptionNotCreated");

        var hashAlg = signatureDescription.CreateDigest();
        if (hashAlg == null)
            throw new CryptographicException("Cryptography_Xml_CreateHashAlgorithmFailed");
        var methodInfo2 = typeof (SignedXml).GetMethod("GetC14NDigest", BindingFlags.Instance | BindingFlags.NonPublic);
        var hashvalue = (byte[]) methodInfo2.Invoke(this, new object[] {hashAlg});

        m_signature.SignatureValue = signerProvider.Sign(hashvalue);
    }
}

然后你需要创建这样的界面

public interface ISignerProvider
{
    byte[] Sign(byte[] data);
}

然后通过执行它Pkcs11互操作像这样

    public class Pkcs11SignerProvider : ISignerProvider
{
    private string _thumbprint;
    public string DllPath { get; set; }
    public string TokenSerial { get; set; }
    public string TokenPin { get; set; }
    public string PrivateKeyLabel { get; set; }

    public Pkcs11SignerProvider(string dllPath, string tokenSerial, string tokenPin, string privateKeyLabel)
    {
        DllPath = dllPath;
        TokenSerial = tokenSerial;
        TokenPin = tokenPin;
        PrivateKeyLabel = privateKeyLabel;
    }

    public byte[] Sign(byte[] data)
    {
        using (var pkcs11 = new Pkcs11(DllPath, AppType.SingleThreaded))
        {

            var slots = pkcs11.GetSlotList(SlotsType.WithTokenPresent);
            var slot = slots.FirstOrDefault(slot1 => slot1.GetTokenInfo().SerialNumber == TokenSerial);
            if (slot == null)
                throw new Exception("there is no token with serial " + TokenSerial);
            using (var session = slot.OpenSession(SessionType.ReadOnly))
            {
                session.Login(CKU.CKU_USER, TokenPin);

                var searchTemplate = new List<ObjectAttribute>
                {
                    new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_PRIVATE_KEY),
                    new ObjectAttribute(CKA.CKA_KEY_TYPE, CKK.CKK_RSA)
                };
                if (!string.IsNullOrEmpty(PrivateKeyLabel))
                    searchTemplate.Add(new ObjectAttribute(CKA.CKA_LABEL, PrivateKeyLabel));

                var foundObjects = session.FindAllObjects(searchTemplate);
                var privateKey = foundObjects.FirstOrDefault();

                using (var mechanism = new Mechanism(CKM.CKM_RSA_PKCS))
                {
                    return session.Sign(mechanism, privateKey, data);
                }

            }

        }
    }

}

然后调用该方法对xml进行签名

public static void Sign(XmlDocument xmlDoc, ISignerProvider signerProvider)
    {
        if (xmlDoc == null)
            throw new ArgumentException("xmlDoc");
        if (xmlDoc.DocumentElement == null)
            throw new ArgumentException("xmlDoc.DocumentElement");
        var signedXml = new CustomSignedXml(xmlDoc);
        var reference = new Reference { Uri = "" };
        var env = new XmlDsigEnvelopedSignatureTransform();
        reference.AddTransform(env);
        signedXml.AddReference(reference);
        signedXml.ComputeSignature(signerProvider);
        var xmlDigitalSignature = signedXml.GetXml();
        xmlDoc.DocumentElement.AppendChild(xmlDoc.ImportNode(xmlDigitalSignature, true));
    }

和这个代码来验证

        public static bool Verify(XmlDocument document, X509Certificate2 certificate)
    {
        // Check arguments.
        if (document == null)
            throw new ArgumentException("Doc");
        if (certificate == null)
            throw new ArgumentException("Key");

        // Create a new SignedXml object and pass it
        // the XML document class.
        var signedXml = new SignedXml(document);

        // Find the "Signature" node and create a new
        // XmlNodeList object.
        var nodeList = document.GetElementsByTagName("Signature");

        // Throw an exception if no signature was found.
        if (nodeList.Count <= 0)
        {
            throw new CryptographicException("Verification failed: No Signature was found in the document.");
        }

        // This example only supports one signature for
        // the entire XML document.  Throw an exception 
        // if more than one signature was found.
        if (nodeList.Count >= 2)
        {
            throw new CryptographicException("Verification failed: More that one signature was found for the document.");
        }

        // Load the first <signature> node.  
        signedXml.LoadXml((XmlElement)nodeList[0]);

        return signedXml.CheckSignature(certificate, true);
    }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何将 HSM 中存储的私钥转换为 C# 中的 SignedXml.SigningKey 的相关文章

随机推荐

  • 如何将 Map 对象写入文件

    我想从 a 写入文件Map目的 这是我的尝试 try stuMap put student getId student Path file Paths get student txt to create the file Files wri
  • MASM x64 中的跳转表实现?

    我正在尝试使用跳转表在汇编 MASM64 Windows x64 中实现算法 基本思想是 我需要对数据执行 3 种不同类型的操作 这些操作取决于一些变量 但我发现实现大量切换和许多冗长的实现很乏味 PUBLIC superFunc 40 v
  • JTidy java API 将 HTML 转换为 XHTML

    我正在使用 JTidy 从 HTML 转换为 XHTML 但我在我的 XHTML 文件中发现了这个标签 nbsp 我可以阻止它吗 这是我的代码 from html to xhtml try fis new FileInputStream h
  • 如何将 DatagridView 保存在 Xml 中并将 Xml 加载到 datagridView?

    您好 我想将数据从 datagridview 保存并加载到 xml 我的想法是 我可以将我的 datagridview 保存到 xml 中 gt date name xml 然后我可以加载此数据 对于这两个操作我想使用两种方法 gt Sav
  • 如何以编程方式在 C++ 或 Python 中列出 DLL 的依赖项?

    我目前正在使用 Boost Python 为 C 项目编写 Python 接口 问题是 如果缺少 DLL Python 会给我们一条非常无用的错误消息 ImportError DLL 加载失败 找不到指定的模块 根据这个网站不可能显示比这更
  • Prestashop 1.6 获取模块类的实例

    我有一个被重写的类OrderConfirmationControllerCore 我有一个带有类的模块Abra 我需要获取一个实例Abra类在OrderConfirmationControllerCore 我的代码是 class Order
  • PostSharp 参数验证 - 使用 RegularExpressionAttribute 查找前导/尾随空格

    我正在使用 PostSharp 3 1 通过验证属性来验证属性的参数 我想用正则表达式属性执行验证 它接受表示正则表达式的字符串 如果字符串有任何前导或尾随空格 但字符串可能在单词之间包含空格 我想抛出异常 在使用 PostSharp 属性
  • 反序列化 JSON 子文档

    我正在调用 JIRA Rest API 来接收工作日志对象列表 我收到的 JSON 看起来像 startAt 0 maxResults 1 total 1 worklogs self http www example com jira re
  • 有没有办法使用 LINQ 表达式填充集合?

    LINQ 的优点之一是允许您获取与集合相关的信息 而无需手动编写代码来迭代集合 有没有办法使用 LINQ 填充集合 从而避免编写循环 例如 假设我有以下代码 它适用于从 1 到 10 的数字范围 public static void Lin
  • 在 WPF 应用程序中使用 .NET Standard 程序集中的内容文件

    我想将文件嵌入到 NET Standard 程序集中 并在 WPF 应用程序的 XAML 中使用它 如果您将构建操作设置为Resource在其他程序集中使用嵌入文件非常容易 但是您必须使用
  • 在 Angular (v5) 中,如何监听我的应用程序 Redux 状态对象的变化?

    我需要知道如何创建一个监听器 例如我想订阅 AppState 更改 以下是我目前非常基本的服务 我在视图上有一个调度操作 它会增加计数器 一旦计数器改变值 我想在我网站的其他部分检测到这一点 例如例如全局标头 我正在使用 ng2 Redux
  • 将光标设置到 CKEditor 中的特定位置

    有没有办法将光标位置设置为 CKEditor 内的已知索引 我想这样做是因为当我更改编辑器内的 html 时 它会将光标重置到插入元素的开头 这是一个问题 因为我在用户键入时动态更改内容 如果我知道我想将光标设置回编辑器内的已知字符位置 例
  • 尝试获取本周星期一的日期

    我已经实现了一种方法来获取本周星期一的日期 并且我已将星期一指定为本周的第一天 但是 无论我做什么 它都会返回 Sun Mar 24 15 03 07 GMT 2013 我看不出这里有什么问题 有人可以帮忙吗 public static D
  • 使用自定义顺序和包含逗号的值编写 Excel VBA 排序代码

    在 VBA 中 Excel 允许使用 CustomOrder 参数对值进行排序 以选择排序的序列项 不幸的是 项目序列是用逗号分隔的 并且我的排序项目之一包含逗号 例如 我想按第二列中的类别对第一列中的数据进行排序 空中 陆地或海上 类别包
  • Android - 将 URI 转换为棒棒糖上的文件路径

    我目前正在尝试制作一个音频媒体播放器 我目前正在运行棒棒糖 我在设置媒体播放器的数据源时遇到问题 首先 这是我设置数据源的方法 public void playSong player reset Song selSong songs get
  • 绘制调用在 Three.js 中如何工作?

    我有许多可能很长的折线 或很短 顶点数非常不稳定 要显示 所以我正在考虑将它们包装在一堆固定大小 假设有 10000 个顶点 的位置BufferAttribute并发送一份drawcall每条折线 如果多段线跨越 10000 限制边界 我可
  • 使用 Amazon Dynamodb 进行不区分大小写的查询

    在 DynamoDB 中 字符串值区分大小写 在我的应用程序中 用户可以在数据库中搜索配置文件名称 但是 如果他们搜索 alan 则搜索结果中不会返回 Alan 如何允许用户指定不区分大小写的搜索以检索良好的结果 仅供参考 我将 Dynam
  • 如何在 Ruby 中捕获终端箭头键?

    如何捕获终端中的箭头键 而用户不必在箭头键后按 Enter 键 查看 Ruby 控制台库红宝石特米奥斯 and ncurses 红宝石
  • 使用 C# 登录 Azure AD。获取刷新令牌和访问令牌

    Task 我需要创建一个 WPF 应用程序 它将与 EWS Exchange Web 服务 一起使用 我也有两个限制 登录只能进行一次 应该使用刷新令牌重新连接 它应该支持 2FA 我的解决方案部分 我使用 OAuth 连接到 Azure
  • 如何将 HSM 中存储的私钥转换为 C# 中的 SignedXml.SigningKey

    我正在尝试使用存储在 HSM 中的证书来实现一些 XML 签名演示 我从此链接中找到了一些有趣的示例 使用 X509Certificate2 签署 XML 文档并将其修改为使用带有 PKCS11Interop 包装器的 HSM 内的证书和密