2016-08-08 17 views
2

を検証し、私は(ダイジェスト/ハッシュがSHA1である)以下で渡しています:OpenSSLがECDSA署名C++を確認できない、C#が正しく

hash = HexToBytes("9E712647173B435CF691537A76C2F1423E4A18ED"); 
signature = Base64ToBytes("ASLQ3wguSDkJCfFWE3kvBfp7BDNjdajl2ezIetR6DsiacFVASvEAw9v6S3IM0LnaqAV2BTe7eBcRmef/qb2/Hw=="); 
pubKey16 = "04C2D0A868C35F475208B6C33A58D4AC275190F1A9D5804456FF07C42605716EF748FB4FD246163E851DBE9A942569741F54341A7C85F394B20777AB7FE526096A";//Actual key lacks 04 at front but I'm guessing OpenSSL needs this? 

この関数に:

int Misc::verify_signature(unsigned char* hash, std::vector<unsigned char> signature, char* cPubKey16) { 

     printf("Signature length: %d\n", signature.size()); 

     int function_status = -1; 

     EC_KEY *eckey = NULL; 
     EC_POINT *pub_key; 
     const EC_GROUP *ecgroup; 

     SSL_library_init(); 
     SSL_load_error_strings(); 

     std::string pubKeyS(cPubKey16); 

     std::vector<unsigned char> pubKeyVC = Misc::hexToBytes(pubKeyS); 

     const unsigned char* pubKeyVCp = pubKeyVC.data(); 

     const unsigned char** pubKeyVCpp = &pubKeyVCp; 

     //NID_secp256k1 is not r1 which is what .NET uses 
     eckey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); 

     //Load our public key 
     eckey = o2i_ECPublicKey(&eckey, pubKeyVCpp, pubKeyVC.size()); 

     if (!EC_KEY_check_key(eckey)) { 
      printf("EC_KEY_check_key failed:\n"); 
      printf("%s\n", ERR_error_string(ERR_get_error(), NULL)); 
     } 
     else { 
      printf("Public key verified OK\n"); 
     } 

     //Create the properly formatted signature 
     ECDSA_SIG* ec_sig = ECDSA_SIG_new(); 

     //Split signature into R and S value 

     //Set R 
     if (NULL == BN_bin2bn(&signature[0], 32, (ec_sig->r))) { 
      printf("Failed to set R value in EC Signature\n"); 
      function_status = -1; 
     } 
     printf("post r :%s\n", BN_bn2hex(ec_sig->r)); 

     //Set S 
     if (NULL == BN_bin2bn(&signature[0] + 32, 32, (ec_sig->s))) { 
      printf("Failed to set S value in EC Signature\n"); 
      function_status = -1; 
     } 
     printf("post s :%s\n", BN_bn2hex(ec_sig->s)); 

     //Encode the signature 
     int sig_size = i2d_ECDSA_SIG(ec_sig, NULL); 
     unsigned char *sig_bytes =(unsigned char *) malloc(sig_size); 
     unsigned char *p; 

     printf("Orig Sig Size: %d\n", sig_size); 

     p = sig_bytes; 
     int new_sig_size = i2d_ECDSA_SIG(ec_sig, &p); 

     printf("New Sig Size: %d\n", new_sig_size); 

     int verify_status = ECDSA_do_verify(hash, 20, ec_sig, eckey); 

     printf("Verify status: %d\n", verify_status); 

     const int verify_success = 1; 
     if (verify_success != verify_status) 
     { 
      if(verify_status==-1)handleErrors(); 
      printf("Failed to verify EC Signature\n"); 
      function_status = -1; 
     } 
     else 
     { 
      printf("Verifed EC Signature\n"); 
      function_status = 1; 
     } 

     //EC_GROUP_free(ecgroup);//Might fail as Ecgroup is constant TODO 
     EC_KEY_free(eckey); 

     return function_status; 
    } 

しかし、私は確認できませんまったく同じデータがC#で正常に検証されたとしても、OpenSSLの署名(verify_successは0)です。

私が間違っている理由や考え方についてのアイデアはありますか?

C#での公開鍵は、次のとおりです。

4543533120000000C2D0A868C35F475208B6C33A58D4AC275190F1A9D5804456FF07C42605716EF748FB4FD246163E851DBE9A942569741F54341A7C85F394B20777AB7FE526096A 

私は45435331.2億はので、私はちょうどそれの残りの部分に04を事前保留.NET固有のものであることを仮定しています。

 HashAlgorithm hashMan2 = new SHA1Managed(); 

     byte[] dataBytes = hashMan2.ComputeHash(Encoding.ASCII.GetBytes("H4sIAAAAAAAEADPQMQBCQzBJDsSm0xCMDTFUYYpQAjFNAIsAAOvFhT3RAAAA")); 

     String sig = "ASLQ3wguSDkJCfFWE3kvBfp7BDNjdajl2ezIetR6DsiacFVASvEAw9v6S3IM0LnaqAV2BTe7eBcRmef/qb2/Hw=="; 

     byte[] readPublicKey2 = Convert.FromBase64String("RUNTMSAAAADC0Khow19HUgi2wzpY1KwnUZDxqdWARFb/B8QmBXFu90j7T9JGFj6FHb6alCVpdB9UNBp8hfOUsgd3q3/lJglq"); 

     Console.WriteLine("Public key file is read as:"); 
     Console.WriteLine(Convert.ToBase64String(readPublicKey2)); 

     using (ECDsaCng ecsdKey = new ECDsaCng(CngKey.Import(readPublicKey2, CngKeyBlobFormat.EccPublicBlob))) 
     { 
      if (ecsdKey.VerifyData(dataBytes, Convert.FromBase64String(sig))) 
      { 
       Console.WriteLine("Data and Signature have been verified."); 
      } 
      else 
      { 
       Console.WriteLine("Data and Signature could not be verified!"); 
      } 
     } 

..(データバイトのSHA1は、両方のプログラムで同一である)を理解すべてのヘルプここ

は、署名を検証するために使用されるC#コードであり、それはとても成功し。

+0

リリースノートを確認してください。 –

+0

私は、ECDSA_SIG、https://www.openssl.org/news/changelog.htmlとの間で変換を必要としない新しいメソッドハンドラのいずれかを見つけることができませんでした。 – Akumaburn

+0

座標X、Y、R、Sのキーとシグネチャの整数値*(可能性もありますが、3つの可能性もあります)。 C#はリトルエンディアンエンコーディングを非常に頻繁に使用します。 –

答えて

1

私は.NET関数ECDSA.SignDataを使用していましたが、実際に入力する前に(ECDsaCng.HashAlgorithmを使用して)データをハッシュしましたが、入力としてハッシュを取っていると仮定していましたが、関数はECDSA.SignHashです。SignHashに切り替えました。新しい署名/メッセージが正しく検証されます。 (あなたの.NETのバージョンによってこれは異なる場合がありますので、必ずあなたのバージョンのAPIをチェックしてください)

もし誰かを助けてくれる場合は、私の下書き機能があります/あなたに役立つかもしれない/不要なもの):

int Misc::verify_signature(std::vector<unsigned char> hash, std::vector<unsigned char> signature, char* cPubKey16) { 

     printf("Signature length: %d\n", signature.size()); 

     int function_status = -1; 

     EC_KEY *eckey = NULL; 
     EC_POINT *pub_key; 
     const EC_GROUP *ecgroup; 

     SSL_library_init(); 
     SSL_load_error_strings(); 

     std::string pubKeyS(cPubKey16); 

     std::vector<unsigned char> pubKeyVC = Misc::hexToBytes(pubKeyS); 

     printf("Raw PubKey Bytes: \n"); 
     for (unsigned char t : pubKeyVC) { 
      printf("%d\n", t); 
     } 
     printf("Raw PubKey Length:%d \n", pubKeyVC.size()); 

     const unsigned char* pubKeyVCp = pubKeyVC.data(); 

     const unsigned char** pubKeyVCpp = &pubKeyVCp; 

     //NID_secp256k1 is not r1 which is what .NET uses 
     eckey = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); 

     EC_KEY_set_asn1_flag(eckey, OPENSSL_EC_NAMED_CURVE); 

     eckey = o2i_ECPublicKey(&eckey, pubKeyVCpp, pubKeyVC.size()); 

     if (!EC_KEY_check_key(eckey)) { 
      printf("EC_KEY_check_key failed:\n"); 
      printf("%s\n", ERR_error_string(ERR_get_error(), NULL)); 
     } 
     else { 
      printf("Public key verified OK\n"); 
     } 

     //Create the properly formatted signature 
     ECDSA_SIG* ec_sig = ECDSA_SIG_new(); 

     //Split signature into R and S value 

     //Set R 
     if (NULL == BN_bin2bn(&signature[0], 32, (ec_sig->r))) { 
      printf("Failed to set R value in EC Signature\n"); 
      function_status = -1; 
     } 
     printf("post r :%s\n", BN_bn2hex(ec_sig->r)); 

     ////Try to pad S 
     //std::vector<unsigned char> sPadded = std::vector<unsigned char>(&signature[32], &signature[32] + 32); 

     //sPadded.insert(sPadded.begin(), '0'); 
     //sPadded.insert(sPadded.begin(), '0'); 

     //Set S 
     if (NULL == BN_bin2bn(&signature[32], 32, (ec_sig->s))) { 
      printf("Failed to set S value in EC Signature\n"); 
      function_status = -1; 
     } 
     printf("post s :%s\n", BN_bn2hex(ec_sig->s)); 



     //Encode the signature 
     std::vector<unsigned char> rValue = std::vector<unsigned char>(&signature[0], &signature[0] + 32); 
     std::vector<unsigned char> sValue = std::vector<unsigned char>(&signature[32], &signature[32] + 32); 

     std::vector<unsigned char> derEncoded = std::vector<unsigned char>(); 

     derEncoded.push_back(0x30); 
     //Push payload length into this position later 

     //Seperator 
     derEncoded.push_back(0x02); 

     //Length of rValue 
     if (rValue.at(0) >= 0x80) { 
      derEncoded.push_back(rValue.size() + 1); 
     } 
     else { 
      derEncoded.push_back(rValue.size()); 
     } 

     //Push rValue bytes in 
     int c = 0; 
     for (unsigned char b : rValue) { 
      if (b >= 0x80 && c == 0) { 
       derEncoded.push_back(0); 
      } 
      derEncoded.push_back(b); 
      c++; 
     } 

     //Seperator 
     derEncoded.push_back(0x02); 
     //Length of sValue 
     if (sValue.at(0) >= 0x80) { 
      derEncoded.push_back(sValue.size() + 1); 
     } 
     else { 
      derEncoded.push_back(sValue.size()); 
     } 

     //Push sValue bytes in 
     c = 0; 
     for (unsigned char b : sValue) { 
      if (b >= 0x80 && c == 0) { 
       derEncoded.push_back(0); 
      } 
      derEncoded.push_back(b); 
      c++; 
     } 

     //Insert payload length in 

     int len = derEncoded.size() - 1; 

     derEncoded.insert(derEncoded.begin() + 1, len); 

     printf("Encoded Sig Len: %d\n", derEncoded.size()); 

     printf("Encoded Sig64: %s\n", Misc::base64_encode_d(&derEncoded).c_str()); 

     //unsigned char *p = (unsigned char*)malloc(ECDSA_size(eckey)); 

     //int new_sig_size = i2d_ECDSA_SIG(ec_sig, &p); 

     //printf("New Sig Size: %d\n", new_sig_size); 

     //for (int x = 0; x < new_sig_size; x++) { 
     // printf("%d\n", p[x]); 
     //} 

     //Dump DER encoded sig 
     //printf("DER encoded signature\n"); 
     //const unsigned char* pp = (unsigned char*) malloc(new_sig_size); 
     //d2i_ECDSA_SIG(&ec_sig, &pp, new_sig_size); 
     //std::vector<unsigned char> ppVC = std::vector<unsigned char>(pp, pp+new_sig_size); 

     //printf("Base64: %s\n", Misc::base64_encode_d(&ppVC).c_str()); 

     //ECDSA_SIG *signature = ECDSA_do_sign(hash, 20, eckey); 
     //ECDSA_size(eckey); 

     int verify_status = ECDSA_verify(0, hash.data(), hash.size(), derEncoded.data(), derEncoded.size(), eckey);//ECDSA_do_verify(hash.data(), hash.size(), ec_sig, eckey); 

     printf("Verify status: %d\n", verify_status); 

     const int verify_success = 1; 
     if (verify_success != verify_status) 
     { 
      if (verify_status == -1) 
      { 
       handleErrors(); 
      } 
      printf("Failed to verify EC Signature\n"); 
      function_status = -1; 
     } 
     else 
     { 
      printf("Verifed EC Signature\n"); 
      function_status = 1; 
     } 

     //EC_GROUP_free(ecgroup);//Might fail as Ecgroup is constant TODO 
     EC_KEY_free(eckey); 

     return function_status; 
    } 
+0

ニース、報告してくれてありがとう!あなたはしばらくするとあなた自身の答えを受け入れることができます。 –

+0

X、Y、R、Sのエンディアン反転はありません。代わりにSignHashを使用するだけですか?これまでの私の相互運用は失敗しています。 – LamonteCristo

+0

.NETバージョンを以前のバージョンで確認してください。これは、SignDataであり、後者のバージョンのSignHashのみです。そして、エンディアンを反転させることはありませんでした。 – Akumaburn

関連する問題