Steem Messenger V0.0.6 : Deep dive in the cryptography updates

in #utopian-io6 years ago

Repository

https://github.com/kingswisdom/SteemMessenger
Merged request: https://github.com/kingswisdom/SteemMessenger/pull/18

About the project

Steem Messenger aims to cover a need in our ecosysteem, the need for a chat on Steem. We aim to do it securely. We want to build the ultimate chat application for the Steem blockchain.

Designed for privacy, with the clever use of the Private Memo Key to authenticate yourself into the Messenger's network, you'll soon be able to safely engage with everybody on the Steem social network without needing anything more than your recipient username.

We use the Steem blockchain as a Decentralized Public Key Infrastructure (DPKI), meaning the Steem blockchain is our contact book, with usernames and they public keys associated to them. We also add a local encrypted wallet (another missing component of steem) to store user keys, like the memo private key.

New Features

Scrypt Benchmark and Parameters choice

Scrypt is a password-based key derivation function that help increase the security of the usage of users password. It hardens the job of an attacker trying to crack your password, specially against GPUs. GPUs are well suited for cracking password because they have more computing units to run the same function and they are easier to scale than CPUs. Using Scrypt greatly decreases the advantage of using GPUs for attackers. This is the reason why it was interesting for mining, although cryptocurrencies like Litecoin used very weak parameters.

So we evaluate the default parameters and benchmark our library to see how much we could increase the default parameters while staying well under the 10s for the first login.

We use https://github.com/bestiejs/benchmark.js/
First download benchmark.js, platform.js and lodash.js.
Second bundle the benchmmark js for the browser:

browserify tests.js -o bundle.js

Now fire index.html in your browser and look in the console for the result.

Some results:
Settings: VM with 2 cpus, 3GB of RAM running Ubuntu
Using directly node tests.js (outside of the browser)

========================
starting Benchmark
========================
default x 0.38 ops/sec ±14.89% (6 runs sampled) => average time 2.651413617 seconds
power15 x 0.24 ops/sec ±1.35% (5 runs sampled) => average time 4.1795559346 seconds
power16 x 0.12 ops/sec ±1.62% (5 runs sampled) => average time 8.406441287000002 seconds
power17 x 0.06 ops/sec ±5.65% (5 runs sampled) => average time 17.863167007 seconds
power18 x 0.03 ops/sec ±2.32% (5 runs sampled) => average time 36.5808561954 seconds
Fastest is default

In Firefox I get:

========================
starting Benchmark
========================
default x 0.72 ops/sec ±7.56% (6 runs sampled) => average time 1.3905 seconds
power15 x 0.33 ops/sec ±18.72% (5 runs sampled) => average time 3.0620000000000003 seconds
power16 x 0.18 ops/sec ±7.46% (5 runs sampled) => average time 5.6842 seconds
power17 x 0.08 ops/sec ±14.08% (5 runs sampled) => average time 12.9344 seconds
power18 x 0.10 ops/sec ±2.06% (5 runs sampled) => average time 10.2472 seconds
Fastest is default

I recommended N=2^16, r=8, p=1. I would like to increase in the future N to 2^18 (remember the default is 2^14). An attacker will certainly not use Javascript code to attack so we are only making her job easier if we can not wait a bit longer to use our keys.

I will write a complete article on password state of the art and wallet encryption in a future post/ on the project wiki. Some sources:

Choose SJCL library

It is hard to do proper cryptography in Javascript. With NodeJS, you get some functions but they usually come from different libraries and it is a better practice to rely on one cryptographic library. We also have the issue that the code needs to work on the client side and not all libraries/function work with browserify. We choose the sjcl library because it has no dependecies, was written by cryptographers, is also used by steem js libcrypto, support various enconding(base64url) and cryptographic functions (AES GCM).
Here is what the decryption function looks like now:

/**
 * Decryption of AES-GCM.
 * @param {string} decryptionKey A base64url encoded symmetric key. Error if it is not the right key
 * @param {string} data string. Make sure that data is a printable (base64url if possible) string.
 * @return {string} The flat json ciphertext.
 */
Crypto.decrypt = function(decryptionKey,data){
    try{
        var rawDecryptionKey = sjcl.codec.base64url.toBits(decryptionKey);
        //convert base64url to base64
        data = data.replace(/-/g,'+').replace(/_/g,'/')
        var plaintext = sjcl.decrypt(rawDecryptionKey, data);
        return plaintext;
    }catch(err) {
        //either the raw dercyption key is not base64url
        //either the decryption fail: which is because
            //the decryption key is not the good one
            //or/and the authentication tag is wrong
        return err;
    }
}

In the next version, we will try to upgrade the remaining security functions, like scrypt or random number generation, that do not rely yet on SJCL.

cryptography migration

The Steem.memo.encode/decode function does two things:

  1. (asymmetric) key exchange to generate a shared secret using the sender memo key and the recipient memo key. This is Diffie–Hellman key exchange.
  2. (symmetric) uses the shared secret with AES in mode CBC to encrypt/decrypt the message.

We ran run into two problems:

  1. asymmetric cryptography is significantly slower than the symmetric counterpart. So this will be the main bottleneck.

It is a bad idea to redo this operation every time we need to send a message. In Steem-Messenger, we encrypt messages between sender and recipient, then this message is encrypted by the sender for the server, then decrypted by the server, and again encrypted by the server for the recipient. This means, if we use the steem.memo.encode/decode function, that we will do two asymetric operations per messages because of the encryption and super-encryption. This was really slow in the previous version.
We now store as much as possible the shared secret. Note that this is mainly a client side problem.

  1. Since we are off the chain, we do not have any signature on the message. This means that recipient cannot verify authenticity and integrity of the messages.

On Steem, you usually sign the operation, whether you write a comment with your posting key or send a transfer with your active key. Steem.memo.encode does not cover this need because it uses AES in the CBC mode. We decide to switch to the mode GCM which provide an authentication tag with the ciphertext.

/**
 * Encryption using AES-GCM. The choices were CCM, GCM, and OCB2. I need to check the other 2.
 * @param {string} encryptionKey A base64url encoded symmetric key
 * @param {string} data string. Make sure that data is a printable (base64url if possible) string.
 * @return {string} The flat json ciphertext.
 */
Crypto.encrypt = function (encryptionKey,data){
    try{
        var rawEncryptionKey = sjcl.codec.base64url.toBits(encryptionKey);
        var ciphertext = sjcl.encrypt(rawEncryptionKey, data, {mode : "gcm"});
        var rawct = sjcl.json.decode(ciphertext);
        var rawOutput = {iv:sjcl.codec.base64url.fromBits(rawct.iv),
            mode : "gcm", cipher :"aes",
            ct:sjcl.codec.base64url.fromBits(rawct.ct)};
        var output = sjcl.json.encode(rawOutput);
        return output;

    }catch(err) {//should happen only if the encryption key is not base64url
        return err;
    }
}

We then update our core functions to use the our new cryptographic choices:

  • user to user message encryption. This greatly improves file encryption performance.
  • user to server (and vice-versa) socket encryption.
  • wallet storage

Various fixes

Previous version ran two round of Scrypt which was rather unnecessary. The salt was also fixed, which is defeating the purpose of using a salt.

Wallet update was re-using the same initializing vector This is bad for stream (mode) encryption because:

CT1 = M1 xor KEY
CT2 = M2 xor KEY
=> CT1 xor CT2 =   M1 xor KEY xor M2 xor KEY = M1 xor M2

There are ways to get some of the contents of both messages form their xor. This was a small issue because the function was not used yet. The fix was simple, the update function just use the create function.

We also moved from base58 to base64url. I am not sure if it is necessary to use base64url instead of just base64 but for now I am sticking to it.

Next features

We are looking into the Signal protocol to securely add group chat and voice/video calls. We are also exploring how we can extend the scope of the wallet to store more keys and do in-chat token transfer.

GitHub Account

https://github.com/cryptohazard

Sort:  

Hi, I checked the PR and didn't find any of your commits (under your github account ID @cryptohazard) in the last 14 days and therefore I am afraid that this will not be moderated.
Please could you read the utopian guidance.

Thank you for your understanding.


Need help? Write a ticket on https://support.utopian.io/.
Chat with us on Discord.
[utopian-moderator]

Hi, the guidance says:

To be considered for potential reward, Bug Fixes and New Features should be submitted via Pull Requests. The Pull Request should have been merged within the past 14 days.

We have been working on the code for quite some time and we finish the new version now. From the rules, it is the date of the pull request that is relevant, not the commits. I mean we are two working on this projects and the work from the main developper (and project owner) got accepted in utopian: https://steemit.com/utopian-io/@kingswisdom/steem-messenger-v0-0-5-safestorage-safesocket-last-update-before-release-and-many-more.

Yes, I can see that, but it is @kingswisdom who opened up the PR (and he did most of the contribution as far as I can see from the list) and merged it. As you said, the main developer has a post accepted already.

He has a post for his work and I am making mine for my work.
Following what you cite, most of his commits should not get rewarded because there are way older. I now have a developer access to the repo so for us it did not make a difference who open/close the request since we have been working on the same branch.

And please, don't evaluate my work in term of number of commits compare to @kingswisdom. I focus on security and will always have a less quantitative impact on the source code.

I have NOT yet evalulated your work yet but I am just saying that from the number of commits. What I was saying is that it is @kingswisdom who opened up the PR - so I am not sure if this is eligible if you want to make a post on it. Will let you know after I get the opinions from the CM.

Thank you for your review, @justyy!

So far this week you've reviewed 4 contributions. Keep up the good work!

Thank you for your contribution. I can see huge efforts have been put to ensure the messages transferred on the steem blockchain are safe. So how do you overcome the problem that the messages may be forged (are not geniue) if you don't sign the messages? Also, since on steem block chains are producing blocks every 3 seconds - and there is a 3 second comment limit, if a user has typed so fast how do you solve this problem?

Your contribution has been evaluated according to Utopian policies and guidelines, as well as a predefined set of questions pertaining to the category.

To view those questions and the relevant answers related to your post, click here.


Need help? Write a ticket on https://support.utopian.io/.
Chat with us on Discord.
[utopian-moderator]

This is why we don't put the messages on the blockchain. You also have the issue that the blockchain would store your conversations forever, even if they are encrypted.

So what do we use steem for? Just for the keys. That way you and I can check each other memo keys directly on the blockchain. Then everything else use a good old database.

We are planning to release it live pretty soon I hope. That way people will test and we will have feedback and a lot of bugs most likely.

Just got the opinions from CM and he said it is fine, so I will review your contribution in 12 hours. Thanks and sorry for any inconvenience.

Sorry too. I thought I knew it would work without issue because I have seen other projects accepted before. That is why I was a bit surprise.
thanks for reviewing.

Hi @cryptohazard!

Your post was upvoted by @steem-ua, new Steem dApp, using UserAuthority for algorithmic post curation!
Your post is eligible for our upvote, thanks to our collaboration with @utopian-io!
Feel free to join our @steem-ua Discord server

Hey, @cryptohazard!

Thanks for contributing on Utopian.
We’re already looking forward to your next contribution!

Get higher incentives and support Utopian.io!
Simply set @utopian.pay as a 5% (or higher) payout beneficiary on your contribution post (via SteemPlus or Steeditor).

Want to chat? Join us on Discord https://discord.gg/h52nFrV.

Vote for Utopian Witness!

Coin Marketplace

STEEM 0.26
TRX 0.11
JST 0.033
BTC 64777.26
ETH 3101.53
USDT 1.00
SBD 3.84