2016-08-08 12 views
2

ich vorbei bin in folgenden (der Digest/Hash SHA1):OpenSSL kann nicht ECDSA Signatur C++ überprüfen, überprüft C# richtig

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

Um diese Funktion:

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

Aber ich kann nicht überprüfen die Signatur in OpenSSL (verify_success ist 0), obwohl die exakt gleichen Daten in C# erfolgreich verifiziert werden.

Irgendwelche Ideen, warum oder was ich falsch mache?

Der öffentliche Schlüssel in C# ist:

4543533120000000C2D0A868C35F475208B6C33A58D4AC275190F1A9D5804456FF07C42605716EF748FB4FD246163E851DBE9A942569741F54341A7C85F394B20777AB7FE526096A 

Ich gehe davon aus, dass 4543533120000000 .NET spezielle Sachen i so nur 04 davon an den Rest vorgehängten.

Hier ist der C# -Code verwendet, um die Signatur zu verifizieren und es tut so erfolgreich (SHA1 von Datenbytes ist über beide Programme identisch) ..

 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!"); 
      } 
     } 

Jede geschätzt Hilfe.

+0

Überprüfen Sie die Versionshinweise. –

+0

Ich habe, konnte nichts zu beachten als auch eine neue Methode Handler, die keine Konvertierung zu und von ECDSA_SIG, https://www.openssl.org/news/changelog.html – Akumaburn

+0

Sie könnten versuchen, die Bytes in die Schlüssel- und Signatur-Integer * Werte * der Koordinaten, X, Y und R, S (eventuell auch mischen, 3 Möglichkeiten). C# verwendet häufig eine Codierung mit wenig Endian. –

Antwort

1

Ich fand das Problem, ich war mit der .NET-Funktion ECDSA.SignData, aber das Hashing tatsächlich die Daten vor der Eingabe (mit ECDsaCng.HashAlgorithm), ich nahm an, es war ein Hash als eine Eingabe, aber die richtige Funktion dafür ist ECDSA.SignHash, ich habe zu SignHash gewechselt und meine neue Signatur/Nachricht wird korrekt verifiziert. (Beachten Sie, dass dies für Sie je nach Ihrer Version von .NET unterschiedlich sein kann, achten Sie darauf, die API für Ihre Version zu überprüfen)

Falls es jemand hilft, hier ist meine Entwurf-Funktion (Es gibt einige extra/nicht benötigte Sachen hier auch, die Ihnen helfen können):

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

Schön, danke für deine Rückmeldung! Sie können Ihre eigene Antwort nach einer Weile akzeptieren. –

+0

Nur um sicher zu sein, gibt es kein Endian-Flip für X, Y und R, S? Verwenden Sie stattdessen SignHash? Bis jetzt versagt meine Interop. – LamonteCristo

+0

Überprüfen Sie Ihre .NET-Version in früheren Versionen war es SignData, seine einzige SignHash in einer der letzteren Versionen weiter. Und nein, es gab keinen Endian. – Akumaburn

Verwandte Themen