From a769402c0c35b3d09e6e2b075511949a4e4a7b95 Mon Sep 17 00:00:00 2001 From: Jack Lloyd Date: Wed, 27 Jan 2021 17:39:09 -0500 Subject: [PATCH] Use the libsignal-client for curve operations --- ACKNOWLEDGMENTS.md | 25 ------------- package.json | 15 ++++---- preload.js | 54 ++++++++++++++++++----------- scripts/generate-acknowledgments.js | 6 +++- ts/curve25519-n.d.ts | 16 --------- ts/updater/curve.ts | 27 +++++++-------- yarn.lock | 15 ++++---- 7 files changed, 67 insertions(+), 91 deletions(-) delete mode 100644 ts/curve25519-n.d.ts diff --git a/ACKNOWLEDGMENTS.md b/ACKNOWLEDGMENTS.md index 0949a3e22e2..9858487ce69 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 f5aff7d33f8..ff93b5e2792 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 35d3c1dd4e0..56549355bb9 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 67c0665dbcb..708bc8adf95 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 7375fca6c14..00000000000 --- 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 029add7124e..df0e5335819 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 93c7137693e..d32b7f56e37 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==