簡體   English   中英

使用SoftHSM 2.2.0(帶有SHA256的ECDSA)C#.net從Pkcs11Interop為CKM_ECDSA_SHA256簽名PDF

[英]Signing PDF from Pkcs11Interop for CKM_ECDSA_SHA256 using SoftHSM 2.2.0 (ECDSA with SHA256) C# .net

我正在嘗試使用Pkcs11Interop .net庫來簽署Pdf文檔。 我需要使用帶有SHA256哈希算法的 ECDSA加密 算法 我使用SoftHSM 2.2.0存儲私鑰。

我找到了一個CKM枚舉, CKM_ECDSA_SHA256 ,我正在創建一個用於調用Session的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?
  • 如果沒有,那么有沒有辦法啟用支持?
  • 如果有支持,請幫我解決這個問題?
  • 看起來它想要我傳遞ECDSA_Param,是否有任何人有傳遞ECDSA_Param的代碼片段

我認為您需要構建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();
}

想到分享對我有用的解決方案。 在上面提到的代碼片段中,我添加了以下內容:

   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();
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM