diff --git a/ACKNOWLEDGMENTS.md b/ACKNOWLEDGMENTS.md index 0949a3e22..9858487ce 100644 --- a/ACKNOWLEDGMENTS.md +++ b/ACKNOWLEDGMENTS.md @@ -446,31 +446,6 @@ Signal Desktop makes use of the following open source projects. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -## curve25519-n - - Copyright (c) 2011 Jann Horn - - This license and copyright notice don't apply to the file curve25519-donna.c, - look into it. - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - ## dashdash # This is the MIT license diff --git a/package.json b/package.json index f5aff7d33..ff93b5e27 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,6 @@ "classnames": "2.2.5", "config": "1.28.1", "copy-text-to-clipboard": "2.1.0", - "curve25519-n": "https://github.com/scottnonnenberg-signal/node-curve25519.git#3e94f60bc54b2426476520d8d1a0aa835c25f5cc", "dashdash": "1.14.1", "emoji-datasource": "6.0.0", "emoji-datasource-apple": "6.0.0", @@ -149,7 +148,8 @@ "underscore": "1.9.0", "uuid": "3.3.2", "websocket": "1.0.28", - "zkgroup": "https://github.com/signalapp/signal-zkgroup-node.git#2d7db946cc88492b65cc66e9aa9de0c9e664fd8d" + "zkgroup": "https://github.com/signalapp/signal-zkgroup-node.git#2d7db946cc88492b65cc66e9aa9de0c9e664fd8d", + "libsignal-client": "https://github.com/signalapp/libsignal-client-node.git#b6f498fa544bcce3bee0be037a7b6445d4efda45" }, "devDependencies": { "@babel/core": "7.7.7", @@ -273,7 +273,8 @@ "mac": { "asarUnpack": [ "**/*.node", - "node_modules/zkgroup/libzkgroup.*" + "node_modules/zkgroup/libzkgroup.*", + "node_modules/libsignal-client/build/*.node" ], "artifactName": "${name}-mac-${version}.${ext}", "category": "public.app-category.social-networking", @@ -298,7 +299,8 @@ "**/*.node", "node_modules/spellchecker/vendor/hunspell_dictionaries", "node_modules/sharp", - "node_modules/zkgroup/libzkgroup.*" + "node_modules/zkgroup/libzkgroup.*", + "node_modules/libsignal-client/build/*.node" ], "artifactName": "${name}-win-${version}.${ext}", "certificateSubjectName": "Signal (Quiet Riddle Ventures, LLC)", @@ -327,7 +329,8 @@ "**/*.node", "node_modules/spellchecker/vendor/hunspell_dictionaries", "node_modules/sharp", - "node_modules/zkgroup/libzkgroup.*" + "node_modules/zkgroup/libzkgroup.*", + "node_modules/libsignal-client/build/*.node" ], "target": [ "deb" @@ -397,7 +400,6 @@ "!**/{.DS_Store,.git,.hg,.svn,CVS,RCS,SCCS,__pycache__,thumbs.db,.gitignore,.gitattributes,.flowconfig,.yarn-metadata.json,.idea,appveyor.yml,.travis.yml,circle.yml,npm-debug.log,.nyc_output,yarn.lock,.yarn-integrity}", "node_modules/spellchecker/build/Release/*.node", "node_modules/websocket/build/Release/*.node", - "node_modules/curve25519-n/build/Release/*.node", "node_modules/ref-napi/build/Release/*.node", "node_modules/ffi-napi/build/Release/*.node", "node_modules/socks/build/*.js", @@ -409,6 +411,7 @@ "!node_modules/@journeyapps/sqlcipher/deps/*", "!node_modules/@journeyapps/sqlcipher/build/*", "!node_modules/@journeyapps/sqlcipher/lib/binding/node-*", + "node_modules/libsignal-client/build/*.node", "node_modules/ringrtc/build/${platform}/**" ] } diff --git a/preload.js b/preload.js index 35d3c1dd4..56549355b 100644 --- a/preload.js +++ b/preload.js @@ -8,7 +8,7 @@ try { const electron = require('electron'); const semver = require('semver'); - const curve = require('curve25519-n'); + const client = require('libsignal-client'); const _ = require('lodash'); const { installGetter, installSetter } = require('./preload_utils'); @@ -484,40 +484,45 @@ try { } const externalCurve = { generateKeyPair: () => { - const { privKey, pubKey } = curve.generateKeyPair(); + const privKey = client.PrivateKey.generate(); + const pubKey = privKey.getPublicKey(); return { - privKey: window.Signal.Crypto.typedArrayToArrayBuffer(privKey), - pubKey: window.Signal.Crypto.typedArrayToArrayBuffer(pubKey), + privKey: privKey.serialize().buffer, + pubKey: pubKey.serialize().buffer, }; }, createKeyPair: incomingKey => { const incomingKeyBuffer = Buffer.from(incomingKey); - const { privKey, pubKey } = curve.createKeyPair(incomingKeyBuffer); + const privKey = client.PrivateKey.deserialize(incomingKeyBuffer); + const pubKey = privKey.getPublicKey(); return { - privKey: window.Signal.Crypto.typedArrayToArrayBuffer(privKey), - pubKey: window.Signal.Crypto.typedArrayToArrayBuffer(pubKey), + privKey: privKey.serialize().buffer, + pubKey: pubKey.serialize().buffer, }; }, calculateAgreement: (pubKey, privKey) => { const pubKeyBuffer = Buffer.from(pubKey); const privKeyBuffer = Buffer.from(privKey); - const buffer = curve.calculateAgreement(pubKeyBuffer, privKeyBuffer); - - return window.Signal.Crypto.typedArrayToArrayBuffer(buffer); + const pubKeyObj = client.PublicKey.deserialize( + Buffer.concat([ + Buffer.from([0x05]), + externalCurve.validatePubKeyFormat(pubKeyBuffer), + ]) + ); + const privKeyObj = client.PrivateKey.deserialize(privKeyBuffer); + const sharedSecret = privKeyObj.agree(pubKeyObj); + return sharedSecret.buffer; }, verifySignature: (pubKey, message, signature) => { const pubKeyBuffer = Buffer.from(pubKey); const messageBuffer = Buffer.from(message); const signatureBuffer = Buffer.from(signature); - const result = curve.verifySignature( - pubKeyBuffer, - messageBuffer, - signatureBuffer - ); + const pubKeyObj = client.PublicKey.deserialize(pubKeyBuffer); + const result = !pubKeyObj.verify(messageBuffer, signatureBuffer); return result; }, @@ -525,14 +530,23 @@ try { const privKeyBuffer = Buffer.from(privKey); const messageBuffer = Buffer.from(message); - const buffer = curve.calculateSignature(privKeyBuffer, messageBuffer); - - return window.Signal.Crypto.typedArrayToArrayBuffer(buffer); + const privKeyObj = client.PrivateKey.deserialize(privKeyBuffer); + const signature = privKeyObj.sign(messageBuffer); + return signature.buffer; }, validatePubKeyFormat: pubKey => { - const pubKeyBuffer = Buffer.from(pubKey); + if ( + pubKey === undefined || + ((pubKey.byteLength !== 33 || new Uint8Array(pubKey)[0] !== 5) && + pubKey.byteLength !== 32) + ) { + throw new Error('Invalid public key'); + } + if (pubKey.byteLength === 33) { + return pubKey.slice(1); + } - return curve.validatePubKeyFormat(pubKeyBuffer); + return pubKey; }, }; externalCurve.ECDHE = externalCurve.calculateAgreement; diff --git a/scripts/generate-acknowledgments.js b/scripts/generate-acknowledgments.js index 67c0665db..708bc8adf 100644 --- a/scripts/generate-acknowledgments.js +++ b/scripts/generate-acknowledgments.js @@ -13,7 +13,11 @@ const { optionalDependencies = {}, } = require('../package.json'); -const SKIPPED_DEPENDENCIES = new Set(['ringrtc', 'zkgroup']); +const SKIPPED_DEPENDENCIES = new Set([ + 'ringrtc', + 'zkgroup', + 'libsignal-client', +]); const rootDir = join(__dirname, '..'); const nodeModulesPath = join(rootDir, 'node_modules'); diff --git a/ts/curve25519-n.d.ts b/ts/curve25519-n.d.ts deleted file mode 100644 index 7375fca6c..000000000 --- a/ts/curve25519-n.d.ts +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2019-2020 Signal Messenger, LLC -// SPDX-License-Identifier: AGPL-3.0-only - -declare module 'curve25519-n' { - export function generateKeyPair( - privKey: Buffer - ): { pubKey: Buffer; privKey: Buffer }; - - export function calculateSignature(privKey: Buffer, message: Buffer): Buffer; - - export function verifySignature( - publicKey: Buffer, - message: Buffer, - signature: Buffer - ): Buffer; -} diff --git a/ts/updater/curve.ts b/ts/updater/curve.ts index 029add712..df0e53358 100644 --- a/ts/updater/curve.ts +++ b/ts/updater/curve.ts @@ -1,25 +1,22 @@ -// Copyright 2019-2020 Signal Messenger, LLC +// Copyright 2019-2021 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only -import { randomBytes } from 'crypto'; -import { - calculateSignature, - generateKeyPair, - verifySignature, -} from 'curve25519-n'; +import { PrivateKey, PublicKey } from 'libsignal-client'; export function keyPair(): Record { - const privateKey = randomBytes(32); - const { pubKey, privKey } = generateKeyPair(privateKey); + const privKey = PrivateKey.generate(); + const pubKey = privKey.getPublicKey(); return { - publicKey: pubKey, - privateKey: privKey, + publicKey: pubKey.serialize(), + privateKey: privKey.serialize(), }; } export function sign(privateKey: Buffer, message: Buffer): Buffer { - return calculateSignature(privateKey, message); + const privKeyObj = PrivateKey.deserialize(privateKey); + const signature = privKeyObj.sign(message); + return signature; } export function verify( @@ -27,7 +24,7 @@ export function verify( message: Buffer, signature: Buffer ): boolean { - const failed = verifySignature(publicKey, message, signature); - - return !failed; + const pubKeyObj = PublicKey.deserialize(publicKey); + const result = pubKeyObj.verify(message, signature); + return result; } diff --git a/yarn.lock b/yarn.lock index 93c713769..d32b7f56e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5739,13 +5739,6 @@ currently-unhandled@^0.4.1: dependencies: array-find-index "^1.0.1" -"curve25519-n@https://github.com/scottnonnenberg-signal/node-curve25519.git#3e94f60bc54b2426476520d8d1a0aa835c25f5cc": - version "1.5.0" - resolved "https://github.com/scottnonnenberg-signal/node-curve25519.git#3e94f60bc54b2426476520d8d1a0aa835c25f5cc" - dependencies: - bindings "^1.5.0" - nan "^2.14.0" - cyclist@~0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640" @@ -10290,6 +10283,12 @@ levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" +"libsignal-client@https://github.com/signalapp/libsignal-client-node.git#b6f498fa544bcce3bee0be037a7b6445d4efda45": + version "0.2.0" + resolved "https://github.com/signalapp/libsignal-client-node.git#b6f498fa544bcce3bee0be037a7b6445d4efda45" + dependencies: + bindings "^1.5.0" + lie@*: version "3.2.0" resolved "https://registry.yarnpkg.com/lie/-/lie-3.2.0.tgz#4f13f2f8bbb027d383db338c43043545791aa8dc" @@ -11271,7 +11270,7 @@ nan@^2.10.0, nan@^2.11.0: resolved "https://registry.yarnpkg.com/nan/-/nan-2.11.1.tgz#90e22bccb8ca57ea4cd37cc83d3819b52eea6766" integrity sha512-iji6k87OSXa0CcrLl9z+ZiYSuR2o+c0bGuNmXdrhTQTakxytAFsC56SArGYoiHlJlFoHSnvmhpceZJaXkVuOtA== -nan@^2.12.1, nan@^2.13.2, nan@^2.14.0: +nan@^2.12.1, nan@^2.13.2: version "2.14.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==