diff --git a/js/modules/loki_rpc.js b/js/modules/loki_rpc.js index 89d2ba615..14d01f8aa 100644 --- a/js/modules/loki_rpc.js +++ b/js/modules/loki_rpc.js @@ -15,23 +15,6 @@ const endpointBase = '/storage_rpc/v1'; // Request index for debugging let onionReqIdx = 0; -const decryptResponse = async (response, address) => { - let plaintext = false; - try { - const ciphertext = await response.text(); - plaintext = await libloki.crypto.snodeCipher.decrypt(address, ciphertext); - const result = plaintext === '' ? {} : JSON.parse(plaintext); - return result; - } catch (e) { - log.warn( - `Could not decrypt response [${plaintext}] from [${address}],`, - e.code, - e.message - ); - } - return {}; -}; - const timeoutDelay = ms => new Promise(resolve => setTimeout(resolve, ms)); const encryptForNode = async (node, payload) => { @@ -234,7 +217,7 @@ const sendToProxy = async (options = {}, targetNode, retryNumber = 0) => { const snPubkeyHex = StringView.hexToArrayBuffer(targetNode.pubkey_x25519); - const myKeys = window.libloki.crypto.snodeCipher._ephemeralKeyPair; + const myKeys = window.libloki.crypto.generateEphemeralKeyPair(); const symmetricKey = libsignal.Curve.calculateAgreement( snPubkeyHex, @@ -428,25 +411,6 @@ const lokiFetch = async (url, options = {}, targetNode = null) => { const method = options.method || 'GET'; const address = parse(url).hostname; - // const doEncryptChannel = address.endsWith('.snode'); - const doEncryptChannel = false; // ENCRYPTION DISABLED - if (doEncryptChannel) { - try { - // eslint-disable-next-line no-param-reassign - options.body = await libloki.crypto.snodeCipher.encrypt( - address, - options.body - ); - // eslint-disable-next-line no-param-reassign - options.headers = { - ...options.headers, - 'Content-Type': 'text/plain', - [LOKI_EPHEMKEY_HEADER]: libloki.crypto.snodeCipher.getChannelPublicKeyHex(), - }; - } catch (e) { - log.warn(`Could not encrypt channel for ${address}: `, e); - } - } const fetchOptions = { ...options, @@ -512,22 +476,14 @@ const lokiFetch = async (url, options = {}, targetNode = null) => { let result; // Wrong swarm if (response.status === 421) { - if (doEncryptChannel) { - result = decryptResponse(response, address); - } else { - result = await response.json(); - } + result = await response.json(); const newSwarm = result.snodes ? result.snodes : []; throw new textsecure.WrongSwarmError(newSwarm); } // Wrong PoW difficulty if (response.status === 432) { - if (doEncryptChannel) { - result = decryptResponse(response, address); - } else { - result = await response.json(); - } + result = await response.json(); const { difficulty } = result; throw new textsecure.WrongDifficultyError(difficulty); } @@ -546,8 +502,6 @@ const lokiFetch = async (url, options = {}, targetNode = null) => { result = await response.json(); } else if (options.responseType === 'arraybuffer') { result = await response.buffer(); - } else if (doEncryptChannel) { - result = decryptResponse(response, address); } else { result = await response.text(); } diff --git a/libloki/crypto.js b/libloki/crypto.js index d5a23c619..23a7f68c7 100644 --- a/libloki/crypto.js +++ b/libloki/crypto.js @@ -136,15 +136,6 @@ const base32zIndex = Multibase.names.indexOf('base32z'); const base32zCode = Multibase.codes[base32zIndex]; - function bufferToArrayBuffer(buf) { - const ab = new ArrayBuffer(buf.length); - const view = new Uint8Array(ab); - for (let i = 0; i < buf.length; i += 1) { - view[i] = buf[i]; - } - return ab; - } - function decodeSnodeAddressToPubKey(snodeAddress) { const snodeAddressClean = snodeAddress .replace('.snode', '') @@ -160,64 +151,6 @@ return keys; } - class LokiSnodeChannel { - constructor() { - this._ephemeralKeyPair = generateEphemeralKeyPair(); - this._ephemeralPubKeyHex = StringView.arrayBufferToHex( - this._ephemeralKeyPair.pubKey - ); - this._cache = {}; - } - - async _getSymmetricKey(snodeAddress) { - if (snodeAddress in this._cache) { - return this._cache[snodeAddress]; - } - const ed25519PubKey = decodeSnodeAddressToPubKey(snodeAddress); - const sodium = await window.getSodium(); - const curve25519PubKey = sodium.crypto_sign_ed25519_pk_to_curve25519( - ed25519PubKey - ); - const snodePubKeyArrayBuffer = bufferToArrayBuffer(curve25519PubKey); - const symmetricKey = libsignal.Curve.calculateAgreement( - snodePubKeyArrayBuffer, - this._ephemeralKeyPair.privKey - ); - this._cache[snodeAddress] = symmetricKey; - return symmetricKey; - } - - getChannelPublicKeyHex() { - return this._ephemeralPubKeyHex; - } - - async decrypt(snodeAddress, ivAndCiphertextBase64) { - const ivAndCiphertext = dcodeIO.ByteBuffer.wrap( - ivAndCiphertextBase64, - 'base64' - ).toArrayBuffer(); - const symmetricKey = await this._getSymmetricKey(snodeAddress); - try { - const decrypted = await DHDecrypt(symmetricKey, ivAndCiphertext); - const decoder = new TextDecoder(); - return decoder.decode(decrypted); - } catch (e) { - return ivAndCiphertext; - } - } - - async encrypt(snodeAddress, plainText) { - if (typeof plainText === 'string') { - const textEncoder = new TextEncoder(); - // eslint-disable-next-line no-param-reassign - plainText = textEncoder.encode(plainText); - } - const symmetricKey = await this._getSymmetricKey(snodeAddress); - const ciphertext = await DHEncrypt(symmetricKey, plainText); - return dcodeIO.ByteBuffer.wrap(ciphertext).toString('base64'); - } - } - async function generateSignatureForPairing(secondaryPubKey, type) { const pubKeyArrayBuffer = StringView.hexToArrayBuffer(secondaryPubKey); // Make sure the signature includes the pairing action (pairing or unpairing) @@ -367,7 +300,6 @@ const tokenString = dcodeIO.ByteBuffer.wrap(token).toString('utf8'); return tokenString; } - const snodeCipher = new LokiSnodeChannel(); const sha512 = data => crypto.subtle.digest('SHA-512', data); @@ -531,7 +463,6 @@ DecryptGCM, // AES-GCM FallBackSessionCipher, FallBackDecryptionError, - snodeCipher, decryptToken, generateSignatureForPairing, verifyPairingSignature, @@ -540,8 +471,6 @@ PairingType, LokiSessionCipher, generateEphemeralKeyPair, - // for testing - _LokiSnodeChannel: LokiSnodeChannel, _decodeSnodeAddressToPubKey: decodeSnodeAddressToPubKey, sha512, }; diff --git a/libloki/test/index.html b/libloki/test/index.html index 4d1c2a5e7..f9eb9c2e4 100644 --- a/libloki/test/index.html +++ b/libloki/test/index.html @@ -33,7 +33,6 @@ - diff --git a/libloki/test/snode_channel_test.js b/libloki/test/snode_channel_test.js deleted file mode 100644 index cb535c73e..000000000 --- a/libloki/test/snode_channel_test.js +++ /dev/null @@ -1,141 +0,0 @@ -/* global libloki, Multibase, libsignal, StringView, dcodeIO */ - -'use strict'; - -async function generateSnodeKeysAndAddress() { - // snode identitys is a ed25519 keypair - const sodium = await window.getSodium(); - const ed25519KeyPair = sodium.crypto_sign_keypair(); - const keyPair = { - pubKey: ed25519KeyPair.publicKey, - privKey: ed25519KeyPair.privateKey, - }; - // snode address is the pubkey in base32z - let address = Multibase.encode( - 'base32z', - Multibase.Buffer.from(keyPair.pubKey) - ).toString(); - // remove first letter, which is the encoding code - address = address.substring(1); - return { keyPair, address }; -} - -describe('Snode Channel', () => { - describe('snodeCipher singleton', () => { - it('should be defined at libloki.crypto', () => { - assert.isDefined(libloki.crypto.snodeCipher); - assert.isTrue( - libloki.crypto.snodeCipher instanceof libloki.crypto._LokiSnodeChannel - ); - }); - }); - - describe('#decodeSnodeAddressToPubKey', () => { - it('should decode a base32z encoded .snode address', async () => { - const { keyPair, address } = await generateSnodeKeysAndAddress(); - - const buffer = libloki.crypto._decodeSnodeAddressToPubKey( - `http://${address}.snode` - ); - - const expected = new Uint8Array(keyPair.pubKey); - assert.strictEqual(expected.length, 32); - assert.strictEqual(buffer.length, 32); - for (let i = 0; i < buffer.length; i += 1) { - assert.strictEqual(buffer[i], expected[i]); - } - }); - }); - - describe('#LokiSnodeChannel', () => { - it('should generate an ephemeral key pair', () => { - const channel = new libloki.crypto._LokiSnodeChannel(); - - assert.isDefined(channel._ephemeralKeyPair); - assert.isTrue(channel._ephemeralKeyPair.privKey instanceof ArrayBuffer); - assert.isTrue(channel._ephemeralKeyPair.pubKey instanceof ArrayBuffer); - const pubKeyHex = StringView.arrayBufferToHex( - channel._ephemeralKeyPair.pubKey - ); - assert.strictEqual(channel.getChannelPublicKeyHex(), pubKeyHex); - }); - - it('should cache something by snode address', async () => { - const { address } = await generateSnodeKeysAndAddress(); - - const channel = new libloki.crypto._LokiSnodeChannel(); - // cache should be empty - assert.strictEqual(Object.keys(channel._cache).length, 0); - - // push to cache - await channel._getSymmetricKey(address); - - assert.strictEqual(Object.keys(channel._cache).length, 1); - assert.strictEqual(Object.keys(channel._cache)[0], address); - }); - - it('should encrypt data correctly', async () => { - // message sent by Session - const snode = await generateSnodeKeysAndAddress(); - const messageSent = 'I am Groot'; - const textEncoder = new TextEncoder(); - const data = textEncoder.encode(messageSent); - - const channel = new libloki.crypto._LokiSnodeChannel(); - const encrypted = await channel.encrypt(snode.address, data); - - assert.strictEqual(typeof encrypted, 'string'); - - // message received by storage server - const senderPubKey = StringView.hexToArrayBuffer( - channel.getChannelPublicKeyHex() - ); - const sodium = await window.getSodium(); - const snodePrivKey = sodium.crypto_sign_ed25519_sk_to_curve25519( - snode.keyPair.privKey - ).buffer; - const symmetricKey = libsignal.Curve.calculateAgreement( - senderPubKey, - snodePrivKey - ); - const encryptedArrayBuffer = dcodeIO.ByteBuffer.wrap( - encrypted, - 'base64' - ).toArrayBuffer(); - const decrypted = await libloki.crypto.DHDecrypt( - symmetricKey, - encryptedArrayBuffer - ); - const textDecoder = new TextDecoder(); - const messageReceived = textDecoder.decode(decrypted); - assert.strictEqual(messageSent, messageReceived); - }); - - it('should decrypt data correctly', async () => { - const channel = new libloki.crypto._LokiSnodeChannel(); - // message sent by storage server - const snode = await generateSnodeKeysAndAddress(); - const messageSent = 'You are Groot'; - const textEncoder = new TextEncoder(); - const data = textEncoder.encode(messageSent); - const senderPubKey = StringView.hexToArrayBuffer( - channel.getChannelPublicKeyHex() - ); - const sodium = await window.getSodium(); - const snodePrivKey = sodium.crypto_sign_ed25519_sk_to_curve25519( - snode.keyPair.privKey - ).buffer; - const symmetricKey = libsignal.Curve.calculateAgreement( - senderPubKey, - snodePrivKey - ); - const encrypted = await libloki.crypto.DHEncrypt(symmetricKey, data); - const encryptedBase64 = dcodeIO.ByteBuffer.wrap(encrypted).toString( - 'base64' - ); - // message received by Session - const decrypted = await channel.decrypt(snode.address, encryptedBase64); - assert.strictEqual(messageSent, decrypted); - }); - }); -}); diff --git a/package.json b/package.json index 7df33965b..265076aa2 100644 --- a/package.json +++ b/package.json @@ -92,7 +92,6 @@ "js-sha512": "0.8.0", "js-yaml": "3.13.0", "jsbn": "1.1.0", - "libsodium-wrappers": "^0.7.4", "linkify-it": "2.0.3", "lodash": "4.17.11", "mkdirp": "0.5.1", diff --git a/preload.js b/preload.js index c61462fc0..9e3144c16 100644 --- a/preload.js +++ b/preload.js @@ -347,13 +347,6 @@ window.React = require('react'); window.ReactDOM = require('react-dom'); window.moment = require('moment'); -const _sodium = require('libsodium-wrappers'); - -window.getSodium = async () => { - await _sodium.ready; - return _sodium; -}; - window.clipboard = clipboard; const Signal = require('./js/modules/signal'); diff --git a/yarn.lock b/yarn.lock index 6180d9ce1..c978424f2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5926,18 +5926,6 @@ levn@^0.3.0, levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" -libsodium-wrappers@^0.7.4: - version "0.7.6" - resolved "https://registry.yarnpkg.com/libsodium-wrappers/-/libsodium-wrappers-0.7.6.tgz#baed4c16d4bf9610104875ad8a8e164d259d48fb" - integrity sha512-OUO2CWW5bHdLr6hkKLHIKI4raEkZrf3QHkhXsJ1yCh6MZ3JDA7jFD3kCATNquuGSG6MjjPHQIQms0y0gBDzjQg== - dependencies: - libsodium "0.7.6" - -libsodium@0.7.6: - version "0.7.6" - resolved "https://registry.yarnpkg.com/libsodium/-/libsodium-0.7.6.tgz#018b80c5728054817845fbffa554274441bda277" - integrity sha512-hPb/04sEuLcTRdWDtd+xH3RXBihpmbPCsKW/Jtf4PsvdyKh+D6z2D2gvp/5BfoxseP+0FCOg66kE+0oGUE/loQ== - lie@*: version "3.3.0" resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a"