Posts

[SOLVED!] PHP Native - Hive Signature Validation - and the Hive+WordPress SSO (single sign on)

avatar of @innerwebbp
25
@innerwebbp
·
0 views
·
7 min read

Verifying a Hive signature in PHP = Adding WordPress magic to your Hive account! I’m excited to say, it’s working!! With the help of a slimmed down ECC library, and about two + weeks of my own private ‘cryptographic google bootcamp’... which was required in order to understand what in the world was actually happening, and how to do it… It’s finally working!!!

update!!! @mahdiyari just posted a new PHP library that is totally awesome! Check it out here: Hive-PHP - A real PHP library for Hive !!! THANK YOU THANK YOU!!! This is SO GREAT!!!

More importantly, it’s working with the same version requirements of a standard WordPress install!!! So, now any WordPress installation can use this plugin! Links at the bottom!

I’m also working with @bambukah to get this added to the Hive PHP libraries he’s maintaining so anyone can use this in any php application! Link to his post about his new Hive-Engine library at the bottom.

If you have no idea what I’m talking about, In my last post, I was asking for some help figuring out how to validate a Hive signed message in PHP. I also talked a little bit about why I want to do that (verify a Hive signature in php), it’s for this WordPress plugin I am working on.

The plugin is a Single Sign On (SSO) plugin for WordPress that allows any user to login to a WordPress site with just their Hive account. Obviously a site needs to be running this plugin, but if they are… anyone with a Hive account can login!!

This plugin is more aimed at ‘Wordpress Creators’ than just the average user… I’m actually making it because I want to use it!!! But it’s something the average user can use too, because it allows them to login to a WordPress site! Ultimately the more creators, the more users, and so on, which is good for Hive. I’m pretty excited about it!

This is part of my 'pinky and the brain' plan, to make just having a Hive account a super power!! Even more than it is now! More about my pinky and the brain plan and IWB (InnerWebBlueprint.com) soon, lots of work still to do.

So, the update is... the first version of the plugin was working great, but it was verifying a Hive signed message on the backend using Python, and the beempy library. Thanks again @brianoflondon for sharing your work!!!

Now, in this case, while it’s working just great, using Python is not ideal, as installing Python libraries can get complicated if you're not hosting your own environment. So I wanted to do it ‘natively’ in PHP so it would be easier for an average WordPress site admin to use it…. Cause if it’s easy, then everyone will do it, right?!?!

So just to go over the whole process…

When a user clicks the ‘login with your hive account’ button, a unique message is sent to Hive Keychain for the user to sign with their Hive account.

After a successful signing, the signature, the original unique message, and the Hive username, are all sent through an ajax call (without reloading the page) back to WordPress (PHP) where the Hive users public key is first looked up from the blockchain, then the message signature is cryptographically verified to have been signed by that same user.

If it is verified, the user is logged in! If they don’t already have a WordPress account with that username, one is created automatically for them... now they do!

Your Hive username becomes your WordPress username, one and the same!

Some details from where the backend starts…

  1. Receive data from the ajax post

  2. Using the provided username, we grab the user's key from the blockchain, so we know it’s not a fake. (this code is not included in the test file, but it’s part of the actual plugin. Eventually I will get this included into one of the PHP libraries as I learn more about classes, something like $account->get_public_key($hiveUname,$keyType))

function iwb_sso_get_publickey ($iwb_sso_HiveUsername) { 
 /** 
  * For now I am just going to use an API call to get the info I need 
  <em> I'm using a hard coded api node for now 
  </em> For API calls I will want to ensure I have a working API 
  <em> see: https://hive.blog/full-nodes/@fullnodeupdate/full-api-node-update---2762022-20220627t203029z 
  </em>/ 
 $iwb_sso_HiveNode = 'https://api.hive.blog'; 
   
 // Use Curl to make an API call.    
 // Build out the json data for the call 
 $iwb_sso_CallData = json_encode(array( 
   "jsonrpc" => "2.0", 
   "method" => "condenser_api.lookup_account_names", 
   "params" => array( 
     ["$iwb_sso_HiveUsername"] 
     ), 
   "id" => 1 
   )); 
  
 // Let's do the curl call 
 $ch = curl_init( $iwb_sso_HiveNode );    
 curl_setopt( $ch, CURLOPT_POSTFIELDS, $iwb_sso_CallData ); 
 curl_setopt( $ch, CURLOPT_HTTPHEADER, array('Content-Type:application/json')); 
 # Return response 
 curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true ); 
 # Send request. 
 $result = curl_exec($ch); 
 curl_close($ch); 
 $data = json_decode($result, true); 
 return $data["result"][0]["active"]["key_auths"][0][0]; 
} 
  
  1. Remove the “STM’ from the key (actually just the first 3, not specifically STM).
// Strip 'STM' 
   $stripKey = substr($hivePublicKey, 3); 
  1. Like Bitcoin, Hive public keys are Base58 encoded, so below we will decode the key. I am using the Tuupola\Base58 library, which I’ve included in the plugin with composer. I’ve also got some links at the bottom I found helpful in explaining Base58 encoding, it’s kinda interesting.
  $base58 = new Base58(["characters" => Base58::BITCOIN]); 
  $decoded = $base58->decode($stripKey); 
  $hexDecoded = bin2hex($decoded); 

Now, we have it decoded, but Hive keys are still ‘compressed’, which I’m pretty sure means it’s got the x coordinate, and some information on how to derive the correct y coordinate. That’s an ECC thing, as there are 2 points on the curve that match possible keys.

  1. So here we check if the key is in fact compressed, and then grab the ‘x’ coordinate from the decoded key, and then using the ECC library get the x,y coordinates that we will test against the signed message.
   // Check if key is compressed 
   // Hive's keys are pretty much always compressed, 
   // See here for reference: https://github.com/holgern/beem/blob/master/beemgraphenebase/account.py 
   // note:: By default, graphene-based networks deal with <b>compressed</b> 
   // public keys. 
  
   // if so, decompress and send to EC to derive y 
   if (substr($hexDecoded,0,2)== '04') { 
       color_red("not compressed"); 
       return $hexDecoded; 
       // do something different here 
       // Hive's keys are pretty much always compressed 
   } elseif (substr($hexDecoded,0,2) == '02'|'03') { 
       color_red("compressed, let's uncompress \n"); 
       $hexDecoded = substr($hexDecoded,0,66); 
       $key = $ec->keyFromPublic($hexDecoded, 'hex'); 
       //print_r($key); 
       $test = $key->getPublic(); 
       print_r($test); 
       // var_dump($test->getX()); 
       // var_dump($test->getY()); 
   } 
   
  1. Now, before we can make sure it’s the same as the signature, first we have to hash the original message that was signed (using sha256). We will use this in a minute.
// let's hash the message - that is what is actually signed 
   $msgHash = openssl_digest($message, 'SHA256' ); 
  1. Now let’s grab the r, and s, from the signature. We will be using these in the last step. Links at the bottom about r and s.
// now lets extract 'r' and 's' from the provided signature into an array 
   $sig   = [ 
       "r" => substr($signature, 2, 64), 
       "s" => substr($signature, 66, 64) 
   ]; 
   color_red("Signature r, and s: \n"); 
   var_dump($sig); 
   echo "\n"; 
  
  1. And now… drum roll please… we send the hashed original message, and our $sig in DER format to the verify method of the ECC library.
   // very the message signature key against the formatted public key pair using the ECC library's verify method. 
   color_red("Is the signature verified: "); 
   echo "Verified: " . (($key->verify($msgHash, $sig) == TRUE) ? "true" : "false") . "\n"; 
 

But wait?? What is that $key thing? LOL?? Well, that’s where I learned that I needed to learn something about OOP (object oriented programming)... That $key is an object, defined in the ECC library I keep referencing.

use Elliptic\EC; 
// 
$ec = new EC('secp256k1'); 
// 
$key = $ec->keyFromPublic($hexDecoded, 'hex'); 

So after all of that… signature verified natively in PHP!!!

Now, I am no expert, that is for certain, so if you have a better way, faster way, or see any errors, please let me know!

Please also note, this is working well, but it’s still early beta, and I plan to add a bunch of settings and stuff like:

  1. Configurable redirect after login
  2. Custom login button colors and text
  3. Custom roles assigned on new account creation
  4. Replacing gravatar with Hive profile pictures
  5. And please comment with any other ideas so I can add them to my list!

I hope you found this valuable in some way, even if the code and ECC stuff doesn’t make any sense to you. It didn’t make sense to me at first either, but it’s starting to seep in!!!

But without all the other people posting all the stuff they have, I would have never been able to figure this out. I hope posting this helps someone else out somewhere along the way like others has helped me.

Links at the bottom:

IWB Github link to the working plugin, which includes test.php in ./includes (all the code mentioned above all together in one file)

Hive Engine Tools PHP Library announcement from @bambukah

My last post asking for help:

@brianoflondon ‘s post -> thank you for sharing your work! https://stemgeeks.net/@brianoflondon/looking-for-help-how-to-verify-if-a-hive-message-is-signed-correctly-in-python-beem

r, s, x and y, curves (secp256k1), inverses, loops, and loopy!

What is the relation between x y and r s in an ECDSA signature? ECDSA r, s encoding as a signature

Why Did Satoshi Decide To Use Secp256k1 Instead Of Secp256r1?

A Bluffer’s Guide to secp256k1

Guidance for Choosing an Elliptic Curve Signature Algorithm in 2022

Another PHP library that I never got around to trying out

A comparison between the secp256r1 and the koblitz secp256k1 bitcoin curves

EC Private Key Example - secp256k1

Base58/encoding/decoding:
https://blog.boot.dev/bitcoin/base64-vs-base58-encoding/

https://blog.boot.dev/cryptography/encoding-vs-encryption/

https://github.com/tuupola/base58

https://www.darklaunch.com/base58-encode-and-decode-using-php-with-example-base58-encode-base58-decode.html

https://stackoverflow.com/questions/8970715/how-do-i-base58-encode-a-string

https://medium.com/concerning-pharo/understanding-base58-encoding-23e673e37ff6 https://en.bitcoinwiki.org/wiki/Base58#base58_converters

Oh, and if you made it this far, this link about hive intelligence is absolutely remarkable…

The Secret Life of Bees The world’s leading expert on bee behavior discovers the secrets of decision-making in a swarm

It’s a ‘core design element’ of the IWB project I am working on… I’ll write a lot more about this later in a ‘regular’ non dev update post. v+v=vm2