3

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

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

我从“Signdata”方法得到响应,但是,在打开签名后生成的 Pdf 文件时,会出现错误“Signature Invalid”。这是 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?
  • 如果没有,那么有什么方法可以启用支持吗?
  • 如果它确实支持,请帮助我如何解决这个问题?
  • 看起来它希望我通过 ECDSA_Param,有没有人有任何代码片段来传递 ECDSA_Param
4

2 回答 2

2

我认为您需要构建结构并用变量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 章:

当使用带有 SignedData 的 ECDSA 时,ECDSA 签名使用以下类型进行编码:

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

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

以下方法使用BouncyCastle库构建 DER 编码ECDSA-Sig-Value结构:

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();
}
于 2017-05-17T07:20:19.750 回答
0

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

   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();
    }
于 2017-05-19T14:01:07.627 回答