From 8e86b20a12e26ea3bd929e5ab87dc5c67743a013 Mon Sep 17 00:00:00 2001 From: morrigan Date: Thu, 31 Oct 2019 14:29:16 +0100 Subject: [PATCH 01/20] Fix tag --- src/index.ts | 2 +- test/index.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/index.ts b/src/index.ts index ad3d735..9c1cda0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,6 @@ import { encrypt } from './encrypt'; -const tag = '/noise/1.0.0'; +const tag = '/noise'; export { tag, diff --git a/test/index.test.ts b/test/index.test.ts index 54b2c0d..d13bbbe 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -3,7 +3,7 @@ import { tag, encrypt} from "../src"; describe("Index", () => { it("should expose right tag and encrypt function", () => { - expect(tag).to.equal('/noise/1.0.0'); + expect(tag).to.equal('/noise'); expect(typeof(encrypt)).to.equal('function'); }) }); From e55fa206fd1fbfbd9275b1dc625e56591d112d4b Mon Sep 17 00:00:00 2001 From: morrigan Date: Thu, 31 Oct 2019 17:35:18 +0100 Subject: [PATCH 02/20] Finish init session functions --- .nvmrc | 1 + package.json | 9 +- src/types/basic.ts | 9 + src/xx.ts | 110 +++++++++++ tsconfig.json | 5 +- yarn.lock | 475 ++++++++++++++++++++++++++++++++++++++++++++- 6 files changed, 602 insertions(+), 7 deletions(-) create mode 100644 .nvmrc create mode 100644 src/types/basic.ts create mode 100644 src/xx.ts diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..f8c17e7 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +12.4.0 diff --git a/package.json b/package.json index b83f589..14549b0 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "@types/mocha": "^5.2.7", "@typescript-eslint/eslint-plugin": "^2.6.0", "@typescript-eslint/parser": "^2.6.0", + "bn.js-typings": "^1.0.1", "chai": "^4.2.0", "eslint": "^6.6.0", "mocha": "^6.2.2", @@ -33,7 +34,11 @@ "@babel/preset-env", "@babel/preset-typescript" ], - "plugins": [ - ] + "plugins": [] + }, + "dependencies": { + "bn.js": "^5.0.0", + "buffer": "^5.4.3", + "libp2p-crypto": "^0.17.1" } } diff --git a/src/types/basic.ts b/src/types/basic.ts new file mode 100644 index 0000000..8e3ad53 --- /dev/null +++ b/src/types/basic.ts @@ -0,0 +1,9 @@ +import { BN } from 'bn.js'; +import { Buffer } from 'buffer'; + +export type bytes = Buffer; +export type bytes32 = Buffer; +export type bytes16 = Buffer; + +export type uint32 = number; +export type uint64 = BN; diff --git a/src/xx.ts b/src/xx.ts new file mode 100644 index 0000000..c3b7238 --- /dev/null +++ b/src/xx.ts @@ -0,0 +1,110 @@ +import {bytes32, bytes16, uint32, uint64, bytes} from './types/basic' +import { Buffer } from 'buffer'; +import * as crypto from 'libp2p-crypto'; + +type KeyPair = { + publicKey: bytes32, + privateKey: bytes32, +} + +type CipherState = { + k: bytes32, + n: uint32, +} + +type SymmetricState = { + cs: CipherState, + ck: bytes32, + h: bytes32, +} + +type HandshakeState = { + ss: SymmetricState, + s: KeyPair, + e: KeyPair, + rs: bytes32, + re: bytes32, + psk: bytes32, +} + +type NoiseSession = { + hs: HandshakeState, + h: bytes32, + cs1: CipherState, + c2: CipherState, + mc: uint64, + i: boolean, +} + +const emptyKey = Buffer.alloc(32) as bytes32; +const minNonce = 0; + +class XXHandshake { + async initializeInitiator(prologue: bytes32, s: KeyPair, rs: bytes32, psk: bytes32) : Promise { + const e: KeyPair; + const re: bytes32; + const name = "Noise_XX_25519_ChaChaPoly_SHA256"; + const ss = await this.initializeSymmetric(name); + await this.mixHash(ss, prologue); + + return {ss, s, e, rs, re, psk}; + } + + async initializeResponder(prologue: bytes32, s: KeyPair, rs: bytes32, psk: bytes32) : Promise { + const e: KeyPair; + const re: bytes32; + const name = "Noise_XX_25519_ChaChaPoly_SHA256"; + const ss = await this.initializeSymmetric(name); + await this.mixHash(ss, prologue); + + return {ss, s, e, rs, re, psk}; + } + + initializeKey(k: bytes32) : CipherState { + const n = minNonce; + return { k, n }; + } + + async initializeSymmetric(protocolName: string) : Promise { + const h = await this.hashProtocolName(protocolName); + const ck = h; + const cs = this.initializeKey(emptyKey); + + return { cs, ck, h }; + } + + async hashProtocolName(protocolName: string) : Promise { + if (protocolName.length <= 32) { + return new Promise(resolve => { + const h = new Buffer(32); + h.write(protocolName); + resolve(h) + }); + } else { + return await this.getHash(Buffer.from(protocolName), new Buffer([])); + } + } + + async mixHash(ss: SymmetricState, data: bytes) { + ss.h = await this.getHash(ss.h, data); + } + + async getHash(a: bytes, b: bytes) : Promise { + return await crypto.hmac.create('sha256', Buffer.from([...a, ...b])) + } + + async initSession(initiator: boolean, prologue: bytes32[], s: KeyPair, rs: bytes32) : Promise { + let session: NoiseSession; + const psk = emptyKey; + + if (initiator) { + session.hs = await this.initializeInitiator(prologue, s, rs, psk); + } else { + session.hs = await this.initializeResponder(prologue, s, rs, psk); + } + + session.i = initiator; + session.mc = 0; + return session; + } +} diff --git a/tsconfig.json b/tsconfig.json index adbb048..dd6aa73 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,9 +6,12 @@ "esModuleInterop": true, "typeRoots": [ "./node_modules/@types" + ], + "include": [ + "./node_modules/bn.js-typings/index.d.ts" ] }, "exclude": [ "node_modules" ] -} \ No newline at end of file +} diff --git a/yarn.lock b/yarn.lock index 26df680..833871e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -721,6 +721,11 @@ resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.7.tgz#315d570ccb56c53452ff8638738df60726d5b6ea" integrity sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ== +"@types/node@^10.12.12": + version "10.17.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.2.tgz#41b5afbcde1a5a805302a4da3cf399499f1bbf64" + integrity sha512-sAh60KDol+MpwOr1RTK0+HgBEYejKsxdpmrOS1Wts5bI03dLzq8F7T0sRXDKeaEK8iWDlGfdzxrzg6vx/c5pNA== + "@typescript-eslint/eslint-plugin@^2.6.0": version "2.6.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-2.6.0.tgz#e82ed43fc4527b21bfe35c20a2d6e4ed49fc7957" @@ -869,6 +874,20 @@ array-unique@^0.3.2: resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= +asmcrypto.js@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/asmcrypto.js/-/asmcrypto.js-2.3.2.tgz#b9f84bd0a1fb82f21f8c29cc284a707ad17bba2e" + integrity sha512-3FgFARf7RupsZETQ1nHnhLUUvpcttcCq1iZCaVAbJZbCZ5VNRrNyvpDyHTOb0KC3llFcsyOT/a99NZcCbeiEsA== + +asn1.js@^5.0.1, asn1.js@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.2.0.tgz#292c0357f26a47802ac9727e8772c09c7fc9bd85" + integrity sha512-Q7hnYGGNYbcmGrCPulXfkEw7oW7qjWeM4ZTALmgpuIcZLxyqqKYWxCZg2UBm8bklrnB4m2mGyJPWfoktdORD8A== + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + assertion-error@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" @@ -906,6 +925,18 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= +base-x@^3.0.2: + version "3.0.7" + resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.7.tgz#1c5a7fafe8f66b4114063e8da102799d4e7c408f" + integrity sha512-zAKJGuQPihXW22fkrfOclUUZXM2g92z5GzlSMHxhO6r6Qj+Nm0ccaGNBzDZojzwOMkpjAv4J0fOv1U4go+a4iw== + dependencies: + safe-buffer "^5.0.1" + +base64-js@^1.0.2: + version "1.3.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.1.tgz#58ece8cb75dd07e71ed08c736abc5fac4dbf8df1" + integrity sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g== + base@^0.11.1: version "0.11.2" resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" @@ -924,6 +955,42 @@ binary-extensions@^1.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== +bindings@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + +bip66@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/bip66/-/bip66-1.1.5.tgz#01fa8748785ca70955d5011217d1b3139969ca22" + integrity sha1-AfqHSHhcpwlV1QESF9GzE5lpyiI= + dependencies: + safe-buffer "^5.0.1" + +blakejs@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.1.0.tgz#69df92ef953aa88ca51a32df6ab1c54a155fc7a5" + integrity sha1-ad+S75U6qIylGjLfarHFShVfx6U= + +bn.js-typings@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/bn.js-typings/-/bn.js-typings-1.0.1.tgz#00faef56401850b763cee041c0728a9aaf091e7e" + integrity sha512-PdV3AEpI5A8mHCt3KgBobIJ+3rhoxxkRl8b0dCGDgGtJNYmN4KTPLHYq7xOSmKF1Kv06aZ5k8QhXbyG73IyhdQ== + dependencies: + "@types/node" "^10.12.12" + +bn.js@^4.0.0, bn.js@^4.11.8, bn.js@^4.4.0: + version "4.11.8" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f" + integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA== + +bn.js@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.0.0.tgz#5c3d398021b3ddb548c1296a16f857e908f35c70" + integrity sha512-bVwDX8AF+72fIUNuARelKAlQUNtPOfG2fRxorbVvFk4zpHbqLrPdOGfVg5vrKwVzLLePqPBiATaOZNELQzmS0A== + brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -948,11 +1015,28 @@ braces@^2.3.1, braces@^2.3.2: split-string "^3.0.2" to-regex "^3.0.1" +brorand@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= + browser-stdout@1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== +browserify-aes@^1.0.6, browserify-aes@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + browserslist@^4.6.0, browserslist@^4.7.2: version "4.7.2" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.7.2.tgz#1bb984531a476b5d389cedecb195b2cd69fb1348" @@ -962,11 +1046,31 @@ browserslist@^4.6.0, browserslist@^4.7.2: electron-to-chromium "^1.3.295" node-releases "^1.1.38" +bs58@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" + integrity sha1-vhYedsNU9veIrkBx9j806MTwpCo= + dependencies: + base-x "^3.0.2" + buffer-from@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= + +buffer@^5.2.1, buffer@^5.4.3: + version "5.4.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.4.3.tgz#3fbc9c69eb713d323e3fc1a895eee0710c072115" + integrity sha512-zvj65TkFeIt3i6aj5bIvJDzjjQQGs4o/sNoezg1F1kYap9Nu2jcUdpwzRSJTHMMzG0H7bZkn4rNQpImhuxWX2A== + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + cache-base@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" @@ -1052,6 +1156,14 @@ chownr@^1.1.1: resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.3.tgz#42d837d5239688d55f303003a508230fa6727142" integrity sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw== +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + class-utils@^0.3.5: version "0.3.6" resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" @@ -1158,6 +1270,29 @@ core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= +create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.4: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" @@ -1268,11 +1403,33 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" +drbg.js@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/drbg.js/-/drbg.js-1.0.1.tgz#3e36b6c42b37043823cdbc332d58f31e2445480b" + integrity sha1-Pja2xCs3BDgjzbwzLVjzHiRFSAs= + dependencies: + browserify-aes "^1.0.6" + create-hash "^1.1.2" + create-hmac "^1.1.4" + electron-to-chromium@^1.3.295: version "1.3.296" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.296.tgz#a1d4322d742317945285d3ba88966561b67f3ac8" integrity sha512-s5hv+TSJSVRsxH190De66YHb50pBGTweT9XGWYu/LMR20KX6TsjFzObo36CjVAzM+PUeeKSBRtm/mISlCzeojQ== +elliptic@^6.4.1: + version "6.5.1" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.1.tgz#c380f5f909bf1b9b4428d028cd18d3b0efd6b52b" + integrity sha512-xvJINNLbTeWQjrl6X+7eQCrIy/YPv5XCpKW6kB5mKvtnGILoLDcySuwomfdzt0BMdLNVnuRNTuzKNHj0bva1Cg== + dependencies: + bn.js "^4.4.0" + brorand "^1.0.1" + hash.js "^1.0.0" + hmac-drbg "^1.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.0" + emoji-regex@^7.0.1: version "7.0.3" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" @@ -1283,6 +1440,16 @@ emoji-regex@^8.0.0: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== +err-code@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/err-code/-/err-code-1.1.2.tgz#06e0116d3028f6aef4806849eb0ea6a748ae6960" + integrity sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA= + +err-code@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.0.tgz#452dadddde12356b1dd5a85f33b28ddda377ef2a" + integrity sha512-MsMOijQ4v0xlmrz1fc7lyPEy7jFhoNF7EVaRSP7mPzs20LaFOwG6qNjGRy3Ie85n9DARlcUnB1zbsBv5sJrIvw== + es-abstract@^1.5.1: version "1.16.0" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.16.0.tgz#d3a26dc9c3283ac9750dca569586e976d9dcc06d" @@ -1414,6 +1581,14 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== +evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + expand-brackets@^2.1.4: version "2.1.4" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" @@ -1494,6 +1669,11 @@ file-entry-cache@^5.0.1: dependencies: flat-cache "^2.0.1" +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + fill-range@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" @@ -1724,11 +1904,36 @@ has@^1.0.1, has@^1.0.3: dependencies: function-bind "^1.1.1" +hash-base@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" + integrity sha1-X8hoaEfs1zSZQDMZprCj8/auSRg= + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + he@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== +hmac-drbg@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + iconv-lite@^0.4.24, iconv-lite@^0.4.4: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -1736,6 +1941,11 @@ iconv-lite@^0.4.24, iconv-lite@^0.4.4: dependencies: safer-buffer ">= 2.1.2 < 3" +ieee754@^1.1.4: + version "1.1.13" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84" + integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg== + ignore-walk@^3.0.1: version "3.0.3" resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.3.tgz#017e2447184bfeade7c238e4aefdd1e8f95b1e37" @@ -1769,7 +1979,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.3, inherits@~2.0.3: +inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -1950,6 +2160,11 @@ is-promise@^2.1.0: resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o= +is-promise@~1, is-promise@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-1.0.1.tgz#31573761c057e33c2e91aab9e96da08cefbe76e5" + integrity sha1-MVc3YcBX4zwukaq56W2gjO++duU= + is-regex@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" @@ -1979,6 +2194,14 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= +iso-random-stream@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/iso-random-stream/-/iso-random-stream-1.1.1.tgz#83824bba77fbb3480dd6b35fbb06de7f9e93e80f" + integrity sha512-YEt/7xOwTdu4KXIgtdgGFkiLUsBaddbnkmHyaFdjJYIcD7V4gpQHPvYC5tyh3kA0PQ01y9lWm1ruVdf8Mqzovg== + dependencies: + buffer "^5.4.3" + readable-stream "^3.4.0" + isobject@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" @@ -1996,6 +2219,11 @@ js-levenshtein@^1.1.3: resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d" integrity sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g== +js-sha3@~0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" + integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== + "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -2036,6 +2264,11 @@ json5@^2.1.0: dependencies: minimist "^1.2.0" +keypair@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/keypair/-/keypair-1.0.1.tgz#7603719270afb6564ed38a22087a06fc9aa4ea1b" + integrity sha1-dgNxknCvtlZO04oiCHoG/Jqk6hs= + kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" @@ -2068,6 +2301,39 @@ levn@^0.3.0, levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" +libp2p-crypto-secp256k1@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/libp2p-crypto-secp256k1/-/libp2p-crypto-secp256k1-0.4.0.tgz#337f8cf93f22c40c6d169ccf8a5b127bf402b856" + integrity sha512-/Ttz9IJskz2wlKGGPaS0/yWbQQRsY7OuqOkD57twSPiu9Vj66j4J/uxVvULj/6q3k+mIdACT6hZ9tR8tPrAD3Q== + dependencies: + bs58 "^4.0.1" + multihashing-async "^0.7.0" + nodeify "^1.0.1" + safe-buffer "^5.1.2" + secp256k1 "^3.6.2" + +libp2p-crypto@^0.17.1: + version "0.17.1" + resolved "https://registry.yarnpkg.com/libp2p-crypto/-/libp2p-crypto-0.17.1.tgz#20da30d133930e589d9b68057859c65ae677a7cf" + integrity sha512-IPz/rn8OtHY1Lae2teowSLw6UMqjkL0eM1fVOdPWRrB8fobDfPuwp67E3v7xGtarf6JSYpugsqTj89KEgbcBtw== + dependencies: + asmcrypto.js "^2.3.2" + asn1.js "^5.2.0" + bn.js "^5.0.0" + browserify-aes "^1.2.0" + bs58 "^4.0.1" + err-code "^1.1.2" + iso-random-stream "^1.1.0" + keypair "^1.0.1" + libp2p-crypto-secp256k1 "~0.4.0" + multihashing-async "~0.8.0" + node-forge "~0.9.1" + pem-jwk "^2.0.0" + protons "^1.0.1" + rsa-pem-to-jwk "^1.1.3" + tweetnacl "^1.0.1" + ursa-optional "~0.10.1" + locate-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" @@ -2120,6 +2386,15 @@ map-visit@^1.0.0: dependencies: object-visit "^1.0.0" +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + micromatch@^3.1.10, micromatch@^3.1.4: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" @@ -2144,6 +2419,16 @@ mimic-fn@^2.1.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= + minimatch@3.0.4, minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" @@ -2235,12 +2520,49 @@ ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +multihashes@~0.4.13, multihashes@~0.4.15: + version "0.4.15" + resolved "https://registry.yarnpkg.com/multihashes/-/multihashes-0.4.15.tgz#6dbc55f7f312c6782f5367c03c9783681589d8a6" + integrity sha512-G/Smj1GWqw1RQP3dRuRRPe3oyLqvPqUaEDIaoi7JF7Loxl4WAWvhJNk84oyDEodSucv0MmSW/ZT0RKUrsIFD3g== + dependencies: + bs58 "^4.0.1" + varint "^5.0.0" + +multihashing-async@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/multihashing-async/-/multihashing-async-0.7.0.tgz#3234fb98295be84386b85bfd20377d3e5be20d6b" + integrity sha512-SCbfl3f+DzJh+/5piukga9ofIOxwfT05t8R4jfzZIJ88YE9zU9+l3K2X+XB19MYyxqvyK9UJRNWbmQpZqQlbRA== + dependencies: + blakejs "^1.1.0" + buffer "^5.2.1" + err-code "^1.1.2" + js-sha3 "~0.8.0" + multihashes "~0.4.13" + murmurhash3js-revisited "^3.0.0" + +multihashing-async@~0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/multihashing-async/-/multihashing-async-0.8.0.tgz#a99049160be9bde6681fe93ef15e0e2496341d7d" + integrity sha512-t0iDSl1kkI65vaKmv9/bBM9/E/ogywB18+A9hI7QzcQjolue1tcaNWKdoFuniF6QQtNOJFplO4nQtLfQeK3lLw== + dependencies: + blakejs "^1.1.0" + buffer "^5.4.3" + err-code "^2.0.0" + js-sha3 "~0.8.0" + multihashes "~0.4.15" + murmurhash3js-revisited "^3.0.0" + +murmurhash3js-revisited@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/murmurhash3js-revisited/-/murmurhash3js-revisited-3.0.0.tgz#6bd36e25de8f73394222adc6e41fa3fac08a5869" + integrity sha512-/sF3ee6zvScXMb1XFJ8gDsSnY+X8PbOyjIuBhtgis10W2Jx4ZjIhikUCIF9c4gpJxVnQIsPAFrSwTCuAjicP6g== + mute-stream@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== -nan@^2.12.1: +nan@^2.12.1, nan@^2.14.0: version "2.14.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== @@ -2289,6 +2611,11 @@ node-environment-flags@1.0.5: object.getownpropertydescriptors "^2.0.3" semver "^5.7.0" +node-forge@~0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.9.1.tgz#775368e6846558ab6676858a4d8c6e8d16c677b5" + integrity sha512-G6RlQt5Sb4GMBzXvhfkeFmbqR6MzhtnT7VTHuLadjkii3rdYHNdw0m8zA4BTxVIh68FicCQ2NSUANpsqkr9jvQ== + node-modules-regexp@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" @@ -2317,6 +2644,14 @@ node-releases@^1.1.38: dependencies: semver "^6.3.0" +nodeify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/nodeify/-/nodeify-1.0.1.tgz#64ab69a7bdbaf03ce107b4f0335c87c0b9e91b1d" + integrity sha1-ZKtpp7268DzhB7TwM1yHwLnpGx0= + dependencies: + is-promise "~1.0.0" + promise "~1.3.0" + nopt@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" @@ -2365,6 +2700,11 @@ number-is-nan@^1.0.0: resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= +object-assign@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-2.1.1.tgz#43c36e5d569ff8e4816c4efa8be02d26967c18aa" + integrity sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo= + object-assign@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -2435,6 +2775,13 @@ onetime@^5.1.0: dependencies: mimic-fn "^2.1.0" +optimist@~0.3.5: + version "0.3.7" + resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.3.7.tgz#c90941ad59e4273328923074d2cf2e7cbc6ec0d9" + integrity sha1-yQlBrVnkJzMokjB00s8ufLxuwNk= + dependencies: + wordwrap "~0.0.2" + optionator@^0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" @@ -2535,6 +2882,13 @@ pathval@^1.1.0: resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.0.tgz#b942e6d4bde653005ef6b71361def8727d0645e0" integrity sha1-uULm1L3mUwBe9rcTYd74cn0GReA= +pem-jwk@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pem-jwk/-/pem-jwk-2.0.0.tgz#1c5bb264612fc391340907f5c1de60c06d22f085" + integrity sha512-rFxu7rVoHgQ5H9YsP50dDWf0rHjreVA2z0yPiWr5WdH/UHb29hKtF7h6l8vNd1cbYR1t0QL+JKhW55a2ZV4KtA== + dependencies: + asn1.js "^5.0.1" + pify@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" @@ -2579,6 +2933,28 @@ progress@^2.0.0: resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== +promise@~1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/promise/-/promise-1.3.0.tgz#e5cc9a4c8278e4664ffedc01c7da84842b040175" + integrity sha1-5cyaTIJ45GZP/twBx9qEhCsEAXU= + dependencies: + is-promise "~1" + +protocol-buffers-schema@^3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/protocol-buffers-schema/-/protocol-buffers-schema-3.3.2.tgz#00434f608b4e8df54c59e070efeefc37fb4bb859" + integrity sha512-Xdayp8sB/mU+sUV4G7ws8xtYMGdQnxbeIfLjyO9TZZRJdztBGhlmbI5x1qcY4TG5hBkIKGnc28i7nXxaugu88w== + +protons@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/protons/-/protons-1.0.1.tgz#1c107144c07fc2d1cb8b6cb76451e6a938237676" + integrity sha512-+0ZKnfVs+4c43tbAQ5j0Mck8wPcLnlxUYzKQoB4iDW4ocdXGnN4P+0dDbgX1FTpoY9+7P2Tn2scJyHHqj+S/lQ== + dependencies: + protocol-buffers-schema "^3.3.1" + safe-buffer "^5.1.1" + signed-varint "^2.0.1" + varint "^5.0.0" + punycode@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" @@ -2607,6 +2983,15 @@ readable-stream@^2.0.2, readable-stream@^2.0.6: string_decoder "~1.1.1" util-deprecate "~1.0.1" +readable-stream@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.4.0.tgz#a51c26754658e0a3c21dbf59163bd45ba6f447fc" + integrity sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + readdirp@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" @@ -2741,6 +3126,29 @@ rimraf@^2.6.1: dependencies: glob "^7.1.3" +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +rsa-pem-to-jwk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/rsa-pem-to-jwk/-/rsa-pem-to-jwk-1.1.3.tgz#245e76bdb7e7234cfee7ca032d31b54c38fab98e" + integrity sha1-JF52vbfnI0z+58oDLTG1TDj6uY4= + dependencies: + object-assign "^2.0.0" + rsa-unpack "0.0.6" + +rsa-unpack@0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/rsa-unpack/-/rsa-unpack-0.0.6.tgz#f50ebd56a628378e631f297161026ce9ab4eddba" + integrity sha1-9Q69VqYoN45jHylxYQJs6atO3bo= + dependencies: + optimist "~0.3.5" + run-async@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" @@ -2755,7 +3163,7 @@ rxjs@^6.4.0: dependencies: tslib "^1.9.0" -safe-buffer@^5.1.2: +safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== @@ -2782,6 +3190,20 @@ sax@^1.2.4: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== +secp256k1@^3.6.2: + version "3.7.1" + resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-3.7.1.tgz#12e473e0e9a7c2f2d4d4818e722ad0e14cc1e2f1" + integrity sha512-1cf8sbnRreXrQFdH6qsg2H71Xw91fCCS9Yp021GnUNJzWJS/py96fS4lHbnTnouLp08Xj6jBoBB6V78Tdbdu5g== + dependencies: + bindings "^1.5.0" + bip66 "^1.1.5" + bn.js "^4.11.8" + create-hash "^1.2.0" + drbg.js "^1.0.1" + elliptic "^6.4.1" + nan "^2.14.0" + safe-buffer "^5.1.2" + semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0, semver@^5.7.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" @@ -2807,6 +3229,14 @@ set-value@^2.0.0, set-value@^2.0.1: is-plain-object "^2.0.3" split-string "^3.0.1" +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" @@ -2824,6 +3254,13 @@ signal-exit@^3.0.0, signal-exit@^3.0.2: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= +signed-varint@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/signed-varint/-/signed-varint-2.0.1.tgz#50a9989da7c98c2c61dad119bc97470ef8528129" + integrity sha1-UKmYnafJjCxh2tEZvJdHDvhSgSk= + dependencies: + varint "~5.0.0" + slash@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" @@ -2973,6 +3410,13 @@ string.prototype.trimright@^2.1.0: define-properties "^1.1.3" function-bind "^1.1.1" +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" @@ -3107,6 +3551,11 @@ tsutils@^3.17.1: dependencies: tslib "^1.8.1" +tweetnacl@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.1.tgz#2594d42da73cd036bd0d2a54683dd35a6b55ca17" + integrity sha512-kcoMoKTPYnoeS50tzoqjPY3Uv9axeuuFAZY9M/9zFnhoVvRfxz9K29IMPD7jGmt2c8SW7i3gT9WqDl2+nV7p4A== + type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" @@ -3187,12 +3636,20 @@ urix@^0.1.0: resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= +ursa-optional@~0.10.1: + version "0.10.1" + resolved "https://registry.yarnpkg.com/ursa-optional/-/ursa-optional-0.10.1.tgz#847b9e40a358c41f2264a04d52bba1e92f159adc" + integrity sha512-/pgpBXVJut57dHNrdGF+1/qXi+5B7JrlmZDWPSyoivEcbwFWRZJBJGkWb6ivknMBA3bnFA7lqsb6iHiFfp79QQ== + dependencies: + bindings "^1.5.0" + nan "^2.14.0" + use@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== -util-deprecate@~1.0.1: +util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= @@ -3202,6 +3659,11 @@ v8-compile-cache@^2.0.3: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.0.tgz#e14de37b31a6d194f5690d67efc4e7f6fc6ab30e" integrity sha512-usZBT3PW+LOjM25wbqIlZwPeJV+3OSz3M1k1Ws8snlW39dZyYL9lOGC5FgPVHfk0jKmjiDV8Z0mIbVQPiwFs7g== +varint@^5.0.0, varint@~5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/varint/-/varint-5.0.0.tgz#d826b89f7490732fabc0c0ed693ed475dcb29ebf" + integrity sha1-2Ca4n3SQcy+rwMDtaT7Uddyynr8= + which-module@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" @@ -3221,6 +3683,11 @@ wide-align@1.1.3, wide-align@^1.1.0: dependencies: string-width "^1.0.2 || 2" +wordwrap@~0.0.2: + version "0.0.3" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + integrity sha1-o9XabNXAvAAI03I0u68b7WMFkQc= + wordwrap@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" From 175d8940be4527c938a66a9b91d9faa88b8d8ae0 Mon Sep 17 00:00:00 2001 From: morrigan Date: Fri, 1 Nov 2019 11:30:28 +0100 Subject: [PATCH 03/20] Add encryption methods --- package.json | 3 ++- src/xx.ts | 28 ++++++++++++++++++++++++++++ yarn.lock | 16 +++++++++++++++- 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 14549b0..50ffcde 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "dependencies": { "bn.js": "^5.0.0", "buffer": "^5.4.3", - "libp2p-crypto": "^0.17.1" + "libp2p-crypto": "^0.17.1", + "sodium-native": "^2.4.6" } } diff --git a/src/xx.ts b/src/xx.ts index c3b7238..05cd45c 100644 --- a/src/xx.ts +++ b/src/xx.ts @@ -1,6 +1,7 @@ import {bytes32, bytes16, uint32, uint64, bytes} from './types/basic' import { Buffer } from 'buffer'; import * as crypto from 'libp2p-crypto'; +import * as sodium from 'sodium-native'; type KeyPair = { publicKey: bytes32, @@ -60,11 +61,38 @@ class XXHandshake { return {ss, s, e, rs, re, psk}; } + incrementNonce(n: uint32) : uint32 { + return n + 1; + } + + encrypt(k: bytes32, n: uint32, ad: bytes, plaintext: bytes) : bytes { + const ElongatedNonce = sodium.sodium_malloc(sodium.crypto_aead_xchacha20poly1305_ietf_NPUBBYTES); // 12U ? + sodium.sodium_memzero(ElongatedNonce); + ElongatedNonce.set(n, 16); + + const clen = plaintext.length + sodium.crypto_aead_xchacha20poly1305_ietf_ABYTES; + const c = sodium.sodium_malloc(clen); + sodium.crypto_aead_xchacha20poly1305_ietf_encrypt(c, plaintext, ad, null, ElongatedNonce, k); + } + + // Cipher state related initializeKey(k: bytes32) : CipherState { const n = minNonce; return { k, n }; } + setNonce(cs: CipherState, nonce: uint32) { + cs.n = nonce; + } + + encryptWithAd(cs: CipherState, ad: bytes, plaintext: bytes) : bytes { + const e = this.encrypt(cs.k, cs.n, ad, plaintext); + this.setNonce(cs, this.incrementNonce(cs.n)); + return e; + } + + // Symmetric state related + async initializeSymmetric(protocolName: string) : Promise { const h = await this.hashProtocolName(protocolName); const ck = h; diff --git a/yarn.lock b/yarn.lock index 833871e..1fcce3b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1984,7 +1984,7 @@ inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -ini@~1.3.0: +ini@^1.3.5, ini@~1.3.0: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== @@ -2616,6 +2616,11 @@ node-forge@~0.9.1: resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.9.1.tgz#775368e6846558ab6676858a4d8c6e8d16c677b5" integrity sha512-G6RlQt5Sb4GMBzXvhfkeFmbqR6MzhtnT7VTHuLadjkii3rdYHNdw0m8zA4BTxVIh68FicCQ2NSUANpsqkr9jvQ== +node-gyp-build@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.1.1.tgz#d7270b5d86717068d114cc57fff352f96d745feb" + integrity sha512-dSq1xmcPDKPZ2EED2S6zw/b9NKsqzXRE6dVr8TVQnI3FJOTteUMuqF3Qqs6LZg+mLGYJWqQzMbIjMtJqTv87nQ== + node-modules-regexp@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" @@ -3305,6 +3310,15 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" +sodium-native@^2.4.6: + version "2.4.6" + resolved "https://registry.yarnpkg.com/sodium-native/-/sodium-native-2.4.6.tgz#8a8173095e8cf4f997de393a2ba106c34870cac2" + integrity sha512-Ro9lhTjot8M01nwKLXiqLSmjR7B8o+Wg4HmJUjEShw/q6XPlNMzjPkA1VJKaMH8SO8fJ/sggAKVwreTaFszS2Q== + dependencies: + ini "^1.3.5" + nan "^2.14.0" + node-gyp-build "^4.1.0" + source-map-resolve@^0.5.0: version "0.5.2" resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" From 1db460a44da3d52a5017a80995b8a654f05804b9 Mon Sep 17 00:00:00 2001 From: morrigan Date: Mon, 4 Nov 2019 14:31:58 +0100 Subject: [PATCH 04/20] Replace with aead from bcrypto --- package.json | 4 ++-- src/xx.ts | 17 +++++++++-------- yarn.lock | 43 +++++++++++++++++++++++++++---------------- 3 files changed, 38 insertions(+), 26 deletions(-) diff --git a/package.json b/package.json index 50ffcde..cd740d7 100644 --- a/package.json +++ b/package.json @@ -37,9 +37,9 @@ "plugins": [] }, "dependencies": { + "bcrypto": "^4.2.3", "bn.js": "^5.0.0", "buffer": "^5.4.3", - "libp2p-crypto": "^0.17.1", - "sodium-native": "^2.4.6" + "libp2p-crypto": "^0.17.1" } } diff --git a/src/xx.ts b/src/xx.ts index 05cd45c..17646c8 100644 --- a/src/xx.ts +++ b/src/xx.ts @@ -1,7 +1,7 @@ import {bytes32, bytes16, uint32, uint64, bytes} from './types/basic' import { Buffer } from 'buffer'; import * as crypto from 'libp2p-crypto'; -import * as sodium from 'sodium-native'; +import AEAD from 'bcrypto/aead-browser'; type KeyPair = { publicKey: bytes32, @@ -41,7 +41,7 @@ const emptyKey = Buffer.alloc(32) as bytes32; const minNonce = 0; class XXHandshake { - async initializeInitiator(prologue: bytes32, s: KeyPair, rs: bytes32, psk: bytes32) : Promise { + private async initializeInitiator(prologue: bytes32, s: KeyPair, rs: bytes32, psk: bytes32) : Promise { const e: KeyPair; const re: bytes32; const name = "Noise_XX_25519_ChaChaPoly_SHA256"; @@ -66,13 +66,14 @@ class XXHandshake { } encrypt(k: bytes32, n: uint32, ad: bytes, plaintext: bytes) : bytes { - const ElongatedNonce = sodium.sodium_malloc(sodium.crypto_aead_xchacha20poly1305_ietf_NPUBBYTES); // 12U ? - sodium.sodium_memzero(ElongatedNonce); - ElongatedNonce.set(n, 16); + const nonce = Buffer.alloc(12); + nonce.writeUInt32LE(n, 4); + const ctx = new AEAD(); + ctx.init(k, nonce); + ctx.aad(ad); + ctx.encrypt(plaintext); - const clen = plaintext.length + sodium.crypto_aead_xchacha20poly1305_ietf_ABYTES; - const c = sodium.sodium_malloc(clen); - sodium.crypto_aead_xchacha20poly1305_ietf_encrypt(c, plaintext, ad, null, ElongatedNonce, k); + return ctx.final(); } // Cipher state related diff --git a/yarn.lock b/yarn.lock index 1fcce3b..06bd243 100644 --- a/yarn.lock +++ b/yarn.lock @@ -950,6 +950,16 @@ base@^0.11.1: mixin-deep "^1.2.0" pascalcase "^0.1.1" +bcrypto@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/bcrypto/-/bcrypto-4.2.3.tgz#cb2cf5647168e39b2f57de1c0c2ae49bcaf6ae00" + integrity sha512-58Dh2LNHaNHJo/IKEEhYbqE59dl5C0p5xwR8qOI4ixmAO3rp35u0NTYyLUPuEf/CFqMLK/eusMWQeC4vY7l7uA== + dependencies: + bsert "~0.0.10" + bufio "~1.0.6" + loady "~0.0.1" + nan "^2.13.2" + binary-extensions@^1.0.0: version "1.13.1" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" @@ -1053,6 +1063,11 @@ bs58@^4.0.1: dependencies: base-x "^3.0.2" +bsert@~0.0.10: + version "0.0.10" + resolved "https://registry.yarnpkg.com/bsert/-/bsert-0.0.10.tgz#231ac82873a1418c6ade301ab5cd9ae385895597" + integrity sha512-NHNwlac+WPy4t2LoNh8pXk8uaIGH3NSaIUbTTRXGpE2WEbq0te/tDykYHkFK57YKLPjv/aGHmbqvnGeVWDz57Q== + buffer-from@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" @@ -1071,6 +1086,11 @@ buffer@^5.2.1, buffer@^5.4.3: base64-js "^1.0.2" ieee754 "^1.1.4" +bufio@~1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/bufio/-/bufio-1.0.6.tgz#e0eb6d70b2efcc997b6f8872173540967f90fa4d" + integrity sha512-mjYZFRHmI9bk3Oeexu0rWjHFY+w6hGLabdmwSFzq+EFr4MHHsNOYduDVdYl71NG5pTPL7GGzUCMk9cYuV34/Qw== + cache-base@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" @@ -1984,7 +2004,7 @@ inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -ini@^1.3.5, ini@~1.3.0: +ini@~1.3.0: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== @@ -2334,6 +2354,11 @@ libp2p-crypto@^0.17.1: tweetnacl "^1.0.1" ursa-optional "~0.10.1" +loady@~0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/loady/-/loady-0.0.1.tgz#24a99c14cfed9cd0bffed365b1836035303f7e5d" + integrity sha512-PW5Z13Jd0v6ZcA1P6ZVUc3EV8BJwQuAiwUvvT6VQGHoaZ1d/tu7r1QZctuKfQqwy9SFBWeAGfcIdLxhp7ZW3Rw== + locate-path@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" @@ -2562,7 +2587,7 @@ mute-stream@0.0.8: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== -nan@^2.12.1, nan@^2.14.0: +nan@^2.12.1, nan@^2.13.2, nan@^2.14.0: version "2.14.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== @@ -2616,11 +2641,6 @@ node-forge@~0.9.1: resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.9.1.tgz#775368e6846558ab6676858a4d8c6e8d16c677b5" integrity sha512-G6RlQt5Sb4GMBzXvhfkeFmbqR6MzhtnT7VTHuLadjkii3rdYHNdw0m8zA4BTxVIh68FicCQ2NSUANpsqkr9jvQ== -node-gyp-build@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.1.1.tgz#d7270b5d86717068d114cc57fff352f96d745feb" - integrity sha512-dSq1xmcPDKPZ2EED2S6zw/b9NKsqzXRE6dVr8TVQnI3FJOTteUMuqF3Qqs6LZg+mLGYJWqQzMbIjMtJqTv87nQ== - node-modules-regexp@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" @@ -3310,15 +3330,6 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" -sodium-native@^2.4.6: - version "2.4.6" - resolved "https://registry.yarnpkg.com/sodium-native/-/sodium-native-2.4.6.tgz#8a8173095e8cf4f997de393a2ba106c34870cac2" - integrity sha512-Ro9lhTjot8M01nwKLXiqLSmjR7B8o+Wg4HmJUjEShw/q6XPlNMzjPkA1VJKaMH8SO8fJ/sggAKVwreTaFszS2Q== - dependencies: - ini "^1.3.5" - nan "^2.14.0" - node-gyp-build "^4.1.0" - source-map-resolve@^0.5.0: version "0.5.2" resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" From 37215d7a3cee7f14683817699c0ef4f5383dfbd0 Mon Sep 17 00:00:00 2001 From: morrigan Date: Mon, 4 Nov 2019 14:38:01 +0100 Subject: [PATCH 05/20] use function visibility --- src/xx.ts | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/xx.ts b/src/xx.ts index 17646c8..7ff520f 100644 --- a/src/xx.ts +++ b/src/xx.ts @@ -51,7 +51,7 @@ class XXHandshake { return {ss, s, e, rs, re, psk}; } - async initializeResponder(prologue: bytes32, s: KeyPair, rs: bytes32, psk: bytes32) : Promise { + private async initializeResponder(prologue: bytes32, s: KeyPair, rs: bytes32, psk: bytes32) : Promise { const e: KeyPair; const re: bytes32; const name = "Noise_XX_25519_ChaChaPoly_SHA256"; @@ -61,11 +61,11 @@ class XXHandshake { return {ss, s, e, rs, re, psk}; } - incrementNonce(n: uint32) : uint32 { + private incrementNonce(n: uint32) : uint32 { return n + 1; } - encrypt(k: bytes32, n: uint32, ad: bytes, plaintext: bytes) : bytes { + private encrypt(k: bytes32, n: uint32, ad: bytes, plaintext: bytes) : bytes { const nonce = Buffer.alloc(12); nonce.writeUInt32LE(n, 4); const ctx = new AEAD(); @@ -77,16 +77,16 @@ class XXHandshake { } // Cipher state related - initializeKey(k: bytes32) : CipherState { + private initializeKey(k: bytes32) : CipherState { const n = minNonce; return { k, n }; } - setNonce(cs: CipherState, nonce: uint32) { + private setNonce(cs: CipherState, nonce: uint32) { cs.n = nonce; } - encryptWithAd(cs: CipherState, ad: bytes, plaintext: bytes) : bytes { + private encryptWithAd(cs: CipherState, ad: bytes, plaintext: bytes) : bytes { const e = this.encrypt(cs.k, cs.n, ad, plaintext); this.setNonce(cs, this.incrementNonce(cs.n)); return e; @@ -94,7 +94,7 @@ class XXHandshake { // Symmetric state related - async initializeSymmetric(protocolName: string) : Promise { + private async initializeSymmetric(protocolName: string) : Promise { const h = await this.hashProtocolName(protocolName); const ck = h; const cs = this.initializeKey(emptyKey); @@ -102,27 +102,27 @@ class XXHandshake { return { cs, ck, h }; } - async hashProtocolName(protocolName: string) : Promise { + private async hashProtocolName(protocolName: string) : Promise { if (protocolName.length <= 32) { return new Promise(resolve => { - const h = new Buffer(32); + const h = Buffer.alloc(32); h.write(protocolName); resolve(h) }); } else { - return await this.getHash(Buffer.from(protocolName), new Buffer([])); + return await this.getHash(Buffer.from(protocolName, 'utf-8'), Buffer.from([])); } } - async mixHash(ss: SymmetricState, data: bytes) { + private async mixHash(ss: SymmetricState, data: bytes) { ss.h = await this.getHash(ss.h, data); } - async getHash(a: bytes, b: bytes) : Promise { + private async getHash(a: bytes, b: bytes) : Promise { return await crypto.hmac.create('sha256', Buffer.from([...a, ...b])) } - async initSession(initiator: boolean, prologue: bytes32[], s: KeyPair, rs: bytes32) : Promise { + public async initSession(initiator: boolean, prologue: bytes32[], s: KeyPair, rs: bytes32) : Promise { let session: NoiseSession; const psk = emptyKey; From e4b5c068db912e230dfd06230839db487b799548 Mon Sep 17 00:00:00 2001 From: morrigan Date: Mon, 4 Nov 2019 15:10:14 +0100 Subject: [PATCH 06/20] Address some PR comments --- src/xx.ts | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/src/xx.ts b/src/xx.ts index 7ff520f..9a2fc75 100644 --- a/src/xx.ts +++ b/src/xx.ts @@ -3,7 +3,7 @@ import { Buffer } from 'buffer'; import * as crypto from 'libp2p-crypto'; import AEAD from 'bcrypto/aead-browser'; -type KeyPair = { +interface KeyPair { publicKey: bytes32, privateKey: bytes32, } @@ -37,13 +37,16 @@ type NoiseSession = { i: boolean, } -const emptyKey = Buffer.alloc(32) as bytes32; const minNonce = 0; class XXHandshake { + private createEmptyKey() : bytes32 { + return Buffer.alloc(32); + } + private async initializeInitiator(prologue: bytes32, s: KeyPair, rs: bytes32, psk: bytes32) : Promise { - const e: KeyPair; - const re: bytes32; + let e: KeyPair; + let re: bytes32; const name = "Noise_XX_25519_ChaChaPoly_SHA256"; const ss = await this.initializeSymmetric(name); await this.mixHash(ss, prologue); @@ -52,8 +55,8 @@ class XXHandshake { } private async initializeResponder(prologue: bytes32, s: KeyPair, rs: bytes32, psk: bytes32) : Promise { - const e: KeyPair; - const re: bytes32; + let e: KeyPair; + let re: bytes32; const name = "Noise_XX_25519_ChaChaPoly_SHA256"; const ss = await this.initializeSymmetric(name); await this.mixHash(ss, prologue); @@ -95,22 +98,24 @@ class XXHandshake { // Symmetric state related private async initializeSymmetric(protocolName: string) : Promise { - const h = await this.hashProtocolName(protocolName); + const protocolNameBytes: bytes = Buffer.from(protocolName, 'utf-8'); + const h = await this.hashProtocolName(protocolNameBytes); const ck = h; - const cs = this.initializeKey(emptyKey); + const key = this.createEmptyKey(); + const cs = this.initializeKey(key); return { cs, ck, h }; } - private async hashProtocolName(protocolName: string) : Promise { + private async hashProtocolName(protocolName: bytes) : Promise { if (protocolName.length <= 32) { return new Promise(resolve => { const h = Buffer.alloc(32); - h.write(protocolName); + protocolName.copy(h); resolve(h) }); } else { - return await this.getHash(Buffer.from(protocolName, 'utf-8'), Buffer.from([])); + return await this.getHash(protocolName, Buffer.from([])); } } @@ -124,7 +129,7 @@ class XXHandshake { public async initSession(initiator: boolean, prologue: bytes32[], s: KeyPair, rs: bytes32) : Promise { let session: NoiseSession; - const psk = emptyKey; + const psk = this.createEmptyKey(); if (initiator) { session.hs = await this.initializeInitiator(prologue, s, rs, psk); From c542b53a4bd1673d8df07239723de9b6d2e7c158 Mon Sep 17 00:00:00 2001 From: morrigan Date: Mon, 4 Nov 2019 15:19:40 +0100 Subject: [PATCH 07/20] Add decryption methods --- src/xx.ts | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/xx.ts b/src/xx.ts index 9a2fc75..0ac75b5 100644 --- a/src/xx.ts +++ b/src/xx.ts @@ -39,7 +39,7 @@ type NoiseSession = { const minNonce = 0; -class XXHandshake { +export class XXHandshake { private createEmptyKey() : bytes32 { return Buffer.alloc(32); } @@ -68,9 +68,15 @@ class XXHandshake { return n + 1; } - private encrypt(k: bytes32, n: uint32, ad: bytes, plaintext: bytes) : bytes { + private convertNonce(n: uint32) : bytes { const nonce = Buffer.alloc(12); nonce.writeUInt32LE(n, 4); + + return nonce; + } + + private encrypt(k: bytes32, n: uint32, ad: bytes, plaintext: bytes) : bytes { + const nonce = this.convertNonce(n); const ctx = new AEAD(); ctx.init(k, nonce); ctx.aad(ad); @@ -79,6 +85,17 @@ class XXHandshake { return ctx.final(); } + private decrypt(k: bytes32, n: uint32, ad: bytes, ciphertext: bytes) : bytes { + const nonce = this.convertNonce(n); + const ctx = new AEAD(); + + ctx.init(k, nonce); + ctx.aad(ad); + ctx.decrypt(ciphertext); + + return ctx.final(); + } + // Cipher state related private initializeKey(k: bytes32) : CipherState { const n = minNonce; @@ -95,6 +112,13 @@ class XXHandshake { return e; } + private decryptWithAd(cs: CipherState, ad: bytes, ciphertext: bytes) : bytes { + const plaintext = this.decrypt(cs.k, cs.n, ad, ciphertext); + this.setNonce(cs, this.incrementNonce(cs.n)); + + return plaintext; + } + // Symmetric state related private async initializeSymmetric(protocolName: string) : Promise { From 0132590829d575fa09fe0136ac8fe92edead9fb7 Mon Sep 17 00:00:00 2001 From: morrigan Date: Mon, 4 Nov 2019 17:06:31 +0100 Subject: [PATCH 08/20] Write test and resolve babel and ts compilation --- package.json | 8 ++++++-- src/xx.ts | 12 ++++++++---- test/xx.test.ts | 24 ++++++++++++++++++++++++ tsconfig.json | 8 +++++--- yarn.lock | 26 ++++++++++++++++++++++++-- 5 files changed, 67 insertions(+), 11 deletions(-) create mode 100644 test/xx.test.ts diff --git a/package.json b/package.json index cd740d7..a65556d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "js-libp2p-noise", "version": "1.0.0", - "main": "index.js", + "main": "index", "repository": "git@github.com:NodeFactoryIo/js-libp2p-noise.git", "author": "NodeFactory ", "license": "MIT", @@ -16,9 +16,11 @@ "devDependencies": { "@babel/cli": "^7.6.4", "@babel/core": "^7.6.4", + "@babel/plugin-transform-runtime": "^7.6.2", "@babel/preset-env": "^7.6.3", "@babel/preset-typescript": "^7.6.0", "@babel/register": "^7.6.2", + "@babel/runtime": "^7.6.3", "@types/chai": "^4.2.4", "@types/mocha": "^5.2.7", "@typescript-eslint/eslint-plugin": "^2.6.0", @@ -34,7 +36,9 @@ "@babel/preset-env", "@babel/preset-typescript" ], - "plugins": [] + "plugins": [ + "@babel/plugin-transform-runtime" + ] }, "dependencies": { "bcrypto": "^4.2.3", diff --git a/src/xx.ts b/src/xx.ts index 0ac75b5..afd5097 100644 --- a/src/xx.ts +++ b/src/xx.ts @@ -1,9 +1,9 @@ import {bytes32, bytes16, uint32, uint64, bytes} from './types/basic' import { Buffer } from 'buffer'; import * as crypto from 'libp2p-crypto'; -import AEAD from 'bcrypto/aead-browser'; +import AEAD from 'bcrypto'; -interface KeyPair { +export interface KeyPair { publicKey: bytes32, privateKey: bytes32, } @@ -51,6 +51,7 @@ export class XXHandshake { const ss = await this.initializeSymmetric(name); await this.mixHash(ss, prologue); + // @ts-ignore-next-line return {ss, s, e, rs, re, psk}; } @@ -61,6 +62,7 @@ export class XXHandshake { const ss = await this.initializeSymmetric(name); await this.mixHash(ss, prologue); + // @ts-ignore-next-line return {ss, s, e, rs, re, psk}; } @@ -151,8 +153,10 @@ export class XXHandshake { return await crypto.hmac.create('sha256', Buffer.from([...a, ...b])) } - public async initSession(initiator: boolean, prologue: bytes32[], s: KeyPair, rs: bytes32) : Promise { - let session: NoiseSession; + public async initSession(initiator: boolean, prologue: bytes32, s: KeyPair, rs: bytes32) : Promise { + // TODO: Create noisesession object/class + // @ts-ignore-next-line + let session: NoiseSession = {}; const psk = this.createEmptyKey(); if (initiator) { diff --git a/test/xx.test.ts b/test/xx.test.ts new file mode 100644 index 0000000..5fd43b4 --- /dev/null +++ b/test/xx.test.ts @@ -0,0 +1,24 @@ +import { expect } from "chai"; +import { Buffer } from 'buffer'; +import * as crypto from 'libp2p-crypto'; + +import { XXHandshake, KeyPair } from "../src/xx"; + +// TODO: Move this to some protocol related file +async function generateKeypair() : Promise { + return await crypto.keys.generateKeyPair('ed25519'); +} + +describe("Index", () => { + const prologue = Buffer.from("/noise", "utf-8"); + + it("Test creating new XX session", async () => { + const kpInitiator: KeyPair = await generateKeypair(); + const kpResponder: KeyPair = await generateKeypair(); + + const xx = new XXHandshake(); + + const session = await xx.initSession(true, prologue, kpInitiator, kpResponder.publicKey); + console.log(session) + }) +}); diff --git a/tsconfig.json b/tsconfig.json index dd6aa73..f2a3ef9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,13 +4,15 @@ "module": "commonjs", "strict": true, "esModuleInterop": true, + "noImplicitAny": false, "typeRoots": [ "./node_modules/@types" - ], - "include": [ - "./node_modules/bn.js-typings/index.d.ts" ] }, + "include": [ + "**/src/**/*.ts", + "./node_modules/bn.js-typings/index.d.ts" + ], "exclude": [ "node_modules" ] diff --git a/yarn.lock b/yarn.lock index 06bd243..4d57bf8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -538,6 +538,16 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" +"@babel/plugin-transform-runtime@^7.6.2": + version "7.6.2" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.6.2.tgz#2669f67c1fae0ae8d8bf696e4263ad52cb98b6f8" + integrity sha512-cqULw/QB4yl73cS5Y0TZlQSjDvNkzDbu0FurTZyHlJpWE5T3PCMdnyV+xXoH1opr1ldyHODe3QAX3OMAii5NxA== + dependencies: + "@babel/helper-module-imports" "^7.0.0" + "@babel/helper-plugin-utils" "^7.0.0" + resolve "^1.8.1" + semver "^5.5.1" + "@babel/plugin-transform-shorthand-properties@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz#6333aee2f8d6ee7e28615457298934a3b46198f0" @@ -668,6 +678,13 @@ pirates "^4.0.0" source-map-support "^0.5.9" +"@babel/runtime@^7.6.3": + version "7.6.3" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.6.3.tgz#935122c74c73d2240cafd32ddb5fc2a6cd35cf1f" + integrity sha512-kq6anf9JGjW8Nt5rYfEuGRaEAaH1mkv3Bbu6rYvLOpPh/RusSJXuKPEAoZ7L7gybZkchE8+NV5g9vKF4AGAtsA== + dependencies: + regenerator-runtime "^0.13.2" + "@babel/template@^7.1.0", "@babel/template@^7.4.4", "@babel/template@^7.6.0": version "7.6.0" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.6.0.tgz#7f0159c7f5012230dad64cca42ec9bdb5c9536e6" @@ -3038,6 +3055,11 @@ regenerate@^1.4.0: resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11" integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg== +regenerator-runtime@^0.13.2: + version "0.13.3" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz#7cf6a77d8f5c6f60eb73c5fc1955b2ceb01e6bf5" + integrity sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw== + regenerator-transform@^0.14.0: version "0.14.1" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.1.tgz#3b2fce4e1ab7732c08f665dfdb314749c7ddd2fb" @@ -3117,7 +3139,7 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@^1.3.2: +resolve@^1.3.2, resolve@^1.8.1: version "1.12.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.12.0.tgz#3fc644a35c84a48554609ff26ec52b66fa577df6" integrity sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w== @@ -3229,7 +3251,7 @@ secp256k1@^3.6.2: nan "^2.14.0" safe-buffer "^5.1.2" -semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0, semver@^5.7.0: +semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^5.7.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== From 7456e0c32c43f91631b48f22300c2e317ca88ec2 Mon Sep 17 00:00:00 2001 From: morrigan Date: Mon, 4 Nov 2019 21:34:12 +0100 Subject: [PATCH 09/20] Write messaging functions --- src/xx.ts | 136 ++++++++++++++++++++++++++++++++++++++++++++++-- test/xx.test.ts | 13 ++--- 2 files changed, 136 insertions(+), 13 deletions(-) diff --git a/src/xx.ts b/src/xx.ts index afd5097..b80601e 100644 --- a/src/xx.ts +++ b/src/xx.ts @@ -1,13 +1,19 @@ import {bytes32, bytes16, uint32, uint64, bytes} from './types/basic' import { Buffer } from 'buffer'; import * as crypto from 'libp2p-crypto'; -import AEAD from 'bcrypto'; +import { AEAD, x25519, HKDF } from 'bcrypto'; export interface KeyPair { publicKey: bytes32, privateKey: bytes32, } +interface MessageBuffer { + ne: bytes32, + ns: bytes, + ciphertext: bytes +} + type CipherState = { k: bytes32, n: uint32, @@ -15,8 +21,8 @@ type CipherState = { type SymmetricState = { cs: CipherState, - ck: bytes32, - h: bytes32, + ck: bytes32, // chaining key + h: bytes32, // handshake hash } type HandshakeState = { @@ -32,7 +38,7 @@ type NoiseSession = { hs: HandshakeState, h: bytes32, cs1: CipherState, - c2: CipherState, + cs2: CipherState, mc: uint64, i: boolean, } @@ -70,6 +76,10 @@ export class XXHandshake { return n + 1; } + private dh(privateKey: bytes32, publicKey: bytes32) : bytes32 { + return x25519.derive(privateKey, publicKey); + } + private convertNonce(n: uint32) : bytes { const nonce = Buffer.alloc(12); nonce.writeUInt32LE(n, 4); @@ -98,12 +108,21 @@ export class XXHandshake { return ctx.final(); } + private isEmptyKey(k: bytes32) : boolean { + const emptyKey = this.createEmptyKey(); + return emptyKey.equals(k); + } + // Cipher state related private initializeKey(k: bytes32) : CipherState { const n = minNonce; return { k, n }; } + private hasKey(cs: CipherState) : boolean { + return !this.isEmptyKey(cs.k); + } + private setNonce(cs: CipherState, nonce: uint32) { cs.n = nonce; } @@ -133,6 +152,12 @@ export class XXHandshake { return { cs, ck, h }; } + private mixKey(ss: SymmetricState, ikm: bytes32) { + const [ ck, tempK ] = this.getHkdf(ss.ck, ikm); + ss.cs = this.initializeKey(tempK); + ss.ck = ck; + } + private async hashProtocolName(protocolName: bytes) : Promise { if (protocolName.length <= 32) { return new Promise(resolve => { @@ -145,6 +170,18 @@ export class XXHandshake { } } + private getHkdf(ck: bytes32, ikm: bytes) : Array { + const info = Buffer.alloc(0); + const prk = HKDF.extract('SHA256', ikm, ck); + const okm = HKDF.expand('SHA256', prk, info, ikm.length); + + const k1 = okm.slice(0, 16); + const k2 = okm.slice(16, 32); + const k3 = okm.slice(32, 64); + + return [ k1, k2, k3 ]; + } + private async mixHash(ss: SymmetricState, data: bytes) { ss.h = await this.getHash(ss.h, data); } @@ -153,6 +190,72 @@ export class XXHandshake { return await crypto.hmac.create('sha256', Buffer.from([...a, ...b])) } + private async encryptAndHash(ss: SymmetricState, plaintext: bytes) : Promise { + let ciphertext; + if (this.hasKey(ss.cs)) { + ciphertext = this.encryptWithAd(ss.cs, ss.h, plaintext); + } else { + ciphertext = plaintext; + } + + await this.mixHash(ss, ciphertext); + return ciphertext; + } + + private split (ss: SymmetricState) { + const [ tempk1, tempk2 ] = this.getHkdf(ss.ck, Buffer.alloc(0)); + const cs1 = this.initializeKey(tempk1); + const cs2 = this.initializeKey(tempk2); + + return { cs1, cs2 }; + } + + private async writeMessageA(hs: HandshakeState, payload: bytes) : Promise { + let ns = Buffer.alloc(0); + hs.e = await this.generateKeypair(); + const ne = hs.e.publicKey; + await this.mixHash(hs.ss, ne); + const ciphertext = await this.encryptAndHash(hs.ss, payload); + + return {ne, ns, ciphertext} as MessageBuffer; + } + + private async writeMessageB(hs: HandshakeState, payload: bytes) : Promise { + hs.e = await this.generateKeypair(); + const ne = hs.e.publicKey; + await this.mixKey(hs.ss, this.dh(hs.e.privateKey, hs.re)); + const spk = Buffer.alloc(hs.s.publicKey.length); + const ns = await this.encryptAndHash(hs.ss, spk); + this.mixKey(hs.ss, this.dh(hs.s.privateKey, hs.re)); + const ciphertext = await this.encryptAndHash(hs.ss, payload); + + return { ne, ns, ciphertext }; + } + + private async writeMessageC(hs: HandshakeState, payload: bytes) { + const spk = hs.s.publicKey; + const ns = await this.encryptAndHash(hs.ss, spk); + this.mixKey(hs.ss, this.dh(hs.s.privateKey, hs.re)); + const ciphertext = await this.encryptAndHash(hs.ss, payload); + const ne = this.createEmptyKey(); + const messageBuffer: MessageBuffer = {ne, ns, ciphertext}; + const { cs1, cs2 } = this.split(hs.ss); + + return { h: hs.ss.h, messageBuffer, cs1, cs2 }; + } + + private async writeMessageRegular(cs: CipherState, payload: bytes) : Promise { + const ciphertext = this.encryptWithAd(cs, Buffer.alloc(0), payload); + const ne = this.createEmptyKey(); + const ns = Buffer.alloc(0); + + return { ne, ns, ciphertext }; + } + + public async generateKeypair() : Promise { + return await crypto.keys.generateKeyPair('ed25519'); + } + public async initSession(initiator: boolean, prologue: bytes32, s: KeyPair, rs: bytes32) : Promise { // TODO: Create noisesession object/class // @ts-ignore-next-line @@ -169,4 +272,29 @@ export class XXHandshake { session.mc = 0; return session; } + + public async sendMessage(session: NoiseSession, message: bytes) : Promise { + let messageBuffer: MessageBuffer = {} as MessageBuffer; + if (session.mc === 0) { + messageBuffer = await this.writeMessageA(session.hs, message); + } else if (session.mc === 1) { + messageBuffer = await this.writeMessageB(session.hs, message); + } else if (session.mc === 2) { + const { h, messageBuffer, cs1, cs2 } = await this.writeMessageC(session.hs, message); + session.h = h; + session.cs1 = cs1; + session.cs2 = cs2; + } else if (session.mc > 2) { + if (session.i) { + messageBuffer = await this.writeMessageRegular(session.cs1, message); + } else { + messageBuffer = await this.writeMessageRegular(session.cs2, message); + } + } else { + throw new Error("Session invalid.") + } + + session.mc++; + return messageBuffer; + } } diff --git a/test/xx.test.ts b/test/xx.test.ts index 5fd43b4..96dd529 100644 --- a/test/xx.test.ts +++ b/test/xx.test.ts @@ -1,23 +1,18 @@ import { expect } from "chai"; import { Buffer } from 'buffer'; -import * as crypto from 'libp2p-crypto'; import { XXHandshake, KeyPair } from "../src/xx"; -// TODO: Move this to some protocol related file -async function generateKeypair() : Promise { - return await crypto.keys.generateKeyPair('ed25519'); -} - describe("Index", () => { const prologue = Buffer.from("/noise", "utf-8"); it("Test creating new XX session", async () => { - const kpInitiator: KeyPair = await generateKeypair(); - const kpResponder: KeyPair = await generateKeypair(); - const xx = new XXHandshake(); + const kpInitiator: KeyPair = await xx.generateKeypair(); + const kpResponder: KeyPair = await xx.generateKeypair(); + + const session = await xx.initSession(true, prologue, kpInitiator, kpResponder.publicKey); console.log(session) }) From fdfadfa794604512846aed2d3b2d21345a7afdf1 Mon Sep 17 00:00:00 2001 From: morrigan Date: Mon, 4 Nov 2019 22:09:42 +0100 Subject: [PATCH 10/20] Address PR comments --- package.json | 2 +- src/xx.ts | 36 +++++++++++++++--------------------- tsconfig.json | 6 +++--- 3 files changed, 19 insertions(+), 25 deletions(-) diff --git a/package.json b/package.json index a65556d..8775f27 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "js-libp2p-noise", "version": "1.0.0", - "main": "index", + "main": "dist/index.js", "repository": "git@github.com:NodeFactoryIo/js-libp2p-noise.git", "author": "NodeFactory ", "license": "MIT", diff --git a/src/xx.ts b/src/xx.ts index b80601e..e59f4bd 100644 --- a/src/xx.ts +++ b/src/xx.ts @@ -28,17 +28,17 @@ type SymmetricState = { type HandshakeState = { ss: SymmetricState, s: KeyPair, - e: KeyPair, + e?: KeyPair, rs: bytes32, - re: bytes32, + re?: bytes32, psk: bytes32, } type NoiseSession = { hs: HandshakeState, - h: bytes32, - cs1: CipherState, - cs2: CipherState, + h?: bytes32, + cs1?: CipherState, + cs2?: CipherState, mc: uint64, i: boolean, } @@ -51,25 +51,19 @@ export class XXHandshake { } private async initializeInitiator(prologue: bytes32, s: KeyPair, rs: bytes32, psk: bytes32) : Promise { - let e: KeyPair; - let re: bytes32; const name = "Noise_XX_25519_ChaChaPoly_SHA256"; const ss = await this.initializeSymmetric(name); await this.mixHash(ss, prologue); - // @ts-ignore-next-line - return {ss, s, e, rs, re, psk}; + return { ss, s, rs, psk }; } private async initializeResponder(prologue: bytes32, s: KeyPair, rs: bytes32, psk: bytes32) : Promise { - let e: KeyPair; - let re: bytes32; const name = "Noise_XX_25519_ChaChaPoly_SHA256"; const ss = await this.initializeSymmetric(name); await this.mixHash(ss, prologue); - // @ts-ignore-next-line - return {ss, s, e, rs, re, psk}; + return { ss, s, rs, psk }; } private incrementNonce(n: uint32) : uint32 { @@ -257,20 +251,20 @@ export class XXHandshake { } public async initSession(initiator: boolean, prologue: bytes32, s: KeyPair, rs: bytes32) : Promise { - // TODO: Create noisesession object/class - // @ts-ignore-next-line - let session: NoiseSession = {}; const psk = this.createEmptyKey(); + let hs; if (initiator) { - session.hs = await this.initializeInitiator(prologue, s, rs, psk); + hs = await this.initializeInitiator(prologue, s, rs, psk); } else { - session.hs = await this.initializeResponder(prologue, s, rs, psk); + hs = await this.initializeResponder(prologue, s, rs, psk); } - session.i = initiator; - session.mc = 0; - return session; + return { + hs, + i: initiator, + mc: 0 + }; } public async sendMessage(session: NoiseSession, message: bytes) : Promise { diff --git a/tsconfig.json b/tsconfig.json index f2a3ef9..fccc322 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,12 +6,12 @@ "esModuleInterop": true, "noImplicitAny": false, "typeRoots": [ - "./node_modules/@types" + "./node_modules/@types", + "./node_modules/bn.js-typings/index.d.ts" ] }, "include": [ - "**/src/**/*.ts", - "./node_modules/bn.js-typings/index.d.ts" + "**/src/**/*.ts" ], "exclude": [ "node_modules" From 75dbfeff8ce1f2e6f43eb33c3de975c81bdb3444 Mon Sep 17 00:00:00 2001 From: morrigan Date: Mon, 4 Nov 2019 22:37:43 +0100 Subject: [PATCH 11/20] Fix --- src/xx.ts | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/src/xx.ts b/src/xx.ts index e59f4bd..2709f25 100644 --- a/src/xx.ts +++ b/src/xx.ts @@ -30,7 +30,7 @@ type HandshakeState = { s: KeyPair, e?: KeyPair, rs: bytes32, - re?: bytes32, + re: bytes32, psk: bytes32, } @@ -54,16 +54,18 @@ export class XXHandshake { const name = "Noise_XX_25519_ChaChaPoly_SHA256"; const ss = await this.initializeSymmetric(name); await this.mixHash(ss, prologue); + const re = Buffer.alloc(32); - return { ss, s, rs, psk }; + return { ss, s, rs, psk, re }; } private async initializeResponder(prologue: bytes32, s: KeyPair, rs: bytes32, psk: bytes32) : Promise { const name = "Noise_XX_25519_ChaChaPoly_SHA256"; const ss = await this.initializeSymmetric(name); await this.mixHash(ss, prologue); + const re = Buffer.alloc(32); - return { ss, s, rs, psk }; + return { ss, s, rs, psk, re }; } private incrementNonce(n: uint32) : uint32 { @@ -154,11 +156,9 @@ export class XXHandshake { private async hashProtocolName(protocolName: bytes) : Promise { if (protocolName.length <= 32) { - return new Promise(resolve => { - const h = Buffer.alloc(32); - protocolName.copy(h); - resolve(h) - }); + const h = Buffer.alloc(32); + protocolName.copy(h); + return Promise.resolve(h) } else { return await this.getHash(protocolName, Buffer.from([])); } @@ -280,8 +280,16 @@ export class XXHandshake { session.cs2 = cs2; } else if (session.mc > 2) { if (session.i) { + if (!session.cs1) { + throw new Error("CS1 (cipher state) is not defined") + } + messageBuffer = await this.writeMessageRegular(session.cs1, message); } else { + if (!session.cs2) { + throw new Error("CS2 (cipher state) is not defined") + } + messageBuffer = await this.writeMessageRegular(session.cs2, message); } } else { From ded3cfe5bc3954f6ae1e43b3f6ebc698af585eab Mon Sep 17 00:00:00 2001 From: morrigan Date: Tue, 5 Nov 2019 09:51:24 +0100 Subject: [PATCH 12/20] Add decryption functions --- src/xx.ts | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) diff --git a/src/xx.ts b/src/xx.ts index 2709f25..6bfcd04 100644 --- a/src/xx.ts +++ b/src/xx.ts @@ -196,6 +196,18 @@ export class XXHandshake { return ciphertext; } + private async decryptAndHash(ss: SymmetricState, ciphertext: bytes) : Promise { + let plaintext; + if (this.hasKey(ss.cs)) { + plaintext = this.decryptWithAd(ss.cs, ss.h, ciphertext); + } else { + plaintext = ciphertext; + } + + await this.mixHash(ss, ciphertext); + return plaintext; + } + private split (ss: SymmetricState) { const [ tempk1, tempk2 ] = this.getHkdf(ss.ck, Buffer.alloc(0)); const cs1 = this.initializeKey(tempk1); @@ -246,6 +258,46 @@ export class XXHandshake { return { ne, ns, ciphertext }; } + private async readMessageA(hs: HandshakeState, message: MessageBuffer) : Promise { + // TODO: validate public key here + + await this.mixHash(hs.ss, hs.re); + return await this.decryptAndHash(hs.ss, message.ciphertext); + } + + private async readMessageB(hs: HandshakeState, message: MessageBuffer) : Promise { + // TODO: validate public key here + + await this.mixHash(hs.ss, hs.re); + if (!hs.e) { + throw new Error("Handshake state `e` param is missing."); + } + this.mixKey(hs.ss, this.dh(hs.e.privateKey, hs.re)); + const ns = await this.decryptAndHash(hs.ss, message.ns); + // TODO: validate ns here as public key + hs.rs = ns; + this.mixKey(hs.ss, this.dh(hs.e.privateKey, hs.rs)); + return await this.decryptAndHash(hs.ss, message.ciphertext); + } + + private async readMessageC(hs: HandshakeState, message: MessageBuffer) { + const ns = await this.decryptAndHash(hs.ss, message.ns); + // TODO: validate ns here as public key + hs.rs = ns; + if (!hs.e) { + throw new Error("Handshake state `e` param is missing."); + } + this.mixKey(hs.ss, this.dh(hs.e.privateKey, hs.rs)); + const plaintext = await this.decryptAndHash(hs.ss, message.ciphertext); + const { cs1, cs2 } = this.split(hs.ss); + + return { h: hs.ss.h, plaintext, cs1, cs2 }; + } + + private readMessageRegular(cs: CipherState, message: MessageBuffer) : bytes { + return this.decryptWithAd(cs, Buffer.alloc(0), message.ciphertext); + } + public async generateKeypair() : Promise { return await crypto.keys.generateKeyPair('ed25519'); } @@ -274,7 +326,8 @@ export class XXHandshake { } else if (session.mc === 1) { messageBuffer = await this.writeMessageB(session.hs, message); } else if (session.mc === 2) { - const { h, messageBuffer, cs1, cs2 } = await this.writeMessageC(session.hs, message); + const { h, messageBuffer: resultingBuffer, cs1, cs2 } = await this.writeMessageC(session.hs, message); + messageBuffer = resultingBuffer; session.h = h; session.cs1 = cs1; session.cs2 = cs2; @@ -299,4 +352,36 @@ export class XXHandshake { session.mc++; return messageBuffer; } + + public async RecvMessage(session: NoiseSession, message: MessageBuffer) : Promise { + let plaintext: bytes; + if (session.mc === 0) { + plaintext = await this.readMessageA(session.hs, message); + } else if (session.mc === 1) { + plaintext = await this.readMessageB(session.hs, message); + } else if (session.mc === 2) { + const { h, plaintext: resultingPlaintext, cs1, cs2 } = await this.readMessageC(session.hs, message); + plaintext = resultingPlaintext; + session.h = h; + session.cs1 = cs1; + session.cs2 = cs2; + } else if (session.mc > 2) { + if (session.i) { + if (!session.cs2) { + throw new Error("CS1 (cipher state) is not defined") + } + plaintext = await this.readMessageRegular(session.cs2, message); + } else { + if (!session.cs1) { + throw new Error("CS1 (cipher state) is not defined") + } + plaintext = await this.readMessageRegular(session.cs1, message); + } + } else { + throw new Error("Session invalid."); + } + + session.mc++; + return plaintext; + } } From 9ef8858be4a871085aab40fd067ae59774e649fe Mon Sep 17 00:00:00 2001 From: morrigan Date: Tue, 5 Nov 2019 13:25:03 +0100 Subject: [PATCH 13/20] Write hkdf test --- src/xx.ts | 17 +++++++++-------- test/xx.test.ts | 14 ++++++++++++++ 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/xx.ts b/src/xx.ts index 6bfcd04..5e729af 100644 --- a/src/xx.ts +++ b/src/xx.ts @@ -1,7 +1,7 @@ import {bytes32, bytes16, uint32, uint64, bytes} from './types/basic' import { Buffer } from 'buffer'; import * as crypto from 'libp2p-crypto'; -import { AEAD, x25519, HKDF } from 'bcrypto'; +import { AEAD, x25519, HKDF, SHA256 } from 'bcrypto'; export interface KeyPair { publicKey: bytes32, @@ -42,6 +42,7 @@ type NoiseSession = { mc: uint64, i: boolean, } +export type Hkdf = [bytes, bytes, bytes]; const minNonce = 0; @@ -158,20 +159,20 @@ export class XXHandshake { if (protocolName.length <= 32) { const h = Buffer.alloc(32); protocolName.copy(h); - return Promise.resolve(h) + return h; } else { return await this.getHash(protocolName, Buffer.from([])); } } - private getHkdf(ck: bytes32, ikm: bytes) : Array { + public getHkdf(ck: bytes32, ikm: bytes) : Hkdf { const info = Buffer.alloc(0); - const prk = HKDF.extract('SHA256', ikm, ck); - const okm = HKDF.expand('SHA256', prk, info, ikm.length); + const prk = HKDF.extract(SHA256, ikm, ck); + const okm = HKDF.expand(SHA256, prk, info, 96); - const k1 = okm.slice(0, 16); - const k2 = okm.slice(16, 32); - const k3 = okm.slice(32, 64); + const k1 = okm.slice(0, 32); + const k2 = okm.slice(32, 64); + const k3 = okm.slice(64, 96); return [ k1, k2, k3 ]; } diff --git a/test/xx.test.ts b/test/xx.test.ts index 96dd529..700318a 100644 --- a/test/xx.test.ts +++ b/test/xx.test.ts @@ -16,4 +16,18 @@ describe("Index", () => { const session = await xx.initSession(true, prologue, kpInitiator, kpResponder.publicKey); console.log(session) }) + + it("Test get HKDF", async () => { + const xx = new XXHandshake(); + const ckBytes = Buffer.from('4e6f6973655f58585f32353531395f58436861436861506f6c795f53484132353600000000000000000000000000000000000000000000000000000000000000', 'hex'); + const ikm = Buffer.from('a3eae50ea37a47e8a7aa0c7cd8e16528670536dcd538cebfd724fb68ce44f1910ad898860666227d4e8dd50d22a9a64d1c0a6f47ace092510161e9e442953da3', 'hex'); + const ck = Buffer.alloc(32); + ckBytes.copy(ck); + + const [k1, k2, k3] = xx.getHkdf(ck, ikm); + expect(k1.toString('hex')).to.equal('cc5659adff12714982f806e2477a8d5ddd071def4c29bb38777b7e37046f6914'); + expect(k2.toString('hex')).to.equal('a16ada915e551ab623f38be674bb4ef15d428ae9d80688899c9ef9b62ef208fa'); + expect(k3.toString('hex')).to.equal('ff67bf9727e31b06efc203907e6786667d2c7a74ac412b4d31a80ba3fd766f68'); + + }) }); From 68cc670058c0c457f401233976233dbbea91f04e Mon Sep 17 00:00:00 2001 From: morrigan Date: Tue, 5 Nov 2019 13:36:20 +0100 Subject: [PATCH 14/20] Address MR comments --- src/xx.ts | 28 +++++++++++++++------------- test/xx.test.ts | 2 -- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/xx.ts b/src/xx.ts index 5e729af..551fcb5 100644 --- a/src/xx.ts +++ b/src/xx.ts @@ -2,6 +2,7 @@ import {bytes32, bytes16, uint32, uint64, bytes} from './types/basic' import { Buffer } from 'buffer'; import * as crypto from 'libp2p-crypto'; import { AEAD, x25519, HKDF, SHA256 } from 'bcrypto'; +import { BN } from 'bn.js'; export interface KeyPair { publicKey: bytes32, @@ -224,14 +225,15 @@ export class XXHandshake { await this.mixHash(hs.ss, ne); const ciphertext = await this.encryptAndHash(hs.ss, payload); - return {ne, ns, ciphertext} as MessageBuffer; + return {ne, ns, ciphertext}; } private async writeMessageB(hs: HandshakeState, payload: bytes) : Promise { hs.e = await this.generateKeypair(); const ne = hs.e.publicKey; + await this.mixHash(hs.ss, ne); await this.mixKey(hs.ss, this.dh(hs.e.privateKey, hs.re)); - const spk = Buffer.alloc(hs.s.publicKey.length); + const spk = Buffer.from(hs.s.publicKey); const ns = await this.encryptAndHash(hs.ss, spk); this.mixKey(hs.ss, this.dh(hs.s.privateKey, hs.re)); const ciphertext = await this.encryptAndHash(hs.ss, payload); @@ -240,7 +242,7 @@ export class XXHandshake { } private async writeMessageC(hs: HandshakeState, payload: bytes) { - const spk = hs.s.publicKey; + const spk = Buffer.from(hs.s.publicKey); const ns = await this.encryptAndHash(hs.ss, spk); this.mixKey(hs.ss, this.dh(hs.s.privateKey, hs.re)); const ciphertext = await this.encryptAndHash(hs.ss, payload); @@ -316,23 +318,23 @@ export class XXHandshake { return { hs, i: initiator, - mc: 0 + mc: new BN(0), }; } public async sendMessage(session: NoiseSession, message: bytes) : Promise { - let messageBuffer: MessageBuffer = {} as MessageBuffer; - if (session.mc === 0) { + let messageBuffer: MessageBuffer; + if (session.mc.eqn(0)) { messageBuffer = await this.writeMessageA(session.hs, message); - } else if (session.mc === 1) { + } else if (session.mc.eqn(1)) { messageBuffer = await this.writeMessageB(session.hs, message); - } else if (session.mc === 2) { + } else if (session.mc.eqn(2)) { const { h, messageBuffer: resultingBuffer, cs1, cs2 } = await this.writeMessageC(session.hs, message); messageBuffer = resultingBuffer; session.h = h; session.cs1 = cs1; session.cs2 = cs2; - } else if (session.mc > 2) { + } else if (session.mc.gtn(2)) { if (session.i) { if (!session.cs1) { throw new Error("CS1 (cipher state) is not defined") @@ -356,17 +358,17 @@ export class XXHandshake { public async RecvMessage(session: NoiseSession, message: MessageBuffer) : Promise { let plaintext: bytes; - if (session.mc === 0) { + if (session.mc.eqn(0)) { plaintext = await this.readMessageA(session.hs, message); - } else if (session.mc === 1) { + } else if (session.mc.eqn(1)) { plaintext = await this.readMessageB(session.hs, message); - } else if (session.mc === 2) { + } else if (session.mc.eqn(2)) { const { h, plaintext: resultingPlaintext, cs1, cs2 } = await this.readMessageC(session.hs, message); plaintext = resultingPlaintext; session.h = h; session.cs1 = cs1; session.cs2 = cs2; - } else if (session.mc > 2) { + } else if (session.mc.gtn(2)) { if (session.i) { if (!session.cs2) { throw new Error("CS1 (cipher state) is not defined") diff --git a/test/xx.test.ts b/test/xx.test.ts index 700318a..10628b4 100644 --- a/test/xx.test.ts +++ b/test/xx.test.ts @@ -14,7 +14,6 @@ describe("Index", () => { const session = await xx.initSession(true, prologue, kpInitiator, kpResponder.publicKey); - console.log(session) }) it("Test get HKDF", async () => { @@ -28,6 +27,5 @@ describe("Index", () => { expect(k1.toString('hex')).to.equal('cc5659adff12714982f806e2477a8d5ddd071def4c29bb38777b7e37046f6914'); expect(k2.toString('hex')).to.equal('a16ada915e551ab623f38be674bb4ef15d428ae9d80688899c9ef9b62ef208fa'); expect(k3.toString('hex')).to.equal('ff67bf9727e31b06efc203907e6786667d2c7a74ac412b4d31a80ba3fd766f68'); - }) }); From fe706fbd71d4c5f4f427d2939d99f60708d5ff3f Mon Sep 17 00:00:00 2001 From: morrigan Date: Wed, 6 Nov 2019 13:24:30 +0100 Subject: [PATCH 15/20] Create part of XX test and update code accordingly --- package.json | 7 ++-- payload.proto | 9 +++++ src/xx.ts | 37 ++++++++++++--------- test/xx.test.ts | 50 +++++++++++++++++++++++++++- yarn.lock | 87 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 172 insertions(+), 18 deletions(-) create mode 100644 payload.proto diff --git a/package.json b/package.json index 8775f27..9734daf 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "devDependencies": { "@babel/cli": "^7.6.4", "@babel/core": "^7.6.4", + "@babel/plugin-proposal-object-rest-spread": "^7.6.2", "@babel/plugin-transform-runtime": "^7.6.2", "@babel/preset-env": "^7.6.3", "@babel/preset-typescript": "^7.6.0", @@ -37,13 +38,15 @@ "@babel/preset-typescript" ], "plugins": [ - "@babel/plugin-transform-runtime" + "@babel/plugin-transform-runtime", + "@babel/plugin-proposal-object-rest-spread" ] }, "dependencies": { "bcrypto": "^4.2.3", "bn.js": "^5.0.0", "buffer": "^5.4.3", - "libp2p-crypto": "^0.17.1" + "libp2p-crypto": "^0.17.1", + "protobufjs": "~6.8.8" } } diff --git a/payload.proto b/payload.proto new file mode 100644 index 0000000..765fa4d --- /dev/null +++ b/payload.proto @@ -0,0 +1,9 @@ +syntax = "proto3"; +package pb; + +message NoiseHandshakePayload { + bytes libp2p_key = 1; + bytes noise_static_key_signature = 2; + bytes libp2p_data = 3; + bytes libp2p_data_signature = 4; +} diff --git a/src/xx.ts b/src/xx.ts index 551fcb5..30c77b4 100644 --- a/src/xx.ts +++ b/src/xx.ts @@ -55,7 +55,7 @@ export class XXHandshake { private async initializeInitiator(prologue: bytes32, s: KeyPair, rs: bytes32, psk: bytes32) : Promise { const name = "Noise_XX_25519_ChaChaPoly_SHA256"; const ss = await this.initializeSymmetric(name); - await this.mixHash(ss, prologue); + this.mixHash(ss, prologue); const re = Buffer.alloc(32); return { ss, s, rs, psk, re }; @@ -64,7 +64,7 @@ export class XXHandshake { private async initializeResponder(prologue: bytes32, s: KeyPair, rs: bytes32, psk: bytes32) : Promise { const name = "Noise_XX_25519_ChaChaPoly_SHA256"; const ss = await this.initializeSymmetric(name); - await this.mixHash(ss, prologue); + this.mixHash(ss, prologue); const re = Buffer.alloc(32); return { ss, s, rs, psk, re }; @@ -143,6 +143,7 @@ export class XXHandshake { private async initializeSymmetric(protocolName: string) : Promise { const protocolNameBytes: bytes = Buffer.from(protocolName, 'utf-8'); const h = await this.hashProtocolName(protocolNameBytes); + const ck = h; const key = this.createEmptyKey(); const cs = this.initializeKey(key); @@ -158,11 +159,11 @@ export class XXHandshake { private async hashProtocolName(protocolName: bytes) : Promise { if (protocolName.length <= 32) { - const h = Buffer.alloc(32); + let h = Buffer.alloc(32); protocolName.copy(h); return h; } else { - return await this.getHash(protocolName, Buffer.from([])); + return this.getHash(protocolName, Buffer.alloc(0)); } } @@ -178,12 +179,12 @@ export class XXHandshake { return [ k1, k2, k3 ]; } - private async mixHash(ss: SymmetricState, data: bytes) { - ss.h = await this.getHash(ss.h, data); + private mixHash(ss: SymmetricState, data: bytes) { + ss.h = this.getHash(ss.h, data); } - private async getHash(a: bytes, b: bytes) : Promise { - return await crypto.hmac.create('sha256', Buffer.from([...a, ...b])) + private getHash(a: bytes, b: bytes) : bytes32 { + return SHA256.digest(Buffer.from([...a, ...b])); } private async encryptAndHash(ss: SymmetricState, plaintext: bytes) : Promise { @@ -194,7 +195,7 @@ export class XXHandshake { ciphertext = plaintext; } - await this.mixHash(ss, ciphertext); + this.mixHash(ss, ciphertext); return ciphertext; } @@ -206,7 +207,7 @@ export class XXHandshake { plaintext = ciphertext; } - await this.mixHash(ss, ciphertext); + this.mixHash(ss, ciphertext); return plaintext; } @@ -222,7 +223,8 @@ export class XXHandshake { let ns = Buffer.alloc(0); hs.e = await this.generateKeypair(); const ne = hs.e.publicKey; - await this.mixHash(hs.ss, ne); + + this.mixHash(hs.ss, ne); const ciphertext = await this.encryptAndHash(hs.ss, payload); return {ne, ns, ciphertext}; @@ -231,7 +233,7 @@ export class XXHandshake { private async writeMessageB(hs: HandshakeState, payload: bytes) : Promise { hs.e = await this.generateKeypair(); const ne = hs.e.publicKey; - await this.mixHash(hs.ss, ne); + this.mixHash(hs.ss, ne); await this.mixKey(hs.ss, this.dh(hs.e.privateKey, hs.re)); const spk = Buffer.from(hs.s.publicKey); const ns = await this.encryptAndHash(hs.ss, spk); @@ -264,14 +266,14 @@ export class XXHandshake { private async readMessageA(hs: HandshakeState, message: MessageBuffer) : Promise { // TODO: validate public key here - await this.mixHash(hs.ss, hs.re); + this.mixHash(hs.ss, hs.re); return await this.decryptAndHash(hs.ss, message.ciphertext); } private async readMessageB(hs: HandshakeState, message: MessageBuffer) : Promise { // TODO: validate public key here - await this.mixHash(hs.ss, hs.re); + this.mixHash(hs.ss, hs.re); if (!hs.e) { throw new Error("Handshake state `e` param is missing."); } @@ -302,7 +304,12 @@ export class XXHandshake { } public async generateKeypair() : Promise { - return await crypto.keys.generateKeyPair('ed25519'); + const Ed25519PrivateKey = await crypto.keys.generateKeyPair('ed25519'); + + return { + publicKey: Ed25519PrivateKey.public.bytes, + privateKey: Ed25519PrivateKey.bytes, + } } public async initSession(initiator: boolean, prologue: bytes32, s: KeyPair, rs: bytes32) : Promise { diff --git a/test/xx.test.ts b/test/xx.test.ts index 10628b4..356293b 100644 --- a/test/xx.test.ts +++ b/test/xx.test.ts @@ -1,5 +1,7 @@ -import { expect } from "chai"; +import { expect, assert } from "chai"; import { Buffer } from 'buffer'; +import * as crypto from 'libp2p-crypto'; +import protobuf from 'protobufjs'; import { XXHandshake, KeyPair } from "../src/xx"; @@ -28,4 +30,50 @@ describe("Index", () => { expect(k2.toString('hex')).to.equal('a16ada915e551ab623f38be674bb4ef15d428ae9d80688899c9ef9b62ef208fa'); expect(k3.toString('hex')).to.equal('ff67bf9727e31b06efc203907e6786667d2c7a74ac412b4d31a80ba3fd766f68'); }) + + async function generateKeypair() { + return await crypto.keys.generateKeyPair('ed25519');; + } + + async function doHandshake() { + const xx = new XXHandshake(); + const kpInit = await xx.generateKeypair(); + const kpResp = await xx.generateKeypair(); + const payloadString = Buffer.from("noise-libp2p-static-key:"); + + // initiator setup + const libp2pInitKeys = await generateKeypair(); + const initSignedPayload = await libp2pInitKeys.sign(Buffer.concat([payloadString, kpInit.publicKey])); + + // responder setup + const libp2pRespKeys = await generateKeypair(); + const respSignedPayload = await libp2pRespKeys.sign(Buffer.concat([payloadString, kpResp.publicKey])); + + // initiator: new XX noise session + const nsInit = await xx.initSession(true, prologue, kpInit, kpResp.publicKey); + // responder: new XX noise session + const nsResp = await xx.initSession(false, prologue, kpResp, kpInit.publicKey); + + /* stage 0: initiator */ + + // initiator creates payload + const payloadProtoBuf = await protobuf.load("payload.proto"); + const NoiseHandshakePayload = payloadProtoBuf.lookupType("pb.NoiseHandshakePayload"); + const payloadInit = NoiseHandshakePayload.create({ + libp2pKey: libp2pInitKeys.bytes.toString('hex'), + noiseStaticKeySignature: initSignedPayload, + }); + + const payloadInitEnc = NoiseHandshakePayload.encode(payloadInit).finish(); + + // initiator sends message + const message = Buffer.concat([Buffer.alloc(0), payloadInitEnc]); + const messageBuffer = await xx.sendMessage(nsInit, message); + + expect(messageBuffer.ne.length).not.equal(0); + } + + it("Test handshake", async () => { + await doHandshake(); + }) }); diff --git a/yarn.lock b/yarn.lock index 4d57bf8..e656c1a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -718,6 +718,59 @@ lodash "^4.17.13" to-fast-properties "^2.0.0" +"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" + integrity sha1-m4sMxmPWaafY9vXQiToU00jzD78= + +"@protobufjs/base64@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" + integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== + +"@protobufjs/codegen@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" + integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== + +"@protobufjs/eventemitter@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" + integrity sha1-NVy8mLr61ZePntCV85diHx0Ga3A= + +"@protobufjs/fetch@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" + integrity sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU= + dependencies: + "@protobufjs/aspromise" "^1.1.1" + "@protobufjs/inquire" "^1.1.0" + +"@protobufjs/float@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" + integrity sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E= + +"@protobufjs/inquire@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" + integrity sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik= + +"@protobufjs/path@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" + integrity sha1-bMKyDFya1q0NzP0hynZz2Nf79o0= + +"@protobufjs/pool@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" + integrity sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q= + +"@protobufjs/utf8@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" + integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA= + "@types/chai@^4.2.4": version "4.2.4" resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.2.4.tgz#8936cffad3c96ec470a2dc26a38c3ba8b9b6f619" @@ -733,11 +786,21 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.3.tgz#bdfd69d61e464dcc81b25159c270d75a73c1a636" integrity sha512-Il2DtDVRGDcqjDtE+rF8iqg1CArehSK84HZJCT7AMITlyXRBpuPhqGLDQMowraqqu1coEaimg4ZOqggt6L6L+A== +"@types/long@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.0.tgz#719551d2352d301ac8b81db732acb6bdc28dbdef" + integrity sha512-1w52Nyx4Gq47uuu0EVcsHBxZFJgurQ+rTKS3qMHxR1GY2T8c2AJYd6vZoZ9q1rupaDjU0yT+Jc2XTyXkjeMA+Q== + "@types/mocha@^5.2.7": version "5.2.7" resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.7.tgz#315d570ccb56c53452ff8638738df60726d5b6ea" integrity sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ== +"@types/node@^10.1.0": + version "10.17.3" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.3.tgz#65a8d9a6a0f6af55595a2d0020617959130d6495" + integrity sha512-QZ9CjUB3QoA3f2afw3utKlfRPhpmufB7jC2+oDhLWnXqoyx333fhKSQDLQu2EK7OE0a15X67eYiRAaJsHXrpMA== + "@types/node@^10.12.12": version "10.17.2" resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.2.tgz#41b5afbcde1a5a805302a4da3cf399499f1bbf64" @@ -2401,6 +2464,11 @@ log-symbols@2.2.0: dependencies: chalk "^2.0.1" +long@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" + integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== + loose-envify@^1.0.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" @@ -2982,6 +3050,25 @@ promise@~1.3.0: dependencies: is-promise "~1" +protobufjs@~6.8.8: + version "6.8.8" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.8.8.tgz#c8b4f1282fd7a90e6f5b109ed11c84af82908e7c" + integrity sha512-AAmHtD5pXgZfi7GMpllpO3q1Xw1OYldr+dMUlAnffGTAhqkg72WdmSY71uKBF/JuyiKs8psYbtKrhi0ASCD8qw== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/long" "^4.0.0" + "@types/node" "^10.1.0" + long "^4.0.0" + protocol-buffers-schema@^3.3.1: version "3.3.2" resolved "https://registry.yarnpkg.com/protocol-buffers-schema/-/protocol-buffers-schema-3.3.2.tgz#00434f608b4e8df54c59e070efeefc37fb4bb859" From 1666769690036228f50f325ba857f121d2734b42 Mon Sep 17 00:00:00 2001 From: morrigan Date: Wed, 6 Nov 2019 15:16:13 +0100 Subject: [PATCH 16/20] Change generating keys --- src/xx.ts | 25 +++++++++++++++---------- test/xx.test.ts | 33 ++++++++++++++++++++++++++------- 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/src/xx.ts b/src/xx.ts index 30c77b4..193076b 100644 --- a/src/xx.ts +++ b/src/xx.ts @@ -1,6 +1,5 @@ import {bytes32, bytes16, uint32, uint64, bytes} from './types/basic' import { Buffer } from 'buffer'; -import * as crypto from 'libp2p-crypto'; import { AEAD, x25519, HKDF, SHA256 } from 'bcrypto'; import { BN } from 'bn.js'; @@ -75,7 +74,10 @@ export class XXHandshake { } private dh(privateKey: bytes32, publicKey: bytes32) : bytes32 { - return x25519.derive(privateKey, publicKey); + const derived = x25519.derive(privateKey, publicKey); + const result = Buffer.alloc(32); + derived.copy(result); + return result; } private convertNonce(n: uint32) : bytes { @@ -146,14 +148,14 @@ export class XXHandshake { const ck = h; const key = this.createEmptyKey(); - const cs = this.initializeKey(key); + const cs:CipherState = this.initializeKey(key); return { cs, ck, h }; } private mixKey(ss: SymmetricState, ikm: bytes32) { const [ ck, tempK ] = this.getHkdf(ss.ck, ikm); - ss.cs = this.initializeKey(tempK); + ss.cs = this.initializeKey(tempK) as CipherState; ss.ck = ck; } @@ -234,9 +236,11 @@ export class XXHandshake { hs.e = await this.generateKeypair(); const ne = hs.e.publicKey; this.mixHash(hs.ss, ne); - await this.mixKey(hs.ss, this.dh(hs.e.privateKey, hs.re)); + + this.mixKey(hs.ss, this.dh(hs.e.privateKey, hs.re)); const spk = Buffer.from(hs.s.publicKey); const ns = await this.encryptAndHash(hs.ss, spk); + this.mixKey(hs.ss, this.dh(hs.s.privateKey, hs.re)); const ciphertext = await this.encryptAndHash(hs.ss, payload); @@ -304,11 +308,12 @@ export class XXHandshake { } public async generateKeypair() : Promise { - const Ed25519PrivateKey = await crypto.keys.generateKeyPair('ed25519'); + const privateKey = x25519.privateKeyGenerate(); + const publicKey = x25519.publicKeyCreate(privateKey); return { - publicKey: Ed25519PrivateKey.public.bytes, - privateKey: Ed25519PrivateKey.bytes, + publicKey, + privateKey, } } @@ -359,7 +364,7 @@ export class XXHandshake { throw new Error("Session invalid.") } - session.mc++; + session.mc = session.mc.add(new BN(1)); return messageBuffer; } @@ -391,7 +396,7 @@ export class XXHandshake { throw new Error("Session invalid."); } - session.mc++; + session.mc = session.mc.add(new BN(1)); return plaintext; } } diff --git a/test/xx.test.ts b/test/xx.test.ts index 356293b..15a7cc2 100644 --- a/test/xx.test.ts +++ b/test/xx.test.ts @@ -2,6 +2,7 @@ import { expect, assert } from "chai"; import { Buffer } from 'buffer'; import * as crypto from 'libp2p-crypto'; import protobuf from 'protobufjs'; +import { ed25519 } from 'bcrypto'; import { XXHandshake, KeyPair } from "../src/xx"; @@ -31,8 +32,8 @@ describe("Index", () => { expect(k3.toString('hex')).to.equal('ff67bf9727e31b06efc203907e6786667d2c7a74ac412b4d31a80ba3fd766f68'); }) - async function generateKeypair() { - return await crypto.keys.generateKeyPair('ed25519');; + async function generateEd25519Keys() { + return await crypto.keys.generateKeyPair('ed25519'); } async function doHandshake() { @@ -42,11 +43,11 @@ describe("Index", () => { const payloadString = Buffer.from("noise-libp2p-static-key:"); // initiator setup - const libp2pInitKeys = await generateKeypair(); + const libp2pInitKeys = await generateEd25519Keys(); const initSignedPayload = await libp2pInitKeys.sign(Buffer.concat([payloadString, kpInit.publicKey])); // responder setup - const libp2pRespKeys = await generateKeypair(); + const libp2pRespKeys = await generateEd25519Keys(); const respSignedPayload = await libp2pRespKeys.sign(Buffer.concat([payloadString, kpResp.publicKey])); // initiator: new XX noise session @@ -54,16 +55,15 @@ describe("Index", () => { // responder: new XX noise session const nsResp = await xx.initSession(false, prologue, kpResp, kpInit.publicKey); - /* stage 0: initiator */ + /* STAGE 0 */ // initiator creates payload const payloadProtoBuf = await protobuf.load("payload.proto"); const NoiseHandshakePayload = payloadProtoBuf.lookupType("pb.NoiseHandshakePayload"); const payloadInit = NoiseHandshakePayload.create({ - libp2pKey: libp2pInitKeys.bytes.toString('hex'), + libp2pKey: libp2pInitKeys.bytes, noiseStaticKeySignature: initSignedPayload, }); - const payloadInitEnc = NoiseHandshakePayload.encode(payloadInit).finish(); // initiator sends message @@ -71,6 +71,25 @@ describe("Index", () => { const messageBuffer = await xx.sendMessage(nsInit, message); expect(messageBuffer.ne.length).not.equal(0); + + // responder receives message + const plaintext = await xx.RecvMessage(nsResp, messageBuffer); + + /* STAGE 1 */ + + // responder creates payload + const payloadResp = NoiseHandshakePayload.create({ + libp2pKey: libp2pRespKeys.bytes, + noiseStaticKeySignature: respSignedPayload, + }); + const payloadRespEnc = NoiseHandshakePayload.encode(payloadResp).finish(); + + const message1 = Buffer.concat([message, payloadRespEnc]); + console.log("nsResp: ", nsResp) + const messageBuffer2 = await xx.sendMessage(nsResp, message1); + + expect(messageBuffer2.ne.length).not.equal(0); + expect(messageBuffer2.ns.length).not.equal(0); } it("Test handshake", async () => { From 87d7ed9c41e19d2601e7ca1f0074c885b786a3a3 Mon Sep 17 00:00:00 2001 From: morrigan Date: Wed, 6 Nov 2019 15:45:28 +0100 Subject: [PATCH 17/20] Fix todos and finish stage 1 --- src/xx.ts | 21 ++++++++++++++------- test/xx.test.ts | 5 ++++- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/xx.ts b/src/xx.ts index 193076b..b9d94dc 100644 --- a/src/xx.ts +++ b/src/xx.ts @@ -74,7 +74,7 @@ export class XXHandshake { } private dh(privateKey: bytes32, publicKey: bytes32) : bytes32 { - const derived = x25519.derive(privateKey, publicKey); + const derived = x25519.derive(publicKey, privateKey); const result = Buffer.alloc(32); derived.copy(result); return result; @@ -268,14 +268,18 @@ export class XXHandshake { } private async readMessageA(hs: HandshakeState, message: MessageBuffer) : Promise { - // TODO: validate public key here + if (x25519.publicKeyVerify(message.ne)) { + hs.re = message.ne; + } this.mixHash(hs.ss, hs.re); return await this.decryptAndHash(hs.ss, message.ciphertext); } private async readMessageB(hs: HandshakeState, message: MessageBuffer) : Promise { - // TODO: validate public key here + if (x25519.publicKeyVerify(message.ne)) { + hs.re = message.ne; + } this.mixHash(hs.ss, hs.re); if (!hs.e) { @@ -283,16 +287,19 @@ export class XXHandshake { } this.mixKey(hs.ss, this.dh(hs.e.privateKey, hs.re)); const ns = await this.decryptAndHash(hs.ss, message.ns); - // TODO: validate ns here as public key - hs.rs = ns; + if (ns.length === 32 && x25519.publicKeyVerify(message.ns)) { + hs.rs = ns; + } this.mixKey(hs.ss, this.dh(hs.e.privateKey, hs.rs)); return await this.decryptAndHash(hs.ss, message.ciphertext); } private async readMessageC(hs: HandshakeState, message: MessageBuffer) { const ns = await this.decryptAndHash(hs.ss, message.ns); - // TODO: validate ns here as public key - hs.rs = ns; + if (ns.length === 32 && x25519.publicKeyVerify(message.ns)) { + hs.rs = ns; + } + if (!hs.e) { throw new Error("Handshake state `e` param is missing."); } diff --git a/test/xx.test.ts b/test/xx.test.ts index 15a7cc2..a9a9470 100644 --- a/test/xx.test.ts +++ b/test/xx.test.ts @@ -85,11 +85,14 @@ describe("Index", () => { const payloadRespEnc = NoiseHandshakePayload.encode(payloadResp).finish(); const message1 = Buffer.concat([message, payloadRespEnc]); - console.log("nsResp: ", nsResp) const messageBuffer2 = await xx.sendMessage(nsResp, message1); expect(messageBuffer2.ne.length).not.equal(0); expect(messageBuffer2.ns.length).not.equal(0); + + // initiator receive payload + const plaintext2 = await xx.RecvMessage(nsInit, messageBuffer2); + console.log(plaintext2); } it("Test handshake", async () => { From 051f0765f9ec0d88c589c37e681169ec35ae61b6 Mon Sep 17 00:00:00 2001 From: morrigan Date: Wed, 6 Nov 2019 15:49:20 +0100 Subject: [PATCH 18/20] Finish all handshake stages --- src/xx.ts | 2 +- test/xx.test.ts | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/xx.ts b/src/xx.ts index b9d94dc..4947f63 100644 --- a/src/xx.ts +++ b/src/xx.ts @@ -375,7 +375,7 @@ export class XXHandshake { return messageBuffer; } - public async RecvMessage(session: NoiseSession, message: MessageBuffer) : Promise { + public async recvMessage(session: NoiseSession, message: MessageBuffer) : Promise { let plaintext: bytes; if (session.mc.eqn(0)) { plaintext = await this.readMessageA(session.hs, message); diff --git a/test/xx.test.ts b/test/xx.test.ts index a9a9470..c5232b8 100644 --- a/test/xx.test.ts +++ b/test/xx.test.ts @@ -73,7 +73,8 @@ describe("Index", () => { expect(messageBuffer.ne.length).not.equal(0); // responder receives message - const plaintext = await xx.RecvMessage(nsResp, messageBuffer); + const plaintext = await xx.recvMessage(nsResp, messageBuffer); + console.log("Stage 0 responder payload: ", plaintext); /* STAGE 1 */ @@ -91,8 +92,18 @@ describe("Index", () => { expect(messageBuffer2.ns.length).not.equal(0); // initiator receive payload - const plaintext2 = await xx.RecvMessage(nsInit, messageBuffer2); - console.log(plaintext2); + const plaintext2 = await xx.recvMessage(nsInit, messageBuffer2); + console.log("Stage 1 responder payload: ", plaintext2); + + /* STAGE 2 */ + + // initiator send message + const messageBuffer3 = await xx.sendMessage(nsInit, Buffer.alloc(0)); + // responder receive message + const plaintext3 = await xx.recvMessage(nsResp, messageBuffer3); + console.log("Stage 2 responder payload: ", plaintext3); + + return { nsInit, nsResp }; } it("Test handshake", async () => { From 3b5a401a1c6456cd1b9fd2df473d052c38f8b28a Mon Sep 17 00:00:00 2001 From: morrigan Date: Wed, 6 Nov 2019 16:09:15 +0100 Subject: [PATCH 19/20] Complete test --- src/xx.ts | 5 +++-- test/xx.test.ts | 12 ++++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/xx.ts b/src/xx.ts index 4947f63..aac3850 100644 --- a/src/xx.ts +++ b/src/xx.ts @@ -127,13 +127,14 @@ export class XXHandshake { cs.n = nonce; } - private encryptWithAd(cs: CipherState, ad: bytes, plaintext: bytes) : bytes { + public encryptWithAd(cs: CipherState, ad: bytes, plaintext: bytes) : bytes { const e = this.encrypt(cs.k, cs.n, ad, plaintext); this.setNonce(cs, this.incrementNonce(cs.n)); + return e; } - private decryptWithAd(cs: CipherState, ad: bytes, ciphertext: bytes) : bytes { + public decryptWithAd(cs: CipherState, ad: bytes, ciphertext: bytes) : bytes { const plaintext = this.decrypt(cs.k, cs.n, ad, ciphertext); this.setNonce(cs, this.incrementNonce(cs.n)); diff --git a/test/xx.test.ts b/test/xx.test.ts index c5232b8..6eabb45 100644 --- a/test/xx.test.ts +++ b/test/xx.test.ts @@ -36,8 +36,7 @@ describe("Index", () => { return await crypto.keys.generateKeyPair('ed25519'); } - async function doHandshake() { - const xx = new XXHandshake(); + async function doHandshake(xx) { const kpInit = await xx.generateKeypair(); const kpResp = await xx.generateKeypair(); const payloadString = Buffer.from("noise-libp2p-static-key:"); @@ -99,14 +98,19 @@ describe("Index", () => { // initiator send message const messageBuffer3 = await xx.sendMessage(nsInit, Buffer.alloc(0)); + // responder receive message const plaintext3 = await xx.recvMessage(nsResp, messageBuffer3); console.log("Stage 2 responder payload: ", plaintext3); + assert(nsInit.cs1.k.equals(nsResp.cs1.k)); + assert(nsInit.cs2.k.equals(nsResp.cs2.k)); + return { nsInit, nsResp }; } it("Test handshake", async () => { - await doHandshake(); - }) + const xx = new XXHandshake(); + await doHandshake(xx); + }); }); From 16990f3de6f028182095846644cbff2026aa45d1 Mon Sep 17 00:00:00 2001 From: morrigan Date: Thu, 7 Nov 2019 10:55:18 +0100 Subject: [PATCH 20/20] Address PR comments --- package.json | 13 +++++++++---- payload.proto => protos/payload.proto | 0 src/xx.ts | 8 ++++---- test/utils.ts | 11 +++++++++++ test/xx.test.ts | 11 +++-------- yarn.lock | 14 ++------------ 6 files changed, 29 insertions(+), 28 deletions(-) rename payload.proto => protos/payload.proto (100%) create mode 100644 test/utils.ts diff --git a/package.json b/package.json index 9734daf..5e7e1f0 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,6 @@ "@babel/cli": "^7.6.4", "@babel/core": "^7.6.4", "@babel/plugin-proposal-object-rest-spread": "^7.6.2", - "@babel/plugin-transform-runtime": "^7.6.2", "@babel/preset-env": "^7.6.3", "@babel/preset-typescript": "^7.6.0", "@babel/register": "^7.6.2", @@ -29,16 +28,23 @@ "bn.js-typings": "^1.0.1", "chai": "^4.2.0", "eslint": "^6.6.0", + "libp2p-crypto": "^0.17.1", "mocha": "^6.2.2", "typescript": "^3.6.4" }, "babel": { "presets": [ - "@babel/preset-env", + [ + "@babel/preset-env", + { + "targets": { + "node": "12" + } + } + ], "@babel/preset-typescript" ], "plugins": [ - "@babel/plugin-transform-runtime", "@babel/plugin-proposal-object-rest-spread" ] }, @@ -46,7 +52,6 @@ "bcrypto": "^4.2.3", "bn.js": "^5.0.0", "buffer": "^5.4.3", - "libp2p-crypto": "^0.17.1", "protobufjs": "~6.8.8" } } diff --git a/payload.proto b/protos/payload.proto similarity index 100% rename from payload.proto rename to protos/payload.proto diff --git a/src/xx.ts b/src/xx.ts index aac3850..23a6f80 100644 --- a/src/xx.ts +++ b/src/xx.ts @@ -80,7 +80,7 @@ export class XXHandshake { return result; } - private convertNonce(n: uint32) : bytes { + private nonceToBytes(n: uint32) : bytes { const nonce = Buffer.alloc(12); nonce.writeUInt32LE(n, 4); @@ -88,7 +88,7 @@ export class XXHandshake { } private encrypt(k: bytes32, n: uint32, ad: bytes, plaintext: bytes) : bytes { - const nonce = this.convertNonce(n); + const nonce = this.nonceToBytes(n); const ctx = new AEAD(); ctx.init(k, nonce); ctx.aad(ad); @@ -98,7 +98,7 @@ export class XXHandshake { } private decrypt(k: bytes32, n: uint32, ad: bytes, ciphertext: bytes) : bytes { - const nonce = this.convertNonce(n); + const nonce = this.nonceToBytes(n); const ctx = new AEAD(); ctx.init(k, nonce); @@ -123,7 +123,7 @@ export class XXHandshake { return !this.isEmptyKey(cs.k); } - private setNonce(cs: CipherState, nonce: uint32) { + private setNonce(cs: CipherState, nonce: uint32) : void { cs.n = nonce; } diff --git a/test/utils.ts b/test/utils.ts new file mode 100644 index 0000000..6792447 --- /dev/null +++ b/test/utils.ts @@ -0,0 +1,11 @@ +import protobuf from "protobufjs"; +import * as crypto from 'libp2p-crypto'; + +export async function loadPayloadProto () { + const payloadProtoBuf = await protobuf.load("protos/payload.proto"); + return payloadProtoBuf.lookupType("pb.NoiseHandshakePayload"); +} + +export async function generateEd25519Keys() { + return await crypto.keys.generateKeyPair('ed25519'); +} diff --git a/test/xx.test.ts b/test/xx.test.ts index 6eabb45..2c4f03a 100644 --- a/test/xx.test.ts +++ b/test/xx.test.ts @@ -1,10 +1,9 @@ import { expect, assert } from "chai"; import { Buffer } from 'buffer'; -import * as crypto from 'libp2p-crypto'; -import protobuf from 'protobufjs'; import { ed25519 } from 'bcrypto'; import { XXHandshake, KeyPair } from "../src/xx"; +import { loadPayloadProto, generateEd25519Keys } from "./utils"; describe("Index", () => { const prologue = Buffer.from("/noise", "utf-8"); @@ -32,10 +31,6 @@ describe("Index", () => { expect(k3.toString('hex')).to.equal('ff67bf9727e31b06efc203907e6786667d2c7a74ac412b4d31a80ba3fd766f68'); }) - async function generateEd25519Keys() { - return await crypto.keys.generateKeyPair('ed25519'); - } - async function doHandshake(xx) { const kpInit = await xx.generateKeypair(); const kpResp = await xx.generateKeypair(); @@ -57,8 +52,7 @@ describe("Index", () => { /* STAGE 0 */ // initiator creates payload - const payloadProtoBuf = await protobuf.load("payload.proto"); - const NoiseHandshakePayload = payloadProtoBuf.lookupType("pb.NoiseHandshakePayload"); + const NoiseHandshakePayload = await loadPayloadProto(); const payloadInit = NoiseHandshakePayload.create({ libp2pKey: libp2pInitKeys.bytes, noiseStaticKeySignature: initSignedPayload, @@ -113,4 +107,5 @@ describe("Index", () => { const xx = new XXHandshake(); await doHandshake(xx); }); + }); diff --git a/yarn.lock b/yarn.lock index e656c1a..2ef30f1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -538,16 +538,6 @@ dependencies: "@babel/helper-plugin-utils" "^7.0.0" -"@babel/plugin-transform-runtime@^7.6.2": - version "7.6.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.6.2.tgz#2669f67c1fae0ae8d8bf696e4263ad52cb98b6f8" - integrity sha512-cqULw/QB4yl73cS5Y0TZlQSjDvNkzDbu0FurTZyHlJpWE5T3PCMdnyV+xXoH1opr1ldyHODe3QAX3OMAii5NxA== - dependencies: - "@babel/helper-module-imports" "^7.0.0" - "@babel/helper-plugin-utils" "^7.0.0" - resolve "^1.8.1" - semver "^5.5.1" - "@babel/plugin-transform-shorthand-properties@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz#6333aee2f8d6ee7e28615457298934a3b46198f0" @@ -3226,7 +3216,7 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= -resolve@^1.3.2, resolve@^1.8.1: +resolve@^1.3.2: version "1.12.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.12.0.tgz#3fc644a35c84a48554609ff26ec52b66fa577df6" integrity sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w== @@ -3338,7 +3328,7 @@ secp256k1@^3.6.2: nan "^2.14.0" safe-buffer "^5.1.2" -semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^5.7.0: +semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0, semver@^5.7.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==