HOWTO Verify Messages Between JavaScript and Java with a Graphene KeyPair (via utopian-io)

in #utopian-io7 years ago (edited)

I'm working on a project where the authentication system only requires browser-side access to a user's STEEM Posting Key (similarly to how STEEM, DTube, and DSound interact with the blockchain).

The main difference, however, is that I also need to verify messages (ie. user-specific requests) between a client and server that are not directly verified by the STEEM blockchain. For example, how can I confirm on my back-end server (written in Java) that a particular STEEM user is really who they say they are in the browser?

When you're logged into STEEMIT or DTube, only the front-end really knows you're logged in. And that's just fine, because any transactions such as upvotes that require validation will be verified and encoded by one of the STEEM witnesses into the next block. And if the transaction is accepted, the latest "state" request will reflect any changes effected by all newly accepted transactions collectively.

In my case, however, I need to extend that functionality off-chain, and as such, it would be up to my Java server to validate and verify that the request is a current, non-duplicate "transaction" being requested by a true holder of a valid private posting key vis-a-vis a particular STEEM userID.

At first, I thought this would be a relatively easy problem to solve, because every graphene library that can sign transactions for the blockchain has the required code to perform this signing function. However, most libraries tend to obfuscate their "inner workings". For example, most users of the steemjs library are interested in methods such as:

steem.broadcast.vote(wif, voter, author, permlink, weight, function(err, result) {
console.log(err, result);
});

How that's actually accomplished is a bit less obvious, and the methods used are generally hidden from the library's end users as not to confuse them further. And while I was able to figure out the sign/verify process relatively easily in either javascript or Java, I found myself having an awfully tough time doing it in a way that was inter-operable between the two!

Making it more confusing is that the various code examples I came across were slightly different depending on which chain was being targeted. For example, some libraries seemed to use the bitcoin version, which would perform Sha256Hash.twiceOf(). For graphene chains, the payload is only Sha256Hashed once. Also, while many libraries are designed to sign transactions, they don't focus so much on actually verifying signatures, since that task is normally left up to the witnesses or miners before they're encoded to the blockchain.

And, despite all my googling around and asking others if they had attempted any "off-chain" signing of messages in a compatible way, while some may have attempted it at some point or another, none had a working solution that could perform this seemingly simple extension of a widely performed blockchain operation.

What to do, what to do...?! 😩

Well, as I've often done in the past, if you can't find it readily available, dig, dig, dig, test, test, test, and then dig some more, 😱 pull out a few more hairs from your head 😱, and then test again...! 😩

As such, I traced through the finer details of how these libraries were performing their sign and verify operations. In this case, the main libraries I'm using are steemjs on the javascript side, and steemJ on the Java side.

For those who understand what's involved in a crypto signature, what made this even trickier to solve (which I still don't quite get) is that the signature objects on each side (javascript versus java) would return different r and s combinations, although I later discovered that both were still validating correctly! If anyone has more insight into why this is, please feel free to share in the comments...

To spare you more of my "rambling", the good news is that I finally came up with a solution, which I then rolled up into a relatively simple Java class for anyone to use, called GrapheneUtils.java, which I've now released in my github crypto-playpen repo.

Understanding the Code

GrapheneUtils.java contains both the Java class, and the javascript functions and examples (wrapped in the comments). Also, in order to access the required methods in steemJS, I had to expose a few additional classes, such as the ecc and buffer classes. That updated version of the steemJS library is also available in my github crypto-playpen repo.

In order for the cross-compatible sign/verify to work, I basically made sure that the messages were being processed in the same way, and the signatures were in a compatible format that both sides would understand. Each signature consists of 32-byte R and S integer components, which can be directly serialized to both java's BigInteger type, and javascript's "bigi" BigInteger object. An additional header byte is included for compatibility with other implementations, though when deserializing to javascript, the first byte has to be 32 (base10) to indicate the number of BigInteger bytes. The final format is 1 x 32 x 32, or 1 header byte, 32-bytes for R, and another 32-bytes for S, for a total of 65-bytes. This byte buffer is then converted to its base64 representation, and we're set to go!

In javascript, the functions to achieve this (using my custom-rolled steem.min.js) are as follows:

For the sake of clarity, the above signing call is equivalent to:

const sigObj = steem.ecc.Signature.signBufferSha256(steem.ecc.hash.sha256(msg), privateWif);

In Java, the equivalent functions to encode and decode the same content are as follows:

I've also included a few additional support functions that convert keys between their bytecode and textual (base58) representations. It turns out this was also less intuitive than you would at first expect, and I also had to dig around various libraries and examples to find the correct way to do that as well.

And once you've set this all up, you too will now be empowered with the ability to verify the authenticity of a signed message versus a particular STEEM or other graphene user!

Here's an example from the javascript side:

One last thing though, if you do plan to use this technique to verify messages, you'll also want to include a token and/or a timestamp as well. For example, what if someone intercepts one of the signed packets shown above? Anyone with access to the packet could potentially send that packet again and the server will verify it as valid.

However, if you first send the user a new token before each signed request, that would force the user to generate a freshly signed packet with the correct signing key upon each new login (or any other requested operation, for that matter). If the token encoded into the message doesn't match the one expected by the server, the transaction is simply rejected as invalid.

{"sig":"ABC/7qvUhfvwcGr/cLjR6PXM6kP/olu53FBct6JNgQPfYs2dgBJQS5hFjyvKBcGXFzUsLOTkLVdTnWsVgYhUJIs=","message":["login",{"steem_id":"someSteemUser","token":"7prta-JSla0"}]}

Taking this a step further, you don't even have to include the token in the message. You can simply add it to the signing and verification calls as such:

Wrapping it up...

I'm quite pleased I managed to pull this together, since it opens the doors to using STEEM (and other graphene-based blockchains) as an off-chain authentication system for trusted hybrid blockchain projects where the keys are still maintained locally, but an app can still securely hook into the system to extend functionality beyond the current capabilities of a particular chain.

For example, several services now require a user to link their STEEM userIDs to another account by sending a small transfer of 0.001 SBD or STEEM. Using this technique, the user could simply sign a message along with a token issued by the server, and the server can then validate the signature versus the user's public key pulled directly from the STEEM blockchain.

And finally, for those who've made it this far, but aren't really into blockchain programming, kudos to ya for lasting this long! I can only hope this post provides a bit more insight and understanding into the revolutionary tech that's now taking us... Beyond Bitcoin! 😀

As always, I appreciate your upvote, your follow and all your comments!

GitHub Link: GrapheneUtils.java on github
GitHub Repo: crypto-playpen repo on github

GitHub Repo: steemJ: Steem api wrapper for Java, by @dez1337
GitHub Repo: crypto-core: Swiss Army knife for Blockchain related projects, also by @dez1337



Posted on Utopian.io - Rewarding Open Source Contributors

Sort:  

Thank you for the contribution. It has been approved.


Here is an excerpt from the official rules:

The linked Github repository must always contain code, a README and a license.

Please add a license file to your repo and expand the readme file so that it will be helpful for users who don't know this article.


You can contact us on Discord.
[utopian-moderator]

thank you @vladimir-simovic, also meant to add the article link to the readme but must have slipped my mind. should all be good now ... :)

Hey @vladimir-simovic, I just gave you a tip for your hard work on moderation. Upvote this comment to support the utopian moderators and increase your future rewards!

Hey @alexpmorris I am @utopian-io. I have just upvoted you!

Achievements

  • This is your first accepted contribution here in Utopian. Welcome!

Community-Driven Witness!

I am the first and only Steem Community-Driven Witness. Participate on Discord. Lets GROW TOGETHER!

mooncryption-utopian-witness-gif

Up-vote this comment to grow my power and help Open Source contributions like this one. Want to chat? Join me on Discord https://discord.gg/Pc8HG9x

Not only am I pleased you pulled it together. I'm pleased you narrated the whole process.

Someone that ends up in a similar situation will have one added hair to their head if they they come across this post just before they were ready to pull it out. :)

will have one added hair to their head

awesome @intelliguy, send those hairs my way, I've got a bunch I need to replant! lol

thanks for the comment! :)

super educational your publication, I think more than one will be of great help! I think it is very valuable and it should be very gratifying to know that you contribute very positively in this new platform that becomes much more powerful every day! keep it up

I've been programming since I was 7. I can be good at finding bugs. Let me know if I can help you with beta testing or something :) I've just logged in utopian.io and digging into Steem API. :)

hey @hedac, which languages do you usually find yourself messing around in?

My Javascript is limited... That's why I said beta testing hehe ;) For web development I only know the old PHP+MYSQL HTML5 CSS I'm a bit outdated today ;) Things change so quick in the web but I usually go and learn. I recently like "Lua" a lot.

Educative post.Thanks for sharing it

great and valuable contributions like this are the necessary ones in this platform, so that many of us can understand several things that will help a whole conglomerate of people to grow. Thank you

thanks for information dear friend

wow it's really well explained . Appreciate about this . It will help lot of people in this community .
So keep posting like that .
Waiting for another good one .
Thanks for sharing and bless up @alexpmorris

Too many developers rely on Steem Connect to authenticate to their sites. This article shows an alternative where you validate with the server without needing to send the private key to the server. I would feel a lot more comfortable logging into utopian.io and many other sites if I didn't need to give Steem Connect the Steem equivalent of my bank card and PIN!