From 4bcab33b904184990672603772733f98ebe2e84a Mon Sep 17 00:00:00 2001 From: Jean-Pierre de Villiers Date: Thu, 25 Aug 2022 12:56:31 +0200 Subject: [PATCH] feat(web-client): add Diffie-Hellman key agreement --- web-client/package-lock.json | 183 ++++++++++++++++++ web-client/package.json | 3 + .../patches/@stablelib+binary+1.0.1.patch | 33 ++++ .../patches/@stablelib+bytes+1.0.1.patch | 33 ++++ .../@stablelib+constant-time+1.0.1.patch | 33 ++++ .../patches/@stablelib+hash+1.0.1.patch | 33 ++++ .../patches/@stablelib+hkdf+1.0.1.patch | 33 ++++ .../patches/@stablelib+hmac+1.0.1.patch | 33 ++++ web-client/patches/@stablelib+int+1.0.1.patch | 33 ++++ .../@stablelib+keyagreement+1.0.1.patch | 33 ++++ .../patches/@stablelib+random+1.0.1.patch | 29 +++ .../patches/@stablelib+sha256+1.0.1.patch | 33 ++++ .../patches/@stablelib+wipe+1.0.1.patch | 33 ++++ .../patches/@stablelib+x25519+1.0.2.patch | 16 ++ web-client/src/schema/crypto.spec.ts | 26 +++ web-client/src/schema/crypto.ts | 96 ++++++++- 16 files changed, 679 insertions(+), 4 deletions(-) create mode 100644 web-client/patches/@stablelib+binary+1.0.1.patch create mode 100644 web-client/patches/@stablelib+bytes+1.0.1.patch create mode 100644 web-client/patches/@stablelib+constant-time+1.0.1.patch create mode 100644 web-client/patches/@stablelib+hash+1.0.1.patch create mode 100644 web-client/patches/@stablelib+hkdf+1.0.1.patch create mode 100644 web-client/patches/@stablelib+hmac+1.0.1.patch create mode 100644 web-client/patches/@stablelib+int+1.0.1.patch create mode 100644 web-client/patches/@stablelib+keyagreement+1.0.1.patch create mode 100644 web-client/patches/@stablelib+random+1.0.1.patch create mode 100644 web-client/patches/@stablelib+sha256+1.0.1.patch create mode 100644 web-client/patches/@stablelib+wipe+1.0.1.patch create mode 100644 web-client/patches/@stablelib+x25519+1.0.2.patch create mode 100644 web-client/src/schema/crypto.spec.ts diff --git a/web-client/package-lock.json b/web-client/package-lock.json index efcc3d4b6..fccb8a8b6 100644 --- a/web-client/package-lock.json +++ b/web-client/package-lock.json @@ -40,6 +40,9 @@ "@ngneat/until-destroy": "^9.2.1", "@sentry/angular": "^6.19.7", "@sentry/capacitor": "^0.6.1", + "@stablelib/hkdf": "^1.0.1", + "@stablelib/sha256": "^1.0.1", + "@stablelib/x25519": "^1.0.3", "@zxing/browser": "^0.1.1", "@zxing/library": "^0.19.1", "@zxing/ngx-scanner": "~3.5.0", @@ -11232,6 +11235,96 @@ "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" }, + "node_modules/@stablelib/binary": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/binary/-/binary-1.0.1.tgz", + "integrity": "sha512-ClJWvmL6UBM/wjkvv/7m5VP3GMr9t0osr4yVgLZsLCOz4hGN9gIAFEqnJ0TsSMAN+n840nf2cHZnA5/KFqHC7Q==", + "dependencies": { + "@stablelib/int": "^1.0.1" + } + }, + "node_modules/@stablelib/bytes": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/bytes/-/bytes-1.0.1.tgz", + "integrity": "sha512-Kre4Y4kdwuqL8BR2E9hV/R5sOrUj6NanZaZis0V6lX5yzqC3hBuVSDXUIBqQv/sCpmuWRiHLwqiT1pqqjuBXoQ==" + }, + "node_modules/@stablelib/constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/constant-time/-/constant-time-1.0.1.tgz", + "integrity": "sha512-tNOs3uD0vSJcK6z1fvef4Y+buN7DXhzHDPqRLSXUel1UfqMB1PWNsnnAezrKfEwTLpN0cGH2p9NNjs6IqeD0eg==" + }, + "node_modules/@stablelib/hash": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/hash/-/hash-1.0.1.tgz", + "integrity": "sha512-eTPJc/stDkdtOcrNMZ6mcMK1e6yBbqRBaNW55XA1jU8w/7QdnCF0CmMmOD1m7VSkBR44PWrMHU2l6r8YEQHMgg==" + }, + "node_modules/@stablelib/hkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/hkdf/-/hkdf-1.0.1.tgz", + "integrity": "sha512-SBEHYE16ZXlHuaW5RcGk533YlBj4grMeg5TooN80W3NpcHRtLZLLXvKyX0qcRFxf+BGDobJLnwkvgEwHIDBR6g==", + "dependencies": { + "@stablelib/hash": "^1.0.1", + "@stablelib/hmac": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "node_modules/@stablelib/hmac": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/hmac/-/hmac-1.0.1.tgz", + "integrity": "sha512-V2APD9NSnhVpV/QMYgCVMIYKiYG6LSqw1S65wxVoirhU/51ACio6D4yDVSwMzuTJXWZoVHbDdINioBwKy5kVmA==", + "dependencies": { + "@stablelib/constant-time": "^1.0.1", + "@stablelib/hash": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "node_modules/@stablelib/int": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/int/-/int-1.0.1.tgz", + "integrity": "sha512-byr69X/sDtDiIjIV6m4roLVWnNNlRGzsvxw+agj8CIEazqWGOQp2dTYgQhtyVXV9wpO6WyXRQUzLV/JRNumT2w==" + }, + "node_modules/@stablelib/keyagreement": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/keyagreement/-/keyagreement-1.0.1.tgz", + "integrity": "sha512-VKL6xBwgJnI6l1jKrBAfn265cspaWBPAPEc62VBQrWHLqVgNRE09gQ/AnOEyKUWrrqfD+xSQ3u42gJjLDdMDQg==", + "dependencies": { + "@stablelib/bytes": "^1.0.1" + } + }, + "node_modules/@stablelib/random": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@stablelib/random/-/random-1.0.2.tgz", + "integrity": "sha512-rIsE83Xpb7clHPVRlBj8qNe5L8ISQOzjghYQm/dZ7VaM2KHYwMW5adjQjrzTZCchFnNCNhkwtnOBa9HTMJCI8w==", + "dependencies": { + "@stablelib/binary": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "node_modules/@stablelib/sha256": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/sha256/-/sha256-1.0.1.tgz", + "integrity": "sha512-GIIH3e6KH+91FqGV42Kcj71Uefd/QEe7Dy42sBTeqppXV95ggCcxLTk39bEr+lZfJmp+ghsR07J++ORkRELsBQ==", + "dependencies": { + "@stablelib/binary": "^1.0.1", + "@stablelib/hash": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "node_modules/@stablelib/wipe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/wipe/-/wipe-1.0.1.tgz", + "integrity": "sha512-WfqfX/eXGiAd3RJe4VU2snh/ZPwtSjLG4ynQ/vYzvghTh7dHFcI1wl+nrkWG6lGhukOxOsUHfv8dUXr58D0ayg==" + }, + "node_modules/@stablelib/x25519": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@stablelib/x25519/-/x25519-1.0.3.tgz", + "integrity": "sha512-KnTbKmUhPhHavzobclVJQG5kuivH+qDLpe84iRqX3CLrKp881cF160JvXJ+hjn1aMyCwYOKeIZefIH/P5cJoRw==", + "dependencies": { + "@stablelib/keyagreement": "^1.0.1", + "@stablelib/random": "^1.0.2", + "@stablelib/wipe": "^1.0.1" + } + }, "node_modules/@stencil/core": { "version": "2.17.3", "resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.17.3.tgz", @@ -55860,6 +55953,96 @@ "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" }, + "@stablelib/binary": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/binary/-/binary-1.0.1.tgz", + "integrity": "sha512-ClJWvmL6UBM/wjkvv/7m5VP3GMr9t0osr4yVgLZsLCOz4hGN9gIAFEqnJ0TsSMAN+n840nf2cHZnA5/KFqHC7Q==", + "requires": { + "@stablelib/int": "^1.0.1" + } + }, + "@stablelib/bytes": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/bytes/-/bytes-1.0.1.tgz", + "integrity": "sha512-Kre4Y4kdwuqL8BR2E9hV/R5sOrUj6NanZaZis0V6lX5yzqC3hBuVSDXUIBqQv/sCpmuWRiHLwqiT1pqqjuBXoQ==" + }, + "@stablelib/constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/constant-time/-/constant-time-1.0.1.tgz", + "integrity": "sha512-tNOs3uD0vSJcK6z1fvef4Y+buN7DXhzHDPqRLSXUel1UfqMB1PWNsnnAezrKfEwTLpN0cGH2p9NNjs6IqeD0eg==" + }, + "@stablelib/hash": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/hash/-/hash-1.0.1.tgz", + "integrity": "sha512-eTPJc/stDkdtOcrNMZ6mcMK1e6yBbqRBaNW55XA1jU8w/7QdnCF0CmMmOD1m7VSkBR44PWrMHU2l6r8YEQHMgg==" + }, + "@stablelib/hkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/hkdf/-/hkdf-1.0.1.tgz", + "integrity": "sha512-SBEHYE16ZXlHuaW5RcGk533YlBj4grMeg5TooN80W3NpcHRtLZLLXvKyX0qcRFxf+BGDobJLnwkvgEwHIDBR6g==", + "requires": { + "@stablelib/hash": "^1.0.1", + "@stablelib/hmac": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "@stablelib/hmac": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/hmac/-/hmac-1.0.1.tgz", + "integrity": "sha512-V2APD9NSnhVpV/QMYgCVMIYKiYG6LSqw1S65wxVoirhU/51ACio6D4yDVSwMzuTJXWZoVHbDdINioBwKy5kVmA==", + "requires": { + "@stablelib/constant-time": "^1.0.1", + "@stablelib/hash": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "@stablelib/int": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/int/-/int-1.0.1.tgz", + "integrity": "sha512-byr69X/sDtDiIjIV6m4roLVWnNNlRGzsvxw+agj8CIEazqWGOQp2dTYgQhtyVXV9wpO6WyXRQUzLV/JRNumT2w==" + }, + "@stablelib/keyagreement": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/keyagreement/-/keyagreement-1.0.1.tgz", + "integrity": "sha512-VKL6xBwgJnI6l1jKrBAfn265cspaWBPAPEc62VBQrWHLqVgNRE09gQ/AnOEyKUWrrqfD+xSQ3u42gJjLDdMDQg==", + "requires": { + "@stablelib/bytes": "^1.0.1" + } + }, + "@stablelib/random": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@stablelib/random/-/random-1.0.2.tgz", + "integrity": "sha512-rIsE83Xpb7clHPVRlBj8qNe5L8ISQOzjghYQm/dZ7VaM2KHYwMW5adjQjrzTZCchFnNCNhkwtnOBa9HTMJCI8w==", + "requires": { + "@stablelib/binary": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "@stablelib/sha256": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/sha256/-/sha256-1.0.1.tgz", + "integrity": "sha512-GIIH3e6KH+91FqGV42Kcj71Uefd/QEe7Dy42sBTeqppXV95ggCcxLTk39bEr+lZfJmp+ghsR07J++ORkRELsBQ==", + "requires": { + "@stablelib/binary": "^1.0.1", + "@stablelib/hash": "^1.0.1", + "@stablelib/wipe": "^1.0.1" + } + }, + "@stablelib/wipe": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/wipe/-/wipe-1.0.1.tgz", + "integrity": "sha512-WfqfX/eXGiAd3RJe4VU2snh/ZPwtSjLG4ynQ/vYzvghTh7dHFcI1wl+nrkWG6lGhukOxOsUHfv8dUXr58D0ayg==" + }, + "@stablelib/x25519": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@stablelib/x25519/-/x25519-1.0.3.tgz", + "integrity": "sha512-KnTbKmUhPhHavzobclVJQG5kuivH+qDLpe84iRqX3CLrKp881cF160JvXJ+hjn1aMyCwYOKeIZefIH/P5cJoRw==", + "requires": { + "@stablelib/keyagreement": "^1.0.1", + "@stablelib/random": "^1.0.2", + "@stablelib/wipe": "^1.0.1" + } + }, "@stencil/core": { "version": "2.17.3", "resolved": "https://registry.npmjs.org/@stencil/core/-/core-2.17.3.tgz", diff --git a/web-client/package.json b/web-client/package.json index 3aac1b5ac..983379162 100644 --- a/web-client/package.json +++ b/web-client/package.json @@ -59,6 +59,9 @@ "@ngneat/until-destroy": "^9.2.1", "@sentry/angular": "^6.19.7", "@sentry/capacitor": "^0.6.1", + "@stablelib/hkdf": "^1.0.1", + "@stablelib/sha256": "^1.0.1", + "@stablelib/x25519": "^1.0.3", "@zxing/browser": "^0.1.1", "@zxing/library": "^0.19.1", "@zxing/ngx-scanner": "~3.5.0", diff --git a/web-client/patches/@stablelib+binary+1.0.1.patch b/web-client/patches/@stablelib+binary+1.0.1.patch new file mode 100644 index 000000000..b89c679bc --- /dev/null +++ b/web-client/patches/@stablelib+binary+1.0.1.patch @@ -0,0 +1,33 @@ +diff --git a/node_modules/@stablelib/binary/tsconfig.json b/node_modules/@stablelib/binary/tsconfig.json +index 81435d2..4082f16 100644 +--- a/node_modules/@stablelib/binary/tsconfig.json ++++ b/node_modules/@stablelib/binary/tsconfig.json +@@ -1,27 +1,3 @@ + { +- "compilerOptions": { +- "target": "es5", +- "module": "commonjs", +- "strict": true, +- "noUnusedParameters": true, +- "noImplicitReturns": true, +- "noUnusedLocals": true, +- "removeComments": false, +- "preserveConstEnums": true, +- "moduleResolution": "node", +- "newLine": "LF", +- "sourceMap": true, +- "declaration": true, +- "outDir": "lib", +- "lib": [ +- "es5", +- "es2015.promise", +- "dom", +- "scripthost" +- ] +- }, +- "exclude": [ +- "node_modules", +- "lib" +- ] ++ "extends": "../../tsconfig.json" + } diff --git a/web-client/patches/@stablelib+bytes+1.0.1.patch b/web-client/patches/@stablelib+bytes+1.0.1.patch new file mode 100644 index 000000000..b356d9992 --- /dev/null +++ b/web-client/patches/@stablelib+bytes+1.0.1.patch @@ -0,0 +1,33 @@ +diff --git a/node_modules/@stablelib/bytes/tsconfig.json b/node_modules/@stablelib/bytes/tsconfig.json +index 81435d2..4082f16 100644 +--- a/node_modules/@stablelib/bytes/tsconfig.json ++++ b/node_modules/@stablelib/bytes/tsconfig.json +@@ -1,27 +1,3 @@ + { +- "compilerOptions": { +- "target": "es5", +- "module": "commonjs", +- "strict": true, +- "noUnusedParameters": true, +- "noImplicitReturns": true, +- "noUnusedLocals": true, +- "removeComments": false, +- "preserveConstEnums": true, +- "moduleResolution": "node", +- "newLine": "LF", +- "sourceMap": true, +- "declaration": true, +- "outDir": "lib", +- "lib": [ +- "es5", +- "es2015.promise", +- "dom", +- "scripthost" +- ] +- }, +- "exclude": [ +- "node_modules", +- "lib" +- ] ++ "extends": "../../tsconfig.json" + } diff --git a/web-client/patches/@stablelib+constant-time+1.0.1.patch b/web-client/patches/@stablelib+constant-time+1.0.1.patch new file mode 100644 index 000000000..efcf00bca --- /dev/null +++ b/web-client/patches/@stablelib+constant-time+1.0.1.patch @@ -0,0 +1,33 @@ +diff --git a/node_modules/@stablelib/constant-time/tsconfig.json b/node_modules/@stablelib/constant-time/tsconfig.json +index 81435d2..4082f16 100644 +--- a/node_modules/@stablelib/constant-time/tsconfig.json ++++ b/node_modules/@stablelib/constant-time/tsconfig.json +@@ -1,27 +1,3 @@ + { +- "compilerOptions": { +- "target": "es5", +- "module": "commonjs", +- "strict": true, +- "noUnusedParameters": true, +- "noImplicitReturns": true, +- "noUnusedLocals": true, +- "removeComments": false, +- "preserveConstEnums": true, +- "moduleResolution": "node", +- "newLine": "LF", +- "sourceMap": true, +- "declaration": true, +- "outDir": "lib", +- "lib": [ +- "es5", +- "es2015.promise", +- "dom", +- "scripthost" +- ] +- }, +- "exclude": [ +- "node_modules", +- "lib" +- ] ++ "extends": "../../tsconfig.json" + } diff --git a/web-client/patches/@stablelib+hash+1.0.1.patch b/web-client/patches/@stablelib+hash+1.0.1.patch new file mode 100644 index 000000000..0e540cff2 --- /dev/null +++ b/web-client/patches/@stablelib+hash+1.0.1.patch @@ -0,0 +1,33 @@ +diff --git a/node_modules/@stablelib/hash/tsconfig.json b/node_modules/@stablelib/hash/tsconfig.json +index 81435d2..4082f16 100644 +--- a/node_modules/@stablelib/hash/tsconfig.json ++++ b/node_modules/@stablelib/hash/tsconfig.json +@@ -1,27 +1,3 @@ + { +- "compilerOptions": { +- "target": "es5", +- "module": "commonjs", +- "strict": true, +- "noUnusedParameters": true, +- "noImplicitReturns": true, +- "noUnusedLocals": true, +- "removeComments": false, +- "preserveConstEnums": true, +- "moduleResolution": "node", +- "newLine": "LF", +- "sourceMap": true, +- "declaration": true, +- "outDir": "lib", +- "lib": [ +- "es5", +- "es2015.promise", +- "dom", +- "scripthost" +- ] +- }, +- "exclude": [ +- "node_modules", +- "lib" +- ] ++ "extends": "../../tsconfig.json" + } diff --git a/web-client/patches/@stablelib+hkdf+1.0.1.patch b/web-client/patches/@stablelib+hkdf+1.0.1.patch new file mode 100644 index 000000000..2a70b035d --- /dev/null +++ b/web-client/patches/@stablelib+hkdf+1.0.1.patch @@ -0,0 +1,33 @@ +diff --git a/node_modules/@stablelib/hkdf/tsconfig.json b/node_modules/@stablelib/hkdf/tsconfig.json +index 81435d2..4082f16 100644 +--- a/node_modules/@stablelib/hkdf/tsconfig.json ++++ b/node_modules/@stablelib/hkdf/tsconfig.json +@@ -1,27 +1,3 @@ + { +- "compilerOptions": { +- "target": "es5", +- "module": "commonjs", +- "strict": true, +- "noUnusedParameters": true, +- "noImplicitReturns": true, +- "noUnusedLocals": true, +- "removeComments": false, +- "preserveConstEnums": true, +- "moduleResolution": "node", +- "newLine": "LF", +- "sourceMap": true, +- "declaration": true, +- "outDir": "lib", +- "lib": [ +- "es5", +- "es2015.promise", +- "dom", +- "scripthost" +- ] +- }, +- "exclude": [ +- "node_modules", +- "lib" +- ] ++ "extends": "../../tsconfig.json" + } diff --git a/web-client/patches/@stablelib+hmac+1.0.1.patch b/web-client/patches/@stablelib+hmac+1.0.1.patch new file mode 100644 index 000000000..0a64b2d03 --- /dev/null +++ b/web-client/patches/@stablelib+hmac+1.0.1.patch @@ -0,0 +1,33 @@ +diff --git a/node_modules/@stablelib/hmac/tsconfig.json b/node_modules/@stablelib/hmac/tsconfig.json +index 81435d2..4082f16 100644 +--- a/node_modules/@stablelib/hmac/tsconfig.json ++++ b/node_modules/@stablelib/hmac/tsconfig.json +@@ -1,27 +1,3 @@ + { +- "compilerOptions": { +- "target": "es5", +- "module": "commonjs", +- "strict": true, +- "noUnusedParameters": true, +- "noImplicitReturns": true, +- "noUnusedLocals": true, +- "removeComments": false, +- "preserveConstEnums": true, +- "moduleResolution": "node", +- "newLine": "LF", +- "sourceMap": true, +- "declaration": true, +- "outDir": "lib", +- "lib": [ +- "es5", +- "es2015.promise", +- "dom", +- "scripthost" +- ] +- }, +- "exclude": [ +- "node_modules", +- "lib" +- ] ++ "extends": "../../tsconfig.json" + } diff --git a/web-client/patches/@stablelib+int+1.0.1.patch b/web-client/patches/@stablelib+int+1.0.1.patch new file mode 100644 index 000000000..16c241932 --- /dev/null +++ b/web-client/patches/@stablelib+int+1.0.1.patch @@ -0,0 +1,33 @@ +diff --git a/node_modules/@stablelib/int/tsconfig.json b/node_modules/@stablelib/int/tsconfig.json +index 81435d2..4082f16 100644 +--- a/node_modules/@stablelib/int/tsconfig.json ++++ b/node_modules/@stablelib/int/tsconfig.json +@@ -1,27 +1,3 @@ + { +- "compilerOptions": { +- "target": "es5", +- "module": "commonjs", +- "strict": true, +- "noUnusedParameters": true, +- "noImplicitReturns": true, +- "noUnusedLocals": true, +- "removeComments": false, +- "preserveConstEnums": true, +- "moduleResolution": "node", +- "newLine": "LF", +- "sourceMap": true, +- "declaration": true, +- "outDir": "lib", +- "lib": [ +- "es5", +- "es2015.promise", +- "dom", +- "scripthost" +- ] +- }, +- "exclude": [ +- "node_modules", +- "lib" +- ] ++ "extends": "../../tsconfig.json" + } diff --git a/web-client/patches/@stablelib+keyagreement+1.0.1.patch b/web-client/patches/@stablelib+keyagreement+1.0.1.patch new file mode 100644 index 000000000..a113da969 --- /dev/null +++ b/web-client/patches/@stablelib+keyagreement+1.0.1.patch @@ -0,0 +1,33 @@ +diff --git a/node_modules/@stablelib/keyagreement/tsconfig.json b/node_modules/@stablelib/keyagreement/tsconfig.json +index 81435d2..4082f16 100644 +--- a/node_modules/@stablelib/keyagreement/tsconfig.json ++++ b/node_modules/@stablelib/keyagreement/tsconfig.json +@@ -1,27 +1,3 @@ + { +- "compilerOptions": { +- "target": "es5", +- "module": "commonjs", +- "strict": true, +- "noUnusedParameters": true, +- "noImplicitReturns": true, +- "noUnusedLocals": true, +- "removeComments": false, +- "preserveConstEnums": true, +- "moduleResolution": "node", +- "newLine": "LF", +- "sourceMap": true, +- "declaration": true, +- "outDir": "lib", +- "lib": [ +- "es5", +- "es2015.promise", +- "dom", +- "scripthost" +- ] +- }, +- "exclude": [ +- "node_modules", +- "lib" +- ] ++ "extends": "../../tsconfig.json" + } diff --git a/web-client/patches/@stablelib+random+1.0.1.patch b/web-client/patches/@stablelib+random+1.0.1.patch new file mode 100644 index 000000000..b87f3080b --- /dev/null +++ b/web-client/patches/@stablelib+random+1.0.1.patch @@ -0,0 +1,29 @@ +diff --git a/node_modules/@stablelib/random/source/browser.ts b/node_modules/@stablelib/random/source/browser.ts +index b25887b..a016ebb 100644 +--- a/node_modules/@stablelib/random/source/browser.ts ++++ b/node_modules/@stablelib/random/source/browser.ts +@@ -16,7 +16,7 @@ export class BrowserRandomSource implements RandomSource { + ? (self.crypto || (self as { msCrypto?: any }).msCrypto) // IE11 has msCrypto + : null; + +- if (browserCrypto && browserCrypto.getRandomValues !== undefined) { ++ if (browserCrypto && browserCrypto.getRandomValues) { + this._crypto = browserCrypto; + this.isAvailable = true; + this.isInstantiated = true; +diff --git a/node_modules/@stablelib/random/tsconfig.json b/node_modules/@stablelib/random/tsconfig.json +index 5d5a801..4082f16 100644 +--- a/node_modules/@stablelib/random/tsconfig.json ++++ b/node_modules/@stablelib/random/tsconfig.json +@@ -1,10 +1,3 @@ + { +- "extends": "../../configs/tsconfig.json", +- "compilerOptions": { +- "outDir": "lib", +- }, +- "exclude": [ +- "node_modules", +- "lib" +- ] ++ "extends": "../../tsconfig.json" + } diff --git a/web-client/patches/@stablelib+sha256+1.0.1.patch b/web-client/patches/@stablelib+sha256+1.0.1.patch new file mode 100644 index 000000000..a53af62fa --- /dev/null +++ b/web-client/patches/@stablelib+sha256+1.0.1.patch @@ -0,0 +1,33 @@ +diff --git a/node_modules/@stablelib/sha256/tsconfig.json b/node_modules/@stablelib/sha256/tsconfig.json +index 81435d2..4082f16 100644 +--- a/node_modules/@stablelib/sha256/tsconfig.json ++++ b/node_modules/@stablelib/sha256/tsconfig.json +@@ -1,27 +1,3 @@ + { +- "compilerOptions": { +- "target": "es5", +- "module": "commonjs", +- "strict": true, +- "noUnusedParameters": true, +- "noImplicitReturns": true, +- "noUnusedLocals": true, +- "removeComments": false, +- "preserveConstEnums": true, +- "moduleResolution": "node", +- "newLine": "LF", +- "sourceMap": true, +- "declaration": true, +- "outDir": "lib", +- "lib": [ +- "es5", +- "es2015.promise", +- "dom", +- "scripthost" +- ] +- }, +- "exclude": [ +- "node_modules", +- "lib" +- ] ++ "extends": "../../tsconfig.json" + } diff --git a/web-client/patches/@stablelib+wipe+1.0.1.patch b/web-client/patches/@stablelib+wipe+1.0.1.patch new file mode 100644 index 000000000..aaa8389b3 --- /dev/null +++ b/web-client/patches/@stablelib+wipe+1.0.1.patch @@ -0,0 +1,33 @@ +diff --git a/node_modules/@stablelib/wipe/tsconfig.json b/node_modules/@stablelib/wipe/tsconfig.json +index 81435d2..4082f16 100644 +--- a/node_modules/@stablelib/wipe/tsconfig.json ++++ b/node_modules/@stablelib/wipe/tsconfig.json +@@ -1,27 +1,3 @@ + { +- "compilerOptions": { +- "target": "es5", +- "module": "commonjs", +- "strict": true, +- "noUnusedParameters": true, +- "noImplicitReturns": true, +- "noUnusedLocals": true, +- "removeComments": false, +- "preserveConstEnums": true, +- "moduleResolution": "node", +- "newLine": "LF", +- "sourceMap": true, +- "declaration": true, +- "outDir": "lib", +- "lib": [ +- "es5", +- "es2015.promise", +- "dom", +- "scripthost" +- ] +- }, +- "exclude": [ +- "node_modules", +- "lib" +- ] ++ "extends": "../../tsconfig.json" + } diff --git a/web-client/patches/@stablelib+x25519+1.0.2.patch b/web-client/patches/@stablelib+x25519+1.0.2.patch new file mode 100644 index 000000000..cda42de5b --- /dev/null +++ b/web-client/patches/@stablelib+x25519+1.0.2.patch @@ -0,0 +1,16 @@ +diff --git a/node_modules/@stablelib/x25519/tsconfig.json b/node_modules/@stablelib/x25519/tsconfig.json +index 5d5a801..4082f16 100644 +--- a/node_modules/@stablelib/x25519/tsconfig.json ++++ b/node_modules/@stablelib/x25519/tsconfig.json +@@ -1,10 +1,3 @@ + { +- "extends": "../../configs/tsconfig.json", +- "compilerOptions": { +- "outDir": "lib", +- }, +- "exclude": [ +- "node_modules", +- "lib" +- ] ++ "extends": "../../tsconfig.json" + } diff --git a/web-client/src/schema/crypto.spec.ts b/web-client/src/schema/crypto.spec.ts new file mode 100644 index 000000000..2fafb3302 --- /dev/null +++ b/web-client/src/schema/crypto.spec.ts @@ -0,0 +1,26 @@ +import { HKDF } from '@stablelib/hkdf'; +import { SHA256 } from '@stablelib/sha256'; +import { X25519KeyAgreement } from '@stablelib/x25519/lib/keyagreement'; +import { DiffieHellman, PublicKey, SharedSecret } from './crypto'; + +describe('DiffieHellman', () => { + it('successfully established a shared secret', () => { + const clientSide = DiffieHellman.from_seed( + new Uint8Array(32).fill(111), + new Uint8Array(32).fill(123) + ); + const serverSide = new X25519KeyAgreement(new Uint8Array(32).fill(222)); + const salt = new Uint8Array(32); + + const clientPk: PublicKey = clientSide.x25519_public_key(); + const serverRawSecret: SharedSecret = serverSide + .finish(clientPk) + .getSharedKey(); + const serverHkdf = new HKDF(SHA256, serverRawSecret, salt); + const serverSecret: SharedSecret = serverHkdf.expand(32); + + const serverPk: PublicKey = serverSide.offer(); + const clientSecret: SharedSecret = clientSide.diffie_hellman(serverPk); + expect(clientSecret).toEqual(serverSecret); + }); +}); diff --git a/web-client/src/schema/crypto.ts b/web-client/src/schema/crypto.ts index a71ee3313..c50381297 100644 --- a/web-client/src/schema/crypto.ts +++ b/web-client/src/schema/crypto.ts @@ -2,6 +2,9 @@ * Interface patterned after `SodaBoxCrypto` on the server, but implemented using TweetNaCl. */ +import { HKDF } from '@stablelib/hkdf/lib/hkdf'; +import { SHA256 } from '@stablelib/sha256/lib/sha256'; +import { X25519KeyAgreement } from '@stablelib/x25519/lib/keyagreement'; import * as nacl from 'tweetnacl'; import { BoxKeyPair } from 'tweetnacl'; import { Bytes, Bytes24, Bytes32 } from './types'; @@ -11,12 +14,12 @@ export type PrivateKey = Bytes32; export type Nonce = Bytes24; type EncryptedMessage = { - ciphertext: Bytes; + ciphertext: Bytes32; nonce: Bytes24; }; export class TweetNaClCrypto { - constructor(public keyPair: BoxKeyPair) {} + constructor(public keyPair: BoxKeyPair) { } get public_key(): PublicKey { return this.keyPair.publicKey; @@ -29,15 +32,100 @@ export class TweetNaClCrypto { static new = (): TweetNaClCrypto => new TweetNaClCrypto(nacl.box.keyPair()); decrypt_message = ( - ciphertext: Bytes, + ciphertext: Bytes32, their_pk: PublicKey, nonce: Nonce ): Uint8Array | null => nacl.box.open(ciphertext, nonce, their_pk, this.secret_key); - encrypt_message = (message: Bytes, their_pk: PublicKey): EncryptedMessage => { + encrypt_message = ( + message: Bytes32, + their_pk: PublicKey + ): EncryptedMessage => { const nonce = nacl.randomBytes(nacl.box.nonceLength); const ciphertext = nacl.box(message, nonce, their_pk, this.secret_key); return { ciphertext, nonce }; }; } + +/** + * A shared secret acquired via a DH key agreement + */ +export type SharedSecret = Bytes32; +/** + * A public salt value + */ +export type Salt = Bytes; +/** + * A seed used to instantiate a random number generator such as when generating + * a random key pair. + */ +export type Seed = Bytes32; + +/** + * Diffie-Hellman (DH) key agreement in order to establish shared secrets. + * + * This allows us to establish "session keys" for the authentication of + * multi-step exchanges between the client and server. + */ + +type KeyAgreementFinished = boolean; +export class DiffieHellman { + protected finished: KeyAgreementFinished = false; + protected hkdfSalt: Salt = new Uint8Array(0); + protected ourPk?: PublicKey; + protected x25519: X25519KeyAgreement = new X25519KeyAgreement(); + + protected constructor(hkdfSalt: Salt, seed?: Bytes32); + protected constructor(seed?: Bytes32) { + this.x25519 = new X25519KeyAgreement(seed); + } + + /** + * Instantiate a new key agreement using a keypair generated from a seed. + * Generally, this method should be avoided and `new` should be used in its + * place. + */ + static from_seed = ( + seed: Bytes32, + salt: Salt = new Uint8Array(0) + ): DiffieHellman => new DiffieHellman(salt, seed); + + /** + * Instantiate a new key agreement using a randomly generated keypair. + */ + static new = (salt: Salt = new Uint8Array(0)): DiffieHellman => + new DiffieHellman(salt); + + /** + * Derive a new key pair and return the public key. Otherwise, return a + * previously cached public key. + */ + x25519_public_key = (): PublicKey => { + if (this.ourPk === undefined) { + this.ourPk = this.x25519.offer(); + } + return this.ourPk; + }; + + /** + * Complete the ECDH operation in order to obtain a shared secret. + */ + diffie_hellman = ( + their_pk: PublicKey, + secret_length: number = 32 + ): SharedSecret => { + this.finish(their_pk); + const raw_shared_key: SharedSecret = this.x25519.getSharedKey(); + + // RFC 7748 recommends applying a KDF to the raw shared key + const hkdf = new HKDF(SHA256, raw_shared_key, this.hkdfSalt); + return hkdf.expand(secret_length); + }; + + protected finish = (their_pk: PublicKey): void => { + if (!this.finished) { + this.x25519 = this.x25519.finish(their_pk); + } + }; +}