2016-12-02 25 views
0

私は "SHA512withRSA"署名、署名されたデータ、および公開鍵(base64形式)を持ち、サードパーティから私に送られました。公開鍵を使用して、指定されたデータが正しいことを確認する必要があります。SHA512withRSA .Netの署名検証

基本的な質問は、これを.NETで確認するにはどうすればよいですか(C#コードが好ましい)?

.Netフレームワークのみで可能ですか(RSACryptoServiceProviderは関連クラスですが、SHA1は署名アルゴリズムとしてのみサポートされているようです)。

もしそうでない場合は、これを達成するためにどのライブラリを使用できますか?私はBouncyCastleを試してきましたが、これを明確にする方法を説明するドキュメントは見つかりません。ほとんどすべてのドキュメントは証明書を扱うことに関するものであり、私は証明書を持っておらず、必要もしません。

編集:新しいサンプルコード(まだ失敗)

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
using System.IO; 
using System.Linq; 
using System.Security.Cryptography; 
using System.Text; 
using System.Threading.Tasks; 

namespace SignatureVerificationTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      var t = DoWorkAsync(); 
      Console.ReadLine(); 
     } 

     public static async Task DoWorkAsync() 
     { 
      var rawNotificationData = "merchantOrderId=e7ea4e4c-7ffa-4b19-8af9-ad875c493620&status=AUTHORISED&signature=hgvtCb6RjmhtumXTNuARW8fotZVoIJ%2FAaqXEow1pxA0Ic5afe0j2lGHO%2F6Q7rnPXqd728mMsmkjQSyxGDho7imxYGHEyEudt%2B%2FThOboAj%2FhePNLNfCeJR7DS7LIzO7SCTDkkTHZ%2F5sD5JhBATY3EFADrLnzzlF445mNRP%2Bv2vi3ogVC5k3oYfPCSmvOzd8DFUp6E6cwZelBGQjRHwVJf07%2B8x4esYxW%2FJii3z6quXzaKpImLFt3jaDTe109uwTwsv8bRBh%2F%2FSjFlHPaEr5QTAjTDA0IrMP6OggGTDkukW8sr7PUmQoq%2B4%2FLEIlHqXbuwZgJ2zr7fN75CcwWaj6FHfdiVvmeKGshO11DnHX7rN%2FTU36z7D7jRp%2Fykd4q409MorZUfZspHuXp2XRXo1732OZKRdYkX73eDphFKQUbmhGCf9wQq3xxxlw6Qr3ClTAi8SbOeY8IQIul%2Bp3x0X5G%2FiJmtiMcHMErxxCx2Y84OozrbvMEQP8qzY4FLUuV%2BKv9oragcXfDvpkJ4EAAqZPufXGZ3zCyk5yBJEXy6kqZ7ht16bpuD0aQMBlq2eTyQCOgtRvOPCFJYwCVJ8z43xQShffKa9Tj7gSgPE9LfvD3%2Ba4NdEh0Hg5yV7A7wABLySC%2F3thXvxVfVthNJEfdHZPhpAN2i3C5sql09R27k5SEV96c%3D"; 

      //Find the signature in the data, and url decode the value 
      var x = rawNotificationData.Split(new char[] { '&' }); 

      string notificationSignature = null; 
      foreach (var kvp in x) 
      { 
       var parts = kvp.Split(new char[] { '=' }); 
       if (parts[0] == "signature") 
       { 
        notificationSignature = Uri.UnescapeDataString(parts[1]); 
        break; 
       } 
      } 

      // Get the portion of the string that was signed 
      // Should be; 
      // merchantOrderId=e7ea4e4c-7ffa-4b19-8af9-ad875c493620&status=AUTHORISED 
      var signedData = rawNotificationData.Substring(0, rawNotificationData.IndexOf("&signature=", StringComparison.OrdinalIgnoreCase)); 


      //Define the public key (base 64 encoded string) 
      var publicKey = @"MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAv3kDhkB2yHn/4N1KtNsm 
8IuWuqfnOIDxOnR2txELEtKL1YqSTiAtoBHWfvGg2OMN1gu0/owecT7d9+TnXx7M 
NE4CGp3UOLkdTzRifDMrMh5T9WVvyKfV4Chnv/tkmK7BMSe+yS4T+3IQVBv0zFKu 
Hm9Y8Zicc5sIkTRdpgeg1wbYZkbKA5qZcYkKUKpWHKmWVMyIqqhwAcKFA9dc0j8f 
h6EM3JWQhFOFkXngUHX4O+L2mJ7rnYsMZzujoK3fNk/HIHYtJiZbkbEOzlDGhzp0 
ZackirqZ2iqPRSgZsVcyqTthNiYxjkOvB5AYb/Ww+3T/UQ2zaB0ac7dgLKrq8BL5 
HpVke93F4kQQ6M1BmIWfLiQt3FLRX+LxkcNC5q1SaPW8D/7lnYACM0JErrpA8/Dc 
7U7Th6R8Wk99V8O0FN6+t9gr3lwG99Hw7AykstlPWMdFDch+ljM4JGf/hvxcZDlp 
ACSRPf1BXNON1E6WMofyAXNSsuQ3kG/go0f5pzix+K/484y4PPKizbWTGWElK9sJ 
d2jDFEGG5iCoFzJNLvEvuvzHHhP+cM5y7LTX7D0B8LPdj1kIEboTAIfdhQ1IVVYa 
mSo7WTB/sHgxGk9+8K3EboGAzSmgIqlLrMZob1h8/32LsVSxKhgxs01tGotB7rJO 
MmwP7rPHQjvq0NoPMTFPd+ECAwEAAQ=="; 

      // Decode the base64 key into raw bytes 
      // (Decodes to 550 bytes) 
      var rawKey = Convert.FromBase64String(publicKey); 

      //Create an RSA crypto provider instance initialised with the key 
      //Decodes to a 512 byte modulus and 3 (1, 0, 1) byte exponent 
      using (var rsa = CreateRsa(rawKey)) 
      { 
       bool signatureVerified = rsa.VerifyData 
       (
        System.Text.UTF8Encoding.UTF8.GetBytes(signedData), 
        CryptoConfig.MapNameToOID("SHA512"), 
        Convert.FromBase64String(notificationSignature) 
       ); 

       //Fail if the signature didn't verify 
       Debug.Assert(signatureVerified, "Signature did not verify."); 
      } 
     } 

     private static readonly byte[] SeqOID = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x05, 0x00 }; 

     private static RSACryptoServiceProvider CreateRsa(byte[] publicKey) 
     { 
      /* 

      This code parses the publickey bytes to extract the relevant bits of the public key, the initialises 
      the rsa crypto provider with the key. 
      Taken from "CreateRsa" below is modified from http://www.jensign.com/JavaScience/dotnet/pempublic/ 

      Original license below applies. 

      Copyright(c) 2006 - 2014 JavaScience Consulting, Michel Gallant 

      Permission is hereby granted, free of charge, to any person obtaining a copy 
      of this software and associated documentation files(the "Software"), to deal 
      in the Software without restriction, including without limitation the rights 
      to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
      copies of the Software, and to permit persons to whom the Software is 
      furnished to do so, subject to the following conditions: 

      The above copyright notice and this permission notice shall be included in 
      all copies or substantial portions of the Software. 

      THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
      IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
      FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE 
      AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
      LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
      OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 
      THE SOFTWARE. 
      */ 

      var mem = new System.IO.MemoryStream(publicKey); 
      BinaryReader binr = new BinaryReader(mem); //wrap Memory Stream with BinaryReader for easy reading 
      byte bt = 0; 
      ushort twobytes = 0; 

      twobytes = binr.ReadUInt16(); 
      if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81) 
       binr.ReadByte(); //advance 1 byte 
      else if (twobytes == 0x8230) 
       binr.ReadInt16(); //advance 2 bytes 
      else 
       return null; 

      var seq = binr.ReadBytes(15); //read the Sequence OID 
      if (!CompareBytearrays(seq, SeqOID)) //make sure Sequence for OID is correct 
       return null; 

      twobytes = binr.ReadUInt16(); 
      if (twobytes == 0x8103) //data read as little endian order (actual data order for Bit String is 03 81) 
       binr.ReadByte(); //advance 1 byte 
      else if (twobytes == 0x8203) 
       binr.ReadInt16(); //advance 2 bytes 
      else 
       return null; 

      bt = binr.ReadByte(); 
      if (bt != 0x00) //expect null byte next 
       return null; 

      twobytes = binr.ReadUInt16(); 
      if (twobytes == 0x8130) //data read as little endian order (actual data order for Sequence is 30 81) 
       binr.ReadByte(); //advance 1 byte 
      else if (twobytes == 0x8230) 
       binr.ReadInt16(); //advance 2 bytes 
      else 
       return null; 

      twobytes = binr.ReadUInt16(); 
      byte lowbyte = 0x00; 
      byte highbyte = 0x00; 

      if (twobytes == 0x8102) //data read as little endian order (actual data order for Integer is 02 81) 
       lowbyte = binr.ReadByte(); // read next bytes which is bytes in modulus 
      else if (twobytes == 0x8202) 
      { 
       highbyte = binr.ReadByte(); //advance 2 bytes 
       lowbyte = binr.ReadByte(); 
      } 
      else 
       return null; 
      byte[] modint = { lowbyte, highbyte, 0x00, 0x00 }; //reverse byte order since asn.1 key uses big endian order 
      int modsize = BitConverter.ToInt32(modint, 0); 

      int firstbyte = binr.PeekChar(); 
      if (firstbyte == 0x00) 
      { //if first byte (highest order) of modulus is zero, don't include it 
       binr.ReadByte(); //skip this null byte 
       modsize -= 1; //reduce modulus buffer size by 1 
      } 

      byte[] modulus = binr.ReadBytes(modsize); //read the modulus bytes 

      if (binr.ReadByte() != 0x02)  //expect an Integer for the exponent data 
       return null; 
      int expbytes = (int)binr.ReadByte(); // should only need one byte for actual exponent data (for all useful values) 
      byte[] exponent = binr.ReadBytes(expbytes); 

      // ------- create RSACryptoServiceProvider instance and initialize with public key ----- 
      RSACryptoServiceProvider RSA = new RSACryptoServiceProvider(); 
      RSAParameters RSAKeyInfo = new RSAParameters(); 
      RSAKeyInfo.Modulus = modulus; 
      RSAKeyInfo.Exponent = exponent; 
      RSA.ImportParameters(RSAKeyInfo); 
      RSA.PersistKeyInCsp = false; 
      return RSA; 
     } 

     private static bool CompareBytearrays(byte[] a, byte[] b) 
     { 
      if (a.Length != b.Length) 
       return false; 
      int i = 0; 
      foreach (byte c in a) 
      { 
       if (c != b[i]) 
        return false; 
       i++; 
      } 
      return true; 
     } 

    } 
} 
+0

ここでもコードを試しました。 http://stackoverflow.com/questions/8437288/signing-and-verifying-signatures-with-rsa-c-sharp - それ自体で作成された署名は検証されますが、私が与えられた署名は検証されません。与えられた)。 RSA.SigningAlgorithmプロパティはまだSHA1と言いますが、それが重要かどうかわかりません。 – Yort

+0

コードが正常に動作していて、公開鍵だけが間違っていた場合は、コードからエラーが明らかではないため、質問を閉じる必要があります。 –

答えて

1

RSACryptoServiceProviderがそれを行うことができますが、あなたの代わりにPROV_RSA_FULL(1)のPROV_RSA_AES(24)に格納されたキーを、持っていることを条件とします。

new RSACryptoServiceProvider()はすでにPROV_RSA_AESを作るする必要があるので、あなたにもCspParameters入力を指定(して明示的にdwProvType値を変更する)場合、私はそれがキーをインポートするための間違ったことを期待したい唯一の方法です。

既存RSACryptoServiceProviderオブジェクトを持っている場合は、SHA-のためにはるかに安定した支持を持っている

CspParameters keyParams = new CspParameters(); 
CspKeyContainerInfo keyInfo = currentKey.CspKeyContainerInfo; 
keyParams.KeyContainerName = keyInfo.KeyContainerName; 
keyParams.ProviderType = 24 /*PROV_RSA_AES*/; 
keyParams.KeyNumber = (int)keyInfo.KeyNumber; 
keyParams.Flags = CspProviderFlags.UseExistingKey; 

if (keyInfo.MachineKeyStore) 
    keyParams.Flags |= CspProviderFlags.UseMachineKeyStore; 

return new RSACryptoServiceProvider(keyParams); 

それとも、あなたは.NET 4.6+にしている場合は、RSACngに切り替えると新しいものを、開くことができます2つの署名。

+0

助けてくれてありがとうございます。しかし、私が試してみると、「キーは存在しません」というエラーメッセージが表示され、CryptographicExceptionが表示されます。質問を編集してサンプルコードを追加し、誰かが私の愚かさに気づくかどうかを見てみましょう。私は暗号のnoobだから、おそらく私がやっている何かばかなことだ。ありがとう。 – Yort

0

私は間違った公開鍵が与えられたと思われる情報を第三者に提示した後、正しい公開鍵に切り替えると、検証が成功するようになりました。

関連する問題