holepunchto / hyperswarm-secret-stream

Secret stream backed by Noise and libsodium's secretstream
Apache License 2.0
33 stars 14 forks source link

"Noise handshake failed" error after bundling with browserify #13

Open agrathwohl opened 1 year ago

agrathwohl commented 1 year ago

In the following code example, nodejs executes correctly with no errors thrown.

const SecretStream = require('@hyperswarm/secret-stream')

const a = new SecretStream(true)
a.on('error', err => console.error(err))

But when bundling this code with browserify, I encounter this error immediately after loading the webpage:

bundle.js:504 Error: Noise handshake failed
    at NoiseSecretStream._onhandshakert (bundle.js:836:33)
    at NoiseSecretStream._open (bundle.js:884:32)
    at ReadableState.updateNonPrimary (bundle.js:9055:14)
    at ReadableState.update (bundle.js:9032:69)
    at ReadableState.updateReadNT (bundle.js:9177:8)
(anonymous) @ bundle.js:504
emit @ bundle.js:154
afterDestroy @ bundle.js:9142
_destroy @ bundle.js:969
updateNonPrimary @ bundle.js:8887
update @ bundle.js:8872
afterOpen @ bundle.js:9199
_onhandshakert @ bundle.js:836
_open @ bundle.js:884
updateNonPrimary @ bundle.js:9055
update @ bundle.js:9032
updateReadNT @ bundle.js:9177

For some context, I discovered this issue while attempting to replicate a corestore (v6) between the browser and a websocket server. Before corestore-next made its way into the main corestore repo, I was able to do browser replication and could successfully pipe between corestores. But today, this issue prevents me from being able to do so. This leads me to believe the issue may have been introduced into @hyperswarm/secret-stream somewhat recently.

sce9sc commented 12 months ago

I have also found the same problem using a different approach .

Using node v16 I used package overrides in order to force to use sodium-javascript

{
  "name": "test-corestore",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
  },
  "type": "module",
  "author": "",
  "license": "ISC",
  "overrides": {
    "noise-handshake": {
      "sodium-universal": "npm:sodium-javascript@^0.8.0"
    },
    "@hyperswarm/secret-stream": {
      "sodium-universal": "npm:sodium-javascript@^0.8.0"
    }
  },
  "dependencies": {
    "noise-handshake": "3.0.2",
    "@hyperswarm/secret-stream": "^6.2.0"
  }
}

and running the below Code in debug

import SecretStream from "@hyperswarm/secret-stream";

(async function () {
  const a1 = new SecretStream(true);
  const b1 = new SecretStream(false);

  // pipe the underlying rawstreams together
  a1.rawStream.pipe(b1.rawStream).pipe(a1.rawStream);

  a1.write(Buffer.from("hello encrypted!"));

  b1.on("data", function (data) {
    console.log(data); // <Buffer hello encrypted!>
  });
})();

I found that the issue was


TypeError [ERR_INVALID_ARG_TYPE]: The "size" argument must be of type number. Received undefined
    at Function.alloc (/Users/sce9sc/Documents/Work/test-mobile-corestore-pkg/lib/buffer.js:366:3)
    at Object.alloc (/Users/sce9sc/Documents/Work/test-mobile-corestore-pkg/node_modules/b4a/index.js:10:17)
    at Object.generateKeyPair (/Users/sce9sc/Documents/Work/test-mobile-corestore-pkg/node_modules/noise-curve-ed/index.js:28:27)
    at NoiseState.send (/Users/sce9sc/Documents/Work/test-mobile-corestore-pkg/node_modules/noise-handshake/noise.js:187:52)
    at Handshake.send (/Users/sce9sc/Documents/Work/test-mobile-corestore-pkg/node_modules/@hyperswarm/secret-stream/lib/handshake.js:40:31)
    at NoiseSecretStream._open (/Users/sce9sc/Documents/Work/test-mobile-corestore-pkg/node_modules/@hyperswarm/secret-stream/index.js:390:63)
    at WritableState.updateNonPrimary (/Users/sce9sc/Documents/Work/test-mobile-corestore-pkg/node_modules/streamx/index.js:208:14)
    at WritableState.update (/Users/sce9sc/Documents/Work/test-mobile-corestore-pkg/node_modules/streamx/index.js:183:72)
    at WritableState.updateWriteNT (/Users/sce9sc/Documents/Work/test-mobile-corestore-pkg/node_modules/streamx/index.js:532:10)
    at processTicksAndRejections (node:internal/process/task_queues:78:11) {code: 'ERR_INVALID_ARG_TYPE', stack: 'TypeError [ERR_INVALID_ARG_TYPE]: The "size" …ons (node:internal/process/task_queues:78:11)', message: 'The "size" argument must be of type number. Received undefined', toString: ƒ, Symbol(kIsNodeError): true}

I traced it to handshake.js and I consoled log the error when

this.noise.send() was failing

  send () {
    try {
      const data = this.noise.send()
      const wrap = b4a.allocUnsafe(data.byteLength + 3)

      writeUint24le(data.byteLength, wrap)
      wrap.set(data, 3)

      return this._return(wrap)
    } catch (e) {
      console.log(e)
      this.destroy()
      return null
    }
  }

I hope this helps a bit to find what is the problem .

PS. noise-handshake with the same approach seems to be working

sce9sc commented 12 months ago

It seems that the problem is noise-curve-ed

const DHLEN = sodium.crypto_scalarmult_ed25519_BYTES const PKLEN = sodium.crypto_scalarmult_ed25519_BYTES const SCALARLEN = sodium.crypto_scalarmult_ed25519_BYTES

sodium.crypto_scalarmult_ed25519_noclamp

do not exist in sodium-javascript

https://github.com/chm-diederichs/noise-curve-ed/issues/2