New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Off-the-Record (OTR) Messaging [$1,000] #36

Open
wanderer opened this Issue May 29, 2015 · 75 comments

Comments

@wanderer

wanderer commented May 29, 2015

There is a $1,000 open bounty on this issue. Add to the bounty at Bountysource.

@charlieman

This comment has been minimized.

Show comment
Hide comment
@charlieman

charlieman May 29, 2015

You mean beyond https?

charlieman commented May 29, 2015

You mean beyond https?

@wanderer

This comment has been minimized.

Show comment
Hide comment
@wanderer

wanderer May 29, 2015

it would be nice if it has some OTR for direct messaging

wanderer commented May 29, 2015

it would be nice if it has some OTR for direct messaging

@sampaiodiego

This comment has been minimized.

Show comment
Hide comment
@sampaiodiego

sampaiodiego May 30, 2015

Member

the idea of OTR implies in not saving the message on db?

Member

sampaiodiego commented May 30, 2015

the idea of OTR implies in not saving the message on db?

@engelgabriel

This comment has been minimized.

Show comment
Hide comment
@engelgabriel

engelgabriel May 30, 2015

Member

Off-the-Record (OTR) Messaging

Allows you to have private conversations over instant messaging by providing:

Encryption

No one else can read your instant messages.

Authentication

You are assured the correspondent is who you think it is.

Deniability

The messages you send do not have digital signatures that are checkable by a third party. Anyone can forge messages after a conversation to make them look like they came from you. However, during a conversation, your correspondent is assured the messages he sees are authentic and unmodified.

Perfect forward secrecy

If you lose control of your private keys, no previous conversation is compromised.

Member

engelgabriel commented May 30, 2015

Off-the-Record (OTR) Messaging

Allows you to have private conversations over instant messaging by providing:

Encryption

No one else can read your instant messages.

Authentication

You are assured the correspondent is who you think it is.

Deniability

The messages you send do not have digital signatures that are checkable by a third party. Anyone can forge messages after a conversation to make them look like they came from you. However, during a conversation, your correspondent is assured the messages he sees are authentic and unmodified.

Perfect forward secrecy

If you lose control of your private keys, no previous conversation is compromised.

@engelgabriel engelgabriel changed the title from Does it Encrypt Messages? to Off-the-Record (OTR) Messaging May 30, 2015

@kumavis

This comment has been minimized.

Show comment
Hide comment
@kumavis

kumavis Jun 1, 2015

I don't know if this implementation has been audited or not but https://github.com/arlolra/otr

kumavis commented Jun 1, 2015

I don't know if this implementation has been audited or not but https://github.com/arlolra/otr

@Calinou

This comment has been minimized.

Show comment
Hide comment
@Calinou

Calinou Jun 2, 2015

Contributor

Warning

This library hasn't been properly vetted by security researchers. Do not use in life and death situations!

Contributor

Calinou commented Jun 2, 2015

Warning

This library hasn't been properly vetted by security researchers. Do not use in life and death situations!

@kumavis

This comment has been minimized.

Show comment
Hide comment
@kumavis

kumavis Jun 2, 2015

And further reading on the state of otr arlolra/otr#59

kumavis commented Jun 2, 2015

And further reading on the state of otr arlolra/otr#59

@Igor1201

This comment has been minimized.

Show comment
Hide comment
@Igor1201

Igor1201 Jun 3, 2015

I think otr is the best option we have, audited or not, cryptocat uses it.

As said on arlolra/otr#59, pointed by @kumavis, just few other implementations are available, and otr4-em and node-otr4 aren't well compatible with Meteor, because we can't use client-side node packages.

Igor1201 commented Jun 3, 2015

I think otr is the best option we have, audited or not, cryptocat uses it.

As said on arlolra/otr#59, pointed by @kumavis, just few other implementations are available, and otr4-em and node-otr4 aren't well compatible with Meteor, because we can't use client-side node packages.

@Igor1201

This comment has been minimized.

Show comment
Hide comment
@Igor1201

Igor1201 Jun 3, 2015

It's indeed very easy to implement OTR using arlolra/otr.
Just made a simple PoC Igor1201/otr.

Igor1201 commented Jun 3, 2015

It's indeed very easy to implement OTR using arlolra/otr.
Just made a simple PoC Igor1201/otr.

@engelgabriel

This comment has been minimized.

Show comment
Hide comment
@engelgabriel

engelgabriel Jun 3, 2015

Member

Looks like this feature has more people interested than I expected. I'll raise its priority. 👍

Member

engelgabriel commented Jun 3, 2015

Looks like this feature has more people interested than I expected. I'll raise its priority. 👍

@engelgabriel engelgabriel added this to the v1.0 milestone Jun 3, 2015

@engelgabriel

This comment has been minimized.

Show comment
Hide comment
@engelgabriel

engelgabriel Jun 3, 2015

Member

Can any of you guys do a Pull Request or create a fork with a proposed implementation?

Member

engelgabriel commented Jun 3, 2015

Can any of you guys do a Pull Request or create a fork with a proposed implementation?

@engelgabriel

This comment has been minimized.

Show comment
Hide comment
@engelgabriel

engelgabriel Jul 6, 2015

Member

Hi @Igor1201 can we work together to get your PoC to work on Rocket.Chat?

Member

engelgabriel commented Jul 6, 2015

Hi @Igor1201 can we work together to get your PoC to work on Rocket.Chat?

@engelgabriel

This comment has been minimized.

Show comment
Hide comment
@engelgabriel
Member

engelgabriel commented Jul 6, 2015

See #268

@rodrigok rodrigok modified the milestones: v1.0, Next Aug 15, 2015

@marceloschmidt marceloschmidt modified the milestones: Roadmap, Next Sep 21, 2015

@taoeffect

This comment has been minimized.

Show comment
Hide comment
@taoeffect

taoeffect Oct 18, 2015

Problem with OTR is that it only works while both users are online.

I recommend using Axolotl instead, developed by Open WhisperSystems of TextSecure/Signal fame. It's like OTR but it supports secure asynchronous messaging, which is important because it's rare that everyone is online all the time. :)

There are lots of Axolotl libraries out there, available for both iOS, Android, and Web.

taoeffect commented Oct 18, 2015

Problem with OTR is that it only works while both users are online.

I recommend using Axolotl instead, developed by Open WhisperSystems of TextSecure/Signal fame. It's like OTR but it supports secure asynchronous messaging, which is important because it's rare that everyone is online all the time. :)

There are lots of Axolotl libraries out there, available for both iOS, Android, and Web.

@kdar

This comment has been minimized.

Show comment
Hide comment
@kdar

kdar Oct 30, 2015

I agree with @taoeffect. OTR isn't optimal here.

kdar commented Oct 30, 2015

I agree with @taoeffect. OTR isn't optimal here.

@taoeffect

This comment has been minimized.

Show comment
Hide comment
@taoeffect

taoeffect Nov 2, 2015

FYI, this feature, regardless of how you implement it, really only makes sense for DMs (for now). Encrypting group conversations is extremely difficult, and with today's tech it would result in most of the other features of RocketChat having to be removed (like search).

taoeffect commented Nov 2, 2015

FYI, this feature, regardless of how you implement it, really only makes sense for DMs (for now). Encrypting group conversations is extremely difficult, and with today's tech it would result in most of the other features of RocketChat having to be removed (like search).

@thoys

This comment has been minimized.

Show comment
Hide comment
@thoys

thoys Nov 13, 2015

You could have 2 types of groups, insecure groups and OTR groups.

thoys commented Nov 13, 2015

You could have 2 types of groups, insecure groups and OTR groups.

@taoeffect

This comment has been minimized.

Show comment
Hide comment
@taoeffect

taoeffect Nov 13, 2015

You could have 2 types of groups, insecure groups and OTR groups.

The problem is that "OTR groups" do not exist (to my knowledge). Axolotl has support for groups. There is also np1sec being developed: https://equalit.ie/portfolio/np1sec/

taoeffect commented Nov 13, 2015

You could have 2 types of groups, insecure groups and OTR groups.

The problem is that "OTR groups" do not exist (to my knowledge). Axolotl has support for groups. There is also np1sec being developed: https://equalit.ie/portfolio/np1sec/

@engelgabriel engelgabriel changed the title from Off-the-Record (OTR) Messaging to Off-the-Record (OTR) Messaging [$1,000] Dec 20, 2015

@engelgabriel engelgabriel added the bounty label Dec 20, 2015

@infinitnet

This comment has been minimized.

Show comment
Hide comment
@infinitnet

infinitnet Jan 5, 2016

I'd love to see this. If not for whole groups, it would be a good first step to at least add OTR for personal messages where only 2 endpoints are involved. That should be easy enough and great to keep private messages actually private. Being able to read everything as a sysadmin is not ideal and actually something that would keep us from using this software.

infinitnet commented Jan 5, 2016

I'd love to see this. If not for whole groups, it would be a good first step to at least add OTR for personal messages where only 2 endpoints are involved. That should be easy enough and great to keep private messages actually private. Being able to read everything as a sysadmin is not ideal and actually something that would keep us from using this software.

@lazyfrosch

This comment has been minimized.

Show comment
Hide comment
@lazyfrosch

lazyfrosch Feb 7, 2016

@cryptono how about safely storing chat history for private chats on the server? I would like to see a way to keep the (encrypted) history on server, so I can read it on multiple devices.

Of course this would require the user a way to remove the data, and decide how long to store the encrypted blobs.

lazyfrosch commented Feb 7, 2016

@cryptono how about safely storing chat history for private chats on the server? I would like to see a way to keep the (encrypted) history on server, so I can read it on multiple devices.

Of course this would require the user a way to remove the data, and decide how long to store the encrypted blobs.

@mitar

This comment has been minimized.

Show comment
Hide comment
@mitar

mitar Feb 19, 2016

Contributor

Can somebody first explain what is a threat model here? Against which type of an attacker are we trying to defend by doing OTR?

Contributor

mitar commented Feb 19, 2016

Can somebody first explain what is a threat model here? Against which type of an attacker are we trying to defend by doing OTR?

@engelgabriel

This comment has been minimized.

Show comment
Hide comment
@engelgabriel

engelgabriel Feb 19, 2016

Member

Anyone that can get access to the server DB or application... as all the messages are stored there.
I guess we could use GPG Keychain so only the clients would know how to decrypt the messages.

Member

engelgabriel commented Feb 19, 2016

Anyone that can get access to the server DB or application... as all the messages are stored there.
I guess we could use GPG Keychain so only the clients would know how to decrypt the messages.

@mitar

This comment has been minimized.

Show comment
Hide comment
@mitar

mitar Feb 19, 2016

Contributor

Can you be a bit more precise? You mean read-only access server? Can they modify files? Could they for example modify JavaScript on the server, so that client loads malicious JavaScript, which once they submit a message for encryption on the client side, it is also send to their server unencrypted?

Do we want then messages to work only when both parties are connected (which is what OTR is) or do we want to store them in the database so that you can load history (which OTR is not). We can have the latter, but then again, we have to be able to decrypt them, so attacker can just client side as an oracle to do that for them, by sending them compromised code.

So, the easy approach is to prevent DB dumps from containing messages in plain text. But if you have an attacker which can control the server, things become much more complicated. I would be interested in helping here and in my research group we have done some preliminary work on securing Rocket.Chat. But it would also be important to understand what is a threat model community is interested here. Do we care only about maybe your employee not being able to see messages? Maybe then integration with lets encrypt for Docker images is enough. Do we just want to prevent the server to be subpoenaed to get logs? Then simply not storing any logs is also good a solution.

So, what are we trying to achieve. What is a threat model?

Contributor

mitar commented Feb 19, 2016

Can you be a bit more precise? You mean read-only access server? Can they modify files? Could they for example modify JavaScript on the server, so that client loads malicious JavaScript, which once they submit a message for encryption on the client side, it is also send to their server unencrypted?

Do we want then messages to work only when both parties are connected (which is what OTR is) or do we want to store them in the database so that you can load history (which OTR is not). We can have the latter, but then again, we have to be able to decrypt them, so attacker can just client side as an oracle to do that for them, by sending them compromised code.

So, the easy approach is to prevent DB dumps from containing messages in plain text. But if you have an attacker which can control the server, things become much more complicated. I would be interested in helping here and in my research group we have done some preliminary work on securing Rocket.Chat. But it would also be important to understand what is a threat model community is interested here. Do we care only about maybe your employee not being able to see messages? Maybe then integration with lets encrypt for Docker images is enough. Do we just want to prevent the server to be subpoenaed to get logs? Then simply not storing any logs is also good a solution.

So, what are we trying to achieve. What is a threat model?

@lazyfrosch

This comment has been minimized.

Show comment
Hide comment
@lazyfrosch

lazyfrosch Feb 19, 2016

The thread model is that no admin should be able to read private messages of the users. They lay in plaintext within the history store.

Usually user want to have a good basis for private communication, and a way to communicate open in teams.

Example:

  • employee1 <-> employee2
  • team lead <-> manager
  • employee <-> HR

You wouldn't want these chats to be readable by an admin. The alternative would be to use an alternative channel, but why would I want that when I wanna provide a centralized communications tool for my group?

lazyfrosch commented Feb 19, 2016

The thread model is that no admin should be able to read private messages of the users. They lay in plaintext within the history store.

Usually user want to have a good basis for private communication, and a way to communicate open in teams.

Example:

  • employee1 <-> employee2
  • team lead <-> manager
  • employee <-> HR

You wouldn't want these chats to be readable by an admin. The alternative would be to use an alternative channel, but why would I want that when I wanna provide a centralized communications tool for my group?

@marceloschmidt

This comment has been minimized.

Show comment
Hide comment
@marceloschmidt

marceloschmidt Mar 9, 2016

Member

I've updated the code and now encrypt / decrypt fully works, even with UTF-8 characters. The bad thing is that I used RSA all over the place, which is slow and has a size limit.

My next steps are:

  1. Change the name from OTR to something else encrypt-related
  2. Use RSA to exchange a secret key, to be used with AES
  3. Use AES-CBC to encrypt messages faster and theoretically infinite in length.

Let me know if you think of anything else.

Member

marceloschmidt commented Mar 9, 2016

I've updated the code and now encrypt / decrypt fully works, even with UTF-8 characters. The bad thing is that I used RSA all over the place, which is slow and has a size limit.

My next steps are:

  1. Change the name from OTR to something else encrypt-related
  2. Use RSA to exchange a secret key, to be used with AES
  3. Use AES-CBC to encrypt messages faster and theoretically infinite in length.

Let me know if you think of anything else.

@mitar

This comment has been minimized.

Show comment
Hide comment
@mitar

mitar Mar 10, 2016

Contributor

I think you can keep calling it OTR, just say that this is OTR protocol version Rocket.Chat. ;-) But it is true that we will not have all the properties of OTR. Maybe client-encryption?

OK, I do not have time to go into precise protocol design mode at the moment, but you are doing it wrong (but I am amazed how quickly you did all the stuff, so you are doing it right from the API perspective, but just choice of crypto primitives is not the right one). The main property we want from this encryption is forward secrecy. You are not getting that with RSA. If a key is compromised later on, one can decrypt everything from day one.

So, let me give you some basic ideas, if something is unclear help. But just so that you have some material to work with. The main idea is that you generate a symmetric key which is used to encrypt messages, but that symmetric key is generated without storing it really anywhere. So when both clients forget about it (session is closed), there is no way to retrieve it from the database.

Each peer should on the client generate an ephemeral key pair:

// Generate an ephemeral key pair.
crypto.subtle.generateKey({
  name: 'ECDH',
  namedCurve: 'P-256'
}, false, ['deriveKey', 'deriveBits']).then(function (keyPair) {
  return crypto.subtle.exportKey('spki', keyPair.publicKey);
}).function (exportedPublicKey) {
  // Send it to the other peer.
});

I simply use SPKI export type, because JWK seems bloated to me. :-) You probably have to wrap it into new Uint8Array(exportedPublicKey) to have it EJSON-able. (You can +1 this ticket to get EJSON to support promse-based values and then you could simply send the key directly, and it would be exported internally when doing EJSON serialization.)

OK, so now each side has its own key pair, and a public key of the peer. You can now generate some bits to use it for your session/symmetric/temporary key.

crypto.subtle.importKey('spki', peerPublicKeyContent, {
  name: 'ECDH',
  namedCurve: 'P-256'
}, false, []).then(function (peerPublicKey) {
  return crypto.subtle.deriveBits({
    name: 'ECDH',
    namedCurve: 'P-256',
    public: peerPublicKey
  }, keyPair.privateKey, 256);
}).then(function (bits) {
  return crypto.subtle.digest({
    name: 'SHA-256'
  }, bits);
}).then(function (hashedBits) {
  // We truncate the hash to 128 bits.
  var sessionKeyData = new Uint8Array(hashedBits).slice(0, 16);
  return crypto.subtle.importKey('raw', sessionKeyData, {
    name: 'AES-GCM'
  }, false, ['encrypt', 'decrypt']);
}).then(function (sessionKey) {
  // Session key available.
});

You can do then encryption with:

clearText = new Uint8Array(clearText);
var serial = nextSerialForThisPeer();
var data = new Uint8Array(1 + 1 + serial.length + clearText.length);
if (isFirstPeer()) {
  data[0] = 1;
}
data[1] = serial.length;
data.set(serial, 2);
data.set(clearText, 2 + serial.length);

var iv = crypto.getRandomValues(new Uint8Array(12));

return crypto.subtle.encrypt({
  name: 'AES-GCM',
  iv: iv
}, sessionKey, data).then(function (cipherText) {
  cipherText = new Uint8Array(cipherText);
  var output = new Uint8Array(iv.length + cipherText.length);
  output.set(iv, 0);
  output.set(cipherText, iv.length);
  return output;
});

Decryption:

cipherText = new Uint8Array(cipherText);

var iv = cipherText.slice(0, 12);
cipherText = cipherText.slice(12);

return crypto.subtle.decrypt({
  name: 'AES-GCM',
  iv: iv
}, sessionKey, cipherText).then(function (data) {
  data = new Uint8Array(data);

  if (isFirstPeer()) {
    if (data[0] !== 0) throw new Error("Can decrypt only encrypted data from the second peer.");
  }
  else {
    if (data[0] !== 1) throw new Error("Can decrypt only encrypted data from the first peer.");
  }

  var serial = data.slice(2, 2 + data[1]);
  var clearText = data.slice(2 + data[1]);

  // To copy over and make sure we do not have a shallow slice with simply non-zero byteOffset.
  serial = new Uint8Array(serial);
  clearText = new Uint8Array(clearText);

  // This prevents any replay attacks. Or attacks where messages are changed in order.
  if (!isOneLarger(serial, lastSerial)) throw new Error("Invalid serial.");
  storeLastSerial(serial);

  return clearText;
});

I think this would be a good first step. There is an issue of side-channel. You might want to add random padding to all messages which you append to a message, encrypt, but then throw away on the other side. Attackers would now have harder time knowing what is in the message. (Not sure if random padding is enough though. Especially if it is uniformly distributed randomness.)

I think this is a good first step. Next step is to add something for clients to know if the peerPublicKeyContent they are getting is really from the their peer and not somebody doing MITM attack. But this can then be improved later on. For example, peerPublicKeyContent can be signed by each client with another set of keys. For that you can generate ECDSA keys (SHA-256 as a parameter is OK) on both sides and use it to sign peerPublicKeyContent. Now, the question of course is how to trust the ECDSA keys. :-) What we could do for now is simply send public key to each other and trust them on first use. Clients would remember their ECDSA keys into localStorage on their device. Those keys (for signing only) would be reused, but the keys used to generate the session key would never be reused (and can even be regularly cycled even during one session). Each client could then store (username, public ECDSA key) mapping on each device.

You could add a way to see the fingerprint of the peer's public ECDSA key before they confirm it, but for most people this is magic. But some people could use SMS or e-mail for example to send the fingerprint to their peer (so called out-of-band communication). So, I would allow that users do not have to know anything about fingerprints, but I would also allow that power users can have this extra step of protection.

An open issue here is what if attacker tricks the client to think that the other user is using some other username or something. So confuse users about usernames. This is why some extra metadata should be stored along with the public ECDSA key when it is signed. Something like:

publicKey = new Uint8Array(publicKey);

var userIdArray = convertUserIdToArray(userId);
var data = new Uint8Array(userIdArray.length + publicKey.length);
data.set(userIdArray, 0);
data.set(publicKey, userIdArray.length);

return sandbox.crypto.subtle.sign({
  name: 'ECDSA',
  hash: {
    name: 'SHA-256'
  }
}, signingPrivateKey, data);
var userIdArray = convertUserIdToArray(userId);
var data = new Uint8Array(userIdArray.length + peerPublicKey.length);
data.set(userIdArray, 0);
data.set(peerPublicKey, userIdArray.length);

return crypto.subtle.verify({
  name: 'ECDSA',
  hash: {
    name: 'SHA-256'
  }
}, peerSigningPublicKey, peerPublicKeySignature, data).then(function (isValid) {
  if (!isValid) {
    throw new Error("Peer public key signature mismatch.");
  }
});
Contributor

mitar commented Mar 10, 2016

I think you can keep calling it OTR, just say that this is OTR protocol version Rocket.Chat. ;-) But it is true that we will not have all the properties of OTR. Maybe client-encryption?

OK, I do not have time to go into precise protocol design mode at the moment, but you are doing it wrong (but I am amazed how quickly you did all the stuff, so you are doing it right from the API perspective, but just choice of crypto primitives is not the right one). The main property we want from this encryption is forward secrecy. You are not getting that with RSA. If a key is compromised later on, one can decrypt everything from day one.

So, let me give you some basic ideas, if something is unclear help. But just so that you have some material to work with. The main idea is that you generate a symmetric key which is used to encrypt messages, but that symmetric key is generated without storing it really anywhere. So when both clients forget about it (session is closed), there is no way to retrieve it from the database.

Each peer should on the client generate an ephemeral key pair:

// Generate an ephemeral key pair.
crypto.subtle.generateKey({
  name: 'ECDH',
  namedCurve: 'P-256'
}, false, ['deriveKey', 'deriveBits']).then(function (keyPair) {
  return crypto.subtle.exportKey('spki', keyPair.publicKey);
}).function (exportedPublicKey) {
  // Send it to the other peer.
});

I simply use SPKI export type, because JWK seems bloated to me. :-) You probably have to wrap it into new Uint8Array(exportedPublicKey) to have it EJSON-able. (You can +1 this ticket to get EJSON to support promse-based values and then you could simply send the key directly, and it would be exported internally when doing EJSON serialization.)

OK, so now each side has its own key pair, and a public key of the peer. You can now generate some bits to use it for your session/symmetric/temporary key.

crypto.subtle.importKey('spki', peerPublicKeyContent, {
  name: 'ECDH',
  namedCurve: 'P-256'
}, false, []).then(function (peerPublicKey) {
  return crypto.subtle.deriveBits({
    name: 'ECDH',
    namedCurve: 'P-256',
    public: peerPublicKey
  }, keyPair.privateKey, 256);
}).then(function (bits) {
  return crypto.subtle.digest({
    name: 'SHA-256'
  }, bits);
}).then(function (hashedBits) {
  // We truncate the hash to 128 bits.
  var sessionKeyData = new Uint8Array(hashedBits).slice(0, 16);
  return crypto.subtle.importKey('raw', sessionKeyData, {
    name: 'AES-GCM'
  }, false, ['encrypt', 'decrypt']);
}).then(function (sessionKey) {
  // Session key available.
});

You can do then encryption with:

clearText = new Uint8Array(clearText);
var serial = nextSerialForThisPeer();
var data = new Uint8Array(1 + 1 + serial.length + clearText.length);
if (isFirstPeer()) {
  data[0] = 1;
}
data[1] = serial.length;
data.set(serial, 2);
data.set(clearText, 2 + serial.length);

var iv = crypto.getRandomValues(new Uint8Array(12));

return crypto.subtle.encrypt({
  name: 'AES-GCM',
  iv: iv
}, sessionKey, data).then(function (cipherText) {
  cipherText = new Uint8Array(cipherText);
  var output = new Uint8Array(iv.length + cipherText.length);
  output.set(iv, 0);
  output.set(cipherText, iv.length);
  return output;
});

Decryption:

cipherText = new Uint8Array(cipherText);

var iv = cipherText.slice(0, 12);
cipherText = cipherText.slice(12);

return crypto.subtle.decrypt({
  name: 'AES-GCM',
  iv: iv
}, sessionKey, cipherText).then(function (data) {
  data = new Uint8Array(data);

  if (isFirstPeer()) {
    if (data[0] !== 0) throw new Error("Can decrypt only encrypted data from the second peer.");
  }
  else {
    if (data[0] !== 1) throw new Error("Can decrypt only encrypted data from the first peer.");
  }

  var serial = data.slice(2, 2 + data[1]);
  var clearText = data.slice(2 + data[1]);

  // To copy over and make sure we do not have a shallow slice with simply non-zero byteOffset.
  serial = new Uint8Array(serial);
  clearText = new Uint8Array(clearText);

  // This prevents any replay attacks. Or attacks where messages are changed in order.
  if (!isOneLarger(serial, lastSerial)) throw new Error("Invalid serial.");
  storeLastSerial(serial);

  return clearText;
});

I think this would be a good first step. There is an issue of side-channel. You might want to add random padding to all messages which you append to a message, encrypt, but then throw away on the other side. Attackers would now have harder time knowing what is in the message. (Not sure if random padding is enough though. Especially if it is uniformly distributed randomness.)

I think this is a good first step. Next step is to add something for clients to know if the peerPublicKeyContent they are getting is really from the their peer and not somebody doing MITM attack. But this can then be improved later on. For example, peerPublicKeyContent can be signed by each client with another set of keys. For that you can generate ECDSA keys (SHA-256 as a parameter is OK) on both sides and use it to sign peerPublicKeyContent. Now, the question of course is how to trust the ECDSA keys. :-) What we could do for now is simply send public key to each other and trust them on first use. Clients would remember their ECDSA keys into localStorage on their device. Those keys (for signing only) would be reused, but the keys used to generate the session key would never be reused (and can even be regularly cycled even during one session). Each client could then store (username, public ECDSA key) mapping on each device.

You could add a way to see the fingerprint of the peer's public ECDSA key before they confirm it, but for most people this is magic. But some people could use SMS or e-mail for example to send the fingerprint to their peer (so called out-of-band communication). So, I would allow that users do not have to know anything about fingerprints, but I would also allow that power users can have this extra step of protection.

An open issue here is what if attacker tricks the client to think that the other user is using some other username or something. So confuse users about usernames. This is why some extra metadata should be stored along with the public ECDSA key when it is signed. Something like:

publicKey = new Uint8Array(publicKey);

var userIdArray = convertUserIdToArray(userId);
var data = new Uint8Array(userIdArray.length + publicKey.length);
data.set(userIdArray, 0);
data.set(publicKey, userIdArray.length);

return sandbox.crypto.subtle.sign({
  name: 'ECDSA',
  hash: {
    name: 'SHA-256'
  }
}, signingPrivateKey, data);
var userIdArray = convertUserIdToArray(userId);
var data = new Uint8Array(userIdArray.length + peerPublicKey.length);
data.set(userIdArray, 0);
data.set(peerPublicKey, userIdArray.length);

return crypto.subtle.verify({
  name: 'ECDSA',
  hash: {
    name: 'SHA-256'
  }
}, peerSigningPublicKey, peerPublicKeySignature, data).then(function (isValid) {
  if (!isValid) {
    throw new Error("Peer public key signature mismatch.");
  }
});
@Againstreality

This comment has been minimized.

Show comment
Hide comment
@Againstreality

Againstreality Mar 15, 2016

Is the mobile implementation on the way?

Againstreality commented Mar 15, 2016

Is the mobile implementation on the way?

@marceloschmidt

This comment has been minimized.

Show comment
Hide comment
@marceloschmidt

marceloschmidt Mar 15, 2016

Member

Christian, what's your mobile specs? Have you tested it? It works for a few
modern browsers.

Em ter, 15 de mar de 2016 18:07, Christian Schuster <
notifications@github.com> escreveu:

Is the mobile implementation on the way?


You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub
#36 (comment)

Marcelo Schmidt

Member

marceloschmidt commented Mar 15, 2016

Christian, what's your mobile specs? Have you tested it? It works for a few
modern browsers.

Em ter, 15 de mar de 2016 18:07, Christian Schuster <
notifications@github.com> escreveu:

Is the mobile implementation on the way?


You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub
#36 (comment)

Marcelo Schmidt

@Againstreality

This comment has been minimized.

Show comment
Hide comment
@Againstreality

Againstreality Mar 15, 2016

Its about the apps for Android and ios i personal use an iphone 5s with ios 9.2.1

Againstreality commented Mar 15, 2016

Its about the apps for Android and ios i personal use an iphone 5s with ios 9.2.1

@marceloschmidt

This comment has been minimized.

Show comment
Hide comment
@marceloschmidt

marceloschmidt Mar 17, 2016

Member

It should be working with latest androids and with ios 9.2.1. Have you tested it?

Member

marceloschmidt commented Mar 17, 2016

It should be working with latest androids and with ios 9.2.1. Have you tested it?

@Againstreality

This comment has been minimized.

Show comment
Hide comment
@Againstreality

Againstreality Mar 17, 2016

yes is have testet it. And the option is not there. Maybe it was forgotten in the cordova Code?

Againstreality commented Mar 17, 2016

yes is have testet it. And the option is not there. Maybe it was forgotten in the cordova Code?

@marceloschmidt

This comment has been minimized.

Show comment
Hide comment
@marceloschmidt

marceloschmidt Mar 17, 2016

Member

@Againstreality can you please open an issue, then? Please state your server version, mobile version, and screenshots of your problem. Thanks.

Member

marceloschmidt commented Mar 17, 2016

@Againstreality can you please open an issue, then? Please state your server version, mobile version, and screenshots of your problem. Thanks.

@engelgabriel

This comment has been minimized.

Show comment
Hide comment
@engelgabriel

engelgabriel Mar 29, 2016

Member

Hi @jespow have you been following the development of this feature? Do you have any comments on the current implementation?

Member

engelgabriel commented Mar 29, 2016

Hi @jespow have you been following the development of this feature? Do you have any comments on the current implementation?

@pkaluzacog

This comment has been minimized.

Show comment
Hide comment
@pkaluzacog

pkaluzacog Apr 14, 2016

Since the advantages of the Axolotl ratchet in a more-than-desktop-chat world have been mentioned already, count me among the supporters. At the same time I'd like to give a shout out to the OMEMO ratchet and protocol, which brings even more security and user convenience.

pkaluzacog commented Apr 14, 2016

Since the advantages of the Axolotl ratchet in a more-than-desktop-chat world have been mentioned already, count me among the supporters. At the same time I'd like to give a shout out to the OMEMO ratchet and protocol, which brings even more security and user convenience.

@ccoenen

This comment has been minimized.

Show comment
Hide comment
@ccoenen

ccoenen Jul 4, 2016

I also believe OMEMO would be the standard to back instead of (or perhaps on top of) OTR. There's implementations in

probably a good starting point even though some of it is Java.

(edit) I found the XEP: https://conversations.im/xeps/multi-end.html

ccoenen commented Jul 4, 2016

I also believe OMEMO would be the standard to back instead of (or perhaps on top of) OTR. There's implementations in

probably a good starting point even though some of it is Java.

(edit) I found the XEP: https://conversations.im/xeps/multi-end.html

@electropolis

This comment has been minimized.

Show comment
Hide comment
@electropolis

electropolis Oct 13, 2016

Did something changed here? As I see that in Rocket.Chat OTR function gives me Timeout and it's even not a good option for securing messages during conversation as I read all comments here.. I see you are working on alternative solution. Is there any progress ?

electropolis commented Oct 13, 2016

Did something changed here? As I see that in Rocket.Chat OTR function gives me Timeout and it's even not a good option for securing messages during conversation as I read all comments here.. I see you are working on alternative solution. Is there any progress ?

@thche

This comment has been minimized.

Show comment
Hide comment
@thche

thche commented Dec 1, 2016

push

@C3realGuy

This comment has been minimized.

Show comment
Hide comment
@C3realGuy

C3realGuy Dec 12, 2016

OMEMO encryption would be awesome.

C3realGuy commented Dec 12, 2016

OMEMO encryption would be awesome.

@ghost

This comment has been minimized.

Show comment
Hide comment
@ghost

ghost Dec 12, 2016

Right now riot.im/app is working with Double Ratchet Algorithm (encryption works with multiple participants, and with offline messages)
https://github.com/matrix-org/olm
https://github.com/vector-im/riot-web/search?utf8=%E2%9C%93&q=olm&type=Code

I'm not good developer but seems that in terms of backend it's easy. But in frontend we will require:

  • A way to see the keys (riot app uses read source of message).
  • A way to check keys of the other participants
  • A manual method to import/export key (in case you destroy cookies/use different browser/client you won't see previous or offline messages). -> This is not available in riot app
  • [Your thought here]

ghost commented Dec 12, 2016

Right now riot.im/app is working with Double Ratchet Algorithm (encryption works with multiple participants, and with offline messages)
https://github.com/matrix-org/olm
https://github.com/vector-im/riot-web/search?utf8=%E2%9C%93&q=olm&type=Code

I'm not good developer but seems that in terms of backend it's easy. But in frontend we will require:

  • A way to see the keys (riot app uses read source of message).
  • A way to check keys of the other participants
  • A manual method to import/export key (in case you destroy cookies/use different browser/client you won't see previous or offline messages). -> This is not available in riot app
  • [Your thought here]
@graingert

This comment has been minimized.

Show comment
Hide comment
@graingert

graingert Jan 8, 2017

Mention notifications can be done by sending a DM with special markup to the mentioned users

graingert commented Jan 8, 2017

Mention notifications can be done by sending a DM with special markup to the mentioned users

@graingert

This comment has been minimized.

Show comment
Hide comment
@graingert

graingert Jan 8, 2017

Eg the client that sends the mentioned tagged message in a grpup uses the DM channels to push notifications

graingert commented Jan 8, 2017

Eg the client that sends the mentioned tagged message in a grpup uses the DM channels to push notifications

@dmkjr

This comment has been minimized.

Show comment
Hide comment
@dmkjr

dmkjr Jan 21, 2017

Any update on this? I'm just getting a "timeout" error when attempting to use it.

dmkjr commented Jan 21, 2017

Any update on this? I'm just getting a "timeout" error when attempting to use it.

mrsimpson referenced this issue in assistify/Rocket.Chat Aug 29, 2017

Minor functional enhancements (#50)
* Allow lowercase topic names
* Error handling Smarti not available : Do not create `undefined` script tags
* Help-request actions button shall disappear once the help-request has been closed (#38)
* Make requests for expertises respect case as well (#36)
* Remove subscription of owner who created a request on closing a help request (fixes #38)
* #47 - Closing a help request does not store the conversation correctly
- Added some debugging output
- Some formatting
* Do not lowercase experts channel
* Satisfy linter and remove console dependency
@0xdevalias

This comment has been minimized.

Show comment
Hide comment
@0xdevalias

0xdevalias Sep 7, 2017

FWIW, I would love to see the olm double ratchet that matrix is using (based off the one signal uses from memory) implemented

0xdevalias commented Sep 7, 2017

FWIW, I would love to see the olm double ratchet that matrix is using (based off the one signal uses from memory) implemented

@ccoenen

This comment has been minimized.

Show comment
Hide comment
@ccoenen

ccoenen Sep 7, 2017

@mitar is the paper you mentioned available somewhere? You mentioned it being in review a year ago - and it sounds very interesting!

Also: Thanks for your very detailed descriptions.

ccoenen commented Sep 7, 2017

@mitar is the paper you mentioned available somewhere? You mentioned it being in review a year ago - and it sounds very interesting!

Also: Thanks for your very detailed descriptions.

@mitar

This comment has been minimized.

Show comment
Hide comment
@mitar

mitar Sep 7, 2017

Contributor

Sadly, not. We had issues finding research novelty in that work. It was mostly engineering work, which is not what academic papers should be about, it seems. :-(

Contributor

mitar commented Sep 7, 2017

Sadly, not. We had issues finding research novelty in that work. It was mostly engineering work, which is not what academic papers should be about, it seems. :-(

@tompinzler

This comment has been minimized.

Show comment
Hide comment
@tompinzler

tompinzler Jan 7, 2018

+1 for Olm Double Ratchet. It's certainly challenging to implement but would imho provide the most features (one-on-one and group conversations, partial forward secrecy etc.) and best user experience.

tompinzler commented Jan 7, 2018

+1 for Olm Double Ratchet. It's certainly challenging to implement but would imho provide the most features (one-on-one and group conversations, partial forward secrecy etc.) and best user experience.

@napalm23zero

This comment has been minimized.

Show comment
Hide comment
@napalm23zero

napalm23zero Jan 23, 2018

Any news? Anything? Anyone?
I can see OTR option on my self-hosted Rocket.Chat, but not working.

napalm23zero commented Jan 23, 2018

Any news? Anything? Anyone?
I can see OTR option on my self-hosted Rocket.Chat, but not working.

@geekgonecrazy

This comment has been minimized.

Show comment
Hide comment
@geekgonecrazy

geekgonecrazy Jan 24, 2018

Member

Make sure you are using https

Member

geekgonecrazy commented Jan 24, 2018

Make sure you are using https

@geekgonecrazy

This comment has been minimized.

Show comment
Hide comment
@geekgonecrazy

geekgonecrazy Apr 4, 2018

Member

Our implementation of e2e encryption has a PR open: #10094

Would be great to get some feedback on that PR.

Member

geekgonecrazy commented Apr 4, 2018

Our implementation of e2e encryption has a PR open: #10094

Would be great to get some feedback on that PR.

@PanderMusubi

This comment has been minimized.

Show comment
Hide comment
@PanderMusubi

PanderMusubi Aug 23, 2018

You can add this line at the top of the issue description, it will update itself

![badge](https://api.bountysource.com/badge/issue?issue_id=18684038)

and look like

badge

PanderMusubi commented Aug 23, 2018

You can add this line at the top of the issue description, it will update itself

![badge](https://api.bountysource.com/badge/issue?issue_id=18684038)

and look like

badge

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment