0

我想在二進制數據上使用RSA簽名和驗證,但它只是不工作,無論如何,RSA.VerifyData總是返回false。無法讓我的RSA簽名/驗證BINARY數據正常工作。任何工作示例?

基本上我有一個對象,它是二進制序列化:

public class MyObject { 
    public OtherClass Property1 { get; set; } 

    public Trailer Trailer { get; set; } 
} 

public class Trailer { 
    public byte[] Hash {get;set; } // Any hash 
    public byte[] Signature {get;set; } 
} 

基本上對象都有自己的屬性設置,這裏只是一個(Property1)。然後我計算沒有預告片的對象上的散列,並將其放在Trailer.Hash上。然後我通過Property1,Trailer.Hash和Trailer.Signature = null計算RSA簽名。我正在用DataContractSerializer進行二進制序列化。

問題是,當我檢索哈希是好的,它也很好地重新生成(加載時重新計算),但簽名驗證失敗。嘗試了很多方法,但似乎沒有任何工作。

任何人都可以指出我想做什麼的工作例子嗎?我可以簽署一個字符串並驗證它,但使用二進制數據我無法使它工作。如需更詳細的代碼在Github上查看我的Gist/

public void Save(SampleObject model, byte[] cspBlob, string outFilename) 
{ 
    // Calculate the HMACSHA256 over a model with null Trailer section 
    CheckTrailer check = new CheckTrailer(); // empty keyed hash and empty signature 
    model.Check = null; // both HMAC & Signature are irrelevant for Save because we calculate them here 
    check.Trailer1 = model.GetKeyedHash<HMACSHA256>(GetKey()); 

    DataContractSerializer serializer = new DataContractSerializer(model.GetType()); 
    using (MemoryStream memoryStream = new MemoryStream()) 
    { 
     model.Check = check; 
     // serialize with keyed hash and empty signature 
     serializer.WriteObject(memoryStream, model); 

     CspParameters cspparams = new CspParameters { Flags = CspProviderFlags.CreateEphemeralKey }; 
     using (RSACryptoServiceProvider rsaSign = new RSACryptoServiceProvider(cspparams)) 
     { 
      rsaSign.ImportCspBlob(cspBlob);  // must be a key pair blob 
      if (rsaSign.PublicOnly) 
      { 
       throw new CryptographicException("Cannot sign with PUK"); 
      } 

      check.Trailer2 = rsaSign.SignData(memoryStream, HashAlgorithm.Create(DSIG_HASH)); 
      Console.WriteLine("\tDSIG: {0}", BitConverter.ToString(check.Trailer2)); 
     } 
    } 

    // Place the computed signature 
    model.Check.Trailer2 = check.Trailer2; 

    // serialize 
    IFormatter formatter = new BinaryFormatter(); 
    using (Stream stream = new FileStream(outFilename, FileMode.Create, FileAccess.Write, FileShare.None)) 
    { 
     formatter.Serialize(stream, model); 
    } 
} // Save() 

回答

0

任何人都可以點我的東西我想要做一個工作的例子嗎?我可以簽署一個字符串並驗證它,但使用二進制數據我無法使它工作。

RSA只是定義在二進制數據上,所以問題在於你沒有生成相同的二進制數據來簽名和驗證。

根據您的Save方法,問題在於您正在對空流進行簽名,但驗證了非空流。

// New stream. Position=0, Length=0 
using (MemoryStream memoryStream = new MemoryStream()) 
{ 
    // Write some data. After this, Position=X, Length=X 
    serializer.WriteObject(memoryStream, model); 

    ... 

    // RSA.SignData will read from Position until Length in the stream. 
    // Since Position=Length already, this means it's the same as calling 
    // SignData(Array.Empty<byte>) 
    check.Trailer2 = rsaSign.SignData(memoryStream, HashAlgorithm.Create(DSIG_HASH)); 

你需要調用SignData之前內存流的位置重置爲0:

memoryStream.Position = 0; 
check.Trailer2 = rsaSign.SignData(memoryStream, ...) 
+0

太感謝了。我怎麼會忘了這樣一個基本的錯誤!太感謝了! –