Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for noise-protocol #17

Open
bcomnes opened this issue Jan 8, 2020 · 17 comments
Open

Support for noise-protocol #17

bcomnes opened this issue Jan 8, 2020 · 17 comments

Comments

@bcomnes
Copy link

bcomnes commented Jan 8, 2020

It would be great if the noise-protocol module would work with sodium universal.

From what I can gather the following parts of sodium need to be ported:

The key exchange looks relatively straight forward, the crypto_aead_xchacha20poly1305_ietf end of things looks a bit more involved (e.g. reimplementing https://github.com/jedisct1/libsodium/blob/927dfe8e2eaa86160d3ba12a7e3258fbc322909c/src/libsodium/crypto_core/hchacha20/core_hchacha20.c or doing some kind of WAT rewrite like xsalsa20 ?

@emilbayes do you have any pointers on how you would go about doing that?

@bcomnes
Copy link
Author

bcomnes commented Jan 8, 2020

I started some work on the easy parts here: https://github.com/bcomnes/sodium-javascript/tree/noise-support

@emilbayes
Copy link
Member

Those primitives will be good regardless, but I will change the primitives in noise-protocol soon so they conform with most other implementations out there. This means I will do chacha20-poly1305 soon

@emilbayes
Copy link
Member

Since these are brand new primitives, maybe you want to split them into a separate file like we started doing on some of the newly implemented ones?

@bcomnes
Copy link
Author

bcomnes commented Jan 8, 2020

maybe you want to split them into a separate file like we started doing on some of the newly implemented ones?

Yeah agreed, I was sort of just feeling my way around. I'll split those out.

I will change the primitives in noise-protocol soon so they conform with most other implementations out there. This means I will do chacha20-poly1305 soon

You mean instead of the crypto_kx_* primitives, switch to the chacha20-poly1305 primitives?

I'm taking a stab at a hchacha20 .wat implementation. I'll post if I can get it working.

Thank you for the input!

@bcomnes
Copy link
Author

bcomnes commented Jan 10, 2020

I started a WAT implementation in https://github.com/little-core-labs/hchacha20/blob/master/hchacha20.wat

Has anyone spotted a good way to port macro blocks?

https://github.com/jedisct1/libsodium/blob/master/src/libsodium/crypto_core/hchacha20/core_hchacha20.c#L8-L14

I presume just type it out is the most straight forward option.

@bcomnes
Copy link
Author

bcomnes commented Jan 10, 2020

Completed hchacha20: https://github.com/little-core-labs/hchacha20/blob/master/hchacha20.wat

Time to see if it works.

@cblgh
Copy link

cblgh commented Mar 19, 2020

@bcomnes did it work? :)

@bcomnes
Copy link
Author

bcomnes commented Mar 27, 2020

@cblgh had to step away from the project. 2 observations:

  • in our use case, we have a local node process we can run sodium native on, and use websocketsc over loopback, or use normal https. For now, this is the arrangement we opted for. Generally, this approach seems to be simplest approach instead of doing browser crypto.
  • While doing this, I found libsodium-js which provides a full JS API for libsodium, instead of the patchwork api that sodium-javascript supports. It seems to me the best bang for the buck would be to wrap libsodium-js in a way that make it uniform with sodium-native, and integrate that into sodium-universal. @emilbayes: Has that approach been considered? Part of my stall on this was due to that realization. If we can answer that, there should be a clear path forward.

@tinchoz49
Copy link

tinchoz49 commented Mar 29, 2020

https://github.com/tinchoz49/workaround-hypercore8-browser

Hey everyone! this is a workaround example that I did using sodium-javascript and adding the missing crypto functions from libsodium.js.

It's just an example to check what we need to get hypercore 8 working on the browser.

libsodium.js has everything what we need but:

  1. The API is different from the sodium-friends approach.
  2. I did a benchmark comparing libsodium.js vs sodium-javascript and libsodium.js is like 6x slower than the javascript implementation.

So I think updating sodium-javascript could be the first option.

@emilbayes
Copy link
Member

emilbayes commented Mar 29, 2020

Nice demo @tinchoz49! Even with handrolled sodium-javascript I don't know what kind of performance we can expect, but probably 2 - 4 times slower than sodium-native (just from intuition, no benchmarks to base this on)

@tinchoz49
Copy link

tinchoz49 commented Mar 29, 2020

Thank you @emilbayes ! My benchmark was very poor but it was more for investigation purpose, since I cannot test the xchacha20 functions in sodium-javascript i just run a common crypto_secretbox:

const bench = require('nanobench')
const sodium = require('sodium-native')
const sodiumjs = require('sodium-javascript')
const libsodium = require('libsodium-wrappers')

libsodium.ready.then(() => {
  bench('sodium-native', function (b) {
    b.start()

    for (let i = 0; i < 5000; i++) {
      var nonce = Buffer.alloc(sodium.crypto_secretbox_NONCEBYTES)
      var key = sodium.sodium_malloc(sodium.crypto_secretbox_KEYBYTES) // secure buffer
      var message = Buffer.from('Hello, World!')
      var ciphertext = Buffer.alloc(message.length + sodium.crypto_secretbox_MACBYTES)

      sodium.randombytes_buf(nonce) // insert random data into nonce
      sodium.randombytes_buf(key) // insert random data into key

      // encrypted message is stored in ciphertext.
      sodium.crypto_secretbox_easy(ciphertext, message, nonce, key)

      var plainText = Buffer.alloc(ciphertext.length - sodium.crypto_secretbox_MACBYTES)

      sodium.crypto_secretbox_open_easy(plainText, ciphertext, nonce, key)
    }

    b.end()
  })

  bench('sodium-javascript', function (b) {
    b.start()

    const sodium = sodiumjs

    for (let i = 0; i < 5000; i++) {
      var nonce = Buffer.alloc(sodium.crypto_secretbox_NONCEBYTES)
      var key = sodium.sodium_malloc(sodium.crypto_secretbox_KEYBYTES) // secure buffer
      var message = Buffer.from('Hello, World!')
      var ciphertext = Buffer.alloc(message.length + sodium.crypto_secretbox_MACBYTES)

      sodium.randombytes_buf(nonce) // insert random data into nonce
      sodium.randombytes_buf(key) // insert random data into key

      // encrypted message is stored in ciphertext.
      sodium.crypto_secretbox_easy(ciphertext, message, nonce, key)

      var plainText = Buffer.alloc(ciphertext.length - sodium.crypto_secretbox_MACBYTES)

      sodium.crypto_secretbox_open_easy(plainText, ciphertext, nonce, key)
    }

    b.end()
  })

  bench('libsodium.js', function (b) {
    b.start()

    const sodium = libsodium

    for (let i = 0; i < 5000; i++) {
      var key = Buffer.alloc(sodium.crypto_secretbox_KEYBYTES) // secure buffer
      var message = Buffer.from('Hello, World!')
      var nonce = sodium.randombytes_buf(sodium.crypto_secretbox_NONCEBYTES)
      var ciphertext = sodium.crypto_secretbox_easy(message, nonce, key)
      var plainText = sodium.crypto_secretbox_open_easy(ciphertext, nonce, key)
    }

    b.end()
  })
})

sodium-native

ok ~162 ms (0 s + 161726505 ns)

sodium-javascript

ok ~101 ms (0 s + 100917442 ns)

libsodium.js

ok ~372 ms (0 s + 372270050 ns)

@tinchoz49
Copy link

tinchoz49 commented Mar 29, 2020

If we choose to use libsodium.js we can do a wrapper to provide the same API than sodium-native have. My only concern is about the async nature of loading a wasm library, that breaks everything.

We can compile libsodium.js using the emscripten flag BINARYEN_ASYNC_COMPILATION=0 ?

If we use libsodium.js we would have full support of sodium for the browser, that's a good point I guess.

@emilbayes
Copy link
Member

We have plans to to the remaining ciphers in wasm :) The async'ness is unfortunately a question of binary size

@tinchoz49
Copy link

tinchoz49 commented Apr 4, 2020

The async'ness is unfortunately a question of binary size

That's true.

I'm working on a minimal version of sodium in wasm based on libsodium.js that we can load sync in the browser (thinking about the 4kb limitation of chrome)

Initially, it will have only the necessary to run the missing operations that we need for noise-protocol:

  • crypto_kx_keypair
  • crypto_kx_seed_keypair
  • crypto_kx_client_session_keys
  • crypto_kx_server_session_keys
  • crypto_aead_xchacha20poly1305_ietf_encrypt
  • crypto_aead_xchacha20poly1305_ietf_decrypt

But my idea is to build something that we can extend in the future to add the rest of the operations to have everything in wasm.

I will try to publish next week 🤞

@tinchoz49
Copy link

tinchoz49 commented Apr 6, 2020

https://github.com/geut/sodium-javascript-plus

Experimental support of xchacha20 and kx for sodium-javascript.

And updated the example: https://github.com/tinchoz49/workaround-hypercore8-browser

Performance is about 3x slow than sodium-native but faster than libsodium.js

@cblgh
Copy link

cblgh commented Apr 6, 2020

👏 👏 👏 👏 👏 👏

nice job @tinchoz49!

@bcomnes
Copy link
Author

bcomnes commented Apr 6, 2020

Great work @tinchoz49 !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants