当前位置: 首页 > 知识库问答 >
问题:

使用SoftHSM 2.2从Pkcs11Interop为CKM_ECDSA_SHA256签署PDF。0(带SHA256的ECDSA)C#。网

尹昂雄
2023-03-14

我正在尝试使用Pkcs11Interop签署Pdf文档。net库。我需要使用ECDSA加密算法和SHA256哈希算法。我使用的是SoftHSM 2.2。0用于存储私钥。

我找到了一个CKM枚举,CKM_ECDSA_SHA256,我在创建一个类对象机制以调用会话的Sign方法时传递了它。

我得到的响应从"Signdata"方法,但是,打开后生成的Pdf文件签名给一个错误"签名无效"。下面是Signdata方法调用的代码片段。我在代码中没有任何错误或异常,但是,我提到的pdf显示签名无效。

private Pkcs11 _pkcs11;
private Slot _slot;
private Session _session;

try
{
   _pkcs11 = new Pkcs11(hsmCryptoApi, true);
}
catch (Pkcs11Exception ex)
{
   if (ex.RV == CKR.CKR_CANT_LOCK)
      _pkcs11 = new Pkcs11(hsmCryptoApi, false);
   else
       throw ex;
}

_slot = FindSlot(_pkcs11, _certificateInformation.TokenLabel);
_session = _slot.OpenSession(true);

using (Mechanism mechanism = new Mechanism(CKM.CKM_ECDSA_SHA256))
{
  _session.Login(CKU.CKU_USER, passowrd);
  byte[] signedHash = _session.Sign(mechanism, GetPrivateKeyHandle(), message);
  _session.Logout();
  return signedHash;
}

private ObjectHandle GetPrivateKeyHandle()
{
  string keyLabel = _certificateInformation.KeyLabel;
  List<ObjectAttribute> searchTemplate = new List<ObjectAttribute>();
  searchTemplate.Add(new ObjectAttribute(CKA.CKA_CLASS, CKO.CKO_PRIVATE_KEY));
  searchTemplate.Add(new ObjectAttribute(CKA.CKA_LABEL, keyLabel));
  List<ObjectHandle> foundObjects = _session.FindAllObjects(searchTemplate);
  return foundObjects[0]; 
}
  • 请告诉我是否使用SoftHSM 2.2。0是否支持带有SHA256的ECDSA_P256

共有2个答案

田兴旺
2023-03-14

只是想分享对我有用的解决方案。在上述代码片段中,我添加了以下内容:

   using (Mechanism mechanism = new Mechanism(CKM.CKM_ECDSA))
        {
          _session.Login(CKU.CKU_USER, passowrd);
          byte[] signedHash = _session.Sign(mechanism, GetPrivateKeyHandle(), GetMessageDigest(message));
          _session.Logout();
          return ConstructEcdsaSigValue(signedHash);
        }

    private byte[] GetMessageDigest(byte[] message)
    {
       using (Mechanism mechanism = new Mechanism(CKM_SHA256))
       {
         return _session.Digest(mechanism, message);
        }
    }

    public static byte[] ConstructEcdsaSigValue(byte[] rs)
    {
        if (rs == null)
            throw new ArgumentNullException(nameof(rs));

        if (rs.Length < 2 || rs.Length % 2 != 0)
            throw new ArgumentException("Invalid length", nameof(rs));

        int halfLen = rs.Length / 2;

        byte[] half1 = new byte[halfLen];
        Array.Copy(rs, 0, half1, 0, halfLen);
        var r = new Org.BouncyCastle.Math.BigInteger(1, half1);

        byte[] half2 = new byte[halfLen];
        Array.Copy(rs, halfLen, half2, 0, halfLen);
        var s = new Org.BouncyCastle.Math.BigInteger(1, half2);

        var derSequence = new Org.BouncyCastle.Asn1.DerSequence(
            new Org.BouncyCastle.Asn1.DerInteger(r),
            new Org.BouncyCastle.Asn1.DerInteger(s));

        return derSequence.GetDerEncoded();
    }
夏学名
2023-03-14

我认为您需要构造ECDSA Sig Value结构,并用signedHash变量中的数据填充它。

PKCS#11 v2.20第12.3.1章:

对于这些机制,ECDSA签名是偶数长度的八位字节串,其长度最多为nLen八位字节的两倍,其中nLen是基点阶n的八位字节长度。签名八位字节对应于ECDSA值r和s的级联,两者都表示为一个八位字节字符串,长度最多为nLen,最高有效字节在先。如果r和s有不同的八位字节长度,两者中较短的必须用前导零八位字节填充,以使两者具有相同的八位字节长度。松散地说,签名的前半部分是r,后半部分是s。对于令牌创建的签名,生成的签名总是长度为2nLen。对于传递给令牌进行验证的签名,签名可以具有较短的长度,但必须按照之前指定的方式组成。

RFC5753第7.2章:

将ECDSA与SignedData一起使用时,ECDSA签名使用以下类型进行编码:

ECDSA-Sig-Value ::= SEQUENCE {
    r INTEGER,
    s INTEGER }

ECDSA-Sig-Value在[PKI-ALG]中指定。在CMS中,ECDSA-Sig-Value是DER编码的,并放置在SignedData的签名字段中。

以下方法使用BouncyCastle库构造DER编码的ECDSA Sig值结构:

html" target="_blank">public static byte[] ConstructEcdsaSigValue(byte[] rs)
{
    if (rs == null)
        throw new ArgumentNullException(nameof(rs));

    if (rs.Length < 2 || rs.Length % 2 != 0)
        throw new ArgumentException("Invalid length", nameof(rs));

    int halfLen = rs.Length / 2;

    byte[] half1 = new byte[halfLen];
    Array.Copy(rs, 0, half1, 0, halfLen);
    var r = new Org.BouncyCastle.Math.BigInteger(1, half1);

    byte[] half2 = new byte[halfLen];
    Array.Copy(rs, halfLen, half2, 0, halfLen);
    var s = new Org.BouncyCastle.Math.BigInteger(1, half2);

    var derSequence = new Org.BouncyCastle.Asn1.DerSequence(
        new Org.BouncyCastle.Asn1.DerInteger(r),
        new Org.BouncyCastle.Asn1.DerInteger(s));

    return derSequence.GetDerEncoded();
}
 类似资料:
  • 我正在尝试使用C#和内置的加密库来验证使用EC密钥SHA256创建的签名。 我使用openssl创建了一个私钥和相应的证书: 以下是我正在使用的密钥(别担心,它们并不重要): 然后,我有一个包含字符串“Hello”的简单数据文件。然后,我使用openssl对该文件进行签名,如下所示: 然后,我可以通过首先从证书中提取公钥,然后使用公钥来验证签名: 然后,我尝试使用 C#(.NET Core 3.1

  • 下面是我的场景--我从条形码中读取数据,并将其转换为纯文本。本文是条码数据+数字签名的结合。数字签名附加在末尾,使我能够分离出实际数据和数字签名数据。数字签名数据使用sha256哈希-用户将公钥作为windows证书文件()发送给我。 所需实现:-需要从证书中提取公钥,并根据提供的条形码数据和数字签名验证公钥。 问题:

  • 我有一个包含EC私钥的文件: 我有一个证书,它的公钥对应于私钥: 在 pem 格式中: 以txt格式: 我正在努力完成两件事: < li >使用ecdsa-with-SHA256签名算法使用私钥对字节数组进行签名 < li >使用证书中的公钥验证签名是否正确 我尝试过使用充气城堡图书馆。这是我到目前为止所拥有的。我的断言是失败的。

  • 我有一个私人钥匙在档案里。“privatekey.pem”并且不知道如何创建谁能帮助我吗?我正在尝试使用IText7签名pdf。

  • 也就是说,我需要创建一个可以通过WCF JSON调用公钥的客户机,以便稍后用于签名验证,但我似乎无法使其工作。首先,这里是我用来生成证书的代码: 完成后,我使用以下代码对消息进行签名: 最后,我试图验证:

  • 但是,为了签署请求,openSSL提供了两个工具:ca和X509。然而,这些都不允许使用SHA256。根据官方文档,ca只支持md5、sha1和MDC2。x509仅支持md2、md5、sha1、MDC2。 谢谢你。