Merge pull request #1019 from Mikunj/remove-lib-sodium

Remove libsodium-wrapper.
pull/1023/head
Audric Ackermann 5 years ago committed by GitHub
commit 0770871f9c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -3,35 +3,16 @@
const nodeFetch = require('node-fetch');
const https = require('https');
const { parse } = require('url');
const snodeHttpsAgent = new https.Agent({
rejectUnauthorized: false,
});
const LOKI_EPHEMKEY_HEADER = 'X-Loki-EphemKey';
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 +215,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,
@ -427,27 +408,6 @@ const lokiFetch = async (url, options = {}, targetNode = null) => {
const timeout = options.timeout || 10000;
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,
timeout,
@ -512,22 +472,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 +498,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();
}

@ -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,
};

@ -33,7 +33,6 @@
<script type="text/javascript" src="proof-of-work_test.js"></script>
<script type="text/javascript" src="service_nodes_test.js"></script>
<script type="text/javascript" src="storage_test.js"></script>
<script type="text/javascript" src="snode_channel_test.js"></script>
<!-- Comment out to turn off code coverage. Useful for getting real callstacks. -->
<!-- NOTE: blanket doesn't support modern syntax and will choke until we find a replacement. :0( -->

@ -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);
});
});
});

@ -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",

@ -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');

@ -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"

Loading…
Cancel
Save