[Standards] Disappearing timers for OMEMO proposal

Alexander Krotov ilabdsf at gmail.com
Thu May 10 00:12:38 UTC 2018

I propose to extend OMEMO with disappearing messages.

There is already a thread with a subject: "Self-destruct" message timeout deletion hints.
It started with this message: https://mail.jabber.org/pipermail/standards/2016-October/031515.html
Continued in November: https://mail.jabber.org/pipermail/standards/2016-November/031595.html
Last message is from 2017: https://mail.jabber.org/pipermail/standards/2017-February/032092.html

The thread was started shortly after Signal announced its implementation
of disappearing messages in October 2016.[1] Rationale provided in
the blog post is worth repeating here to avoid talking about the
goals of this feature again, because it causes confusion all the
time (emphasis mine):
> Disappearing messages are a way for you and your friends to keep
> your message history tidy. They are a *collaborative feature* for
> conversations where all participants want to automate minimalist
> data hygiene, *not for situations where your contact is your adversary*
> — after all, if someone who receives a disappearing message really
> wants a record of it, they can always use another camera to take a
> photo of the screen before the message disappears.
See also the Signal FAQ entry for disappearing messages[2].

Implementing Snapchat-over-XMPP is a non-goal, so we don't have to
take into account hostile clients.  Someone may run a client that
advertises support for disappearing messages and does not actually
delete them, but it is the problem of trust between users.  Hostile
user may just as well run a client that advertises end-to-end
encryption, but leaks encryption keys or message contents later.

The problem with previous thread is that it was about *message
hints*, as defined in XEP-0334[3].  Legacy clients, as well as
legacy or hostile servers, may not implement these hints and store
messages permanently without any way for users to ensure their
messages are deleted. Therefore, any plaintext message should be
assumed to be stored permanently, and there is no point in implementing
timers for them. Telegram developers seem to understand it too, and
only implement timed messages for end-to-end encrypted "secret
chats", in contrast to plaintext "cloud chats".

What I propose instead of message hints is to extend OMEMO with:
1. a way to discover disappearing message timer support per device,
2. a way to specify timer value in messages,
3. specification of timer value semantics,
4. a protocol to negotiate common disappearing message timer.

Signal solutions to these problems cannot be copied exactly for
several reasons, which I describe below.

1. A way to discover disappearing message timer support per device.

In XMPP, some devices will never get the support for disappearing
messages. Therefore, disappearing messages must be encrypted only
for devices which advertise their support.

Signal didn't have to deal with this problem. All devices were
eventually updated to the newest version of the Signal and processed
disappearing messages.

As I understand from OMEMO specification[4], the best place to
advertise support for disappearing messages is the device bundle.

As for UI, OMEMO+Timers can be treated simply as another encryption
method. User will have to choose between None, OpenPGP, OTR, OMEMO
and OMEMO+Timers. If user selects OMEMO+Timers, devices which only
support OMEMO will receive a message they can't decrypt.

Devices that don't support OMEMO+Timers will leave the trace of
communication, but little can be done about it I believe. Proper
metadata protection, i.e., hiding the fact of communication, is
impossible in XMPP, so it is a non-goal for this proposal.

2. A way to specify timer value in messages.

Timer value should be placed somewhere in <message> tag. I would
also like to make it encrypted. Problem is, the only encrypted part
of the message is the <payload> which contains plaintext message
corresponding to the contents of <body> and is not extensible.

OX (XEP-0374) solves the problem by treating payload contents as
the <message> contents, i.e., the payload can contain multiple
<body> tags, chat state notifications etc.

I believe this approach can be copied to OMEMO in backwards-compatible
way. Until then, I suggest that we send message timers unencrypted,
just like chat state notifications, and move both inside encrypted
part later. Even though OMEMO+Timers has to be treated as different
encryption method, I would like to keep the changes minimal, avoid
changing namespaces and maintaining two completely separate

<timer> tag with some namespace, which probably should be registered
with XMPP Registrar, will contain the timer value in seconds.

3. Specification of timer value semantics.

We should define what timer value means. To see what the options
are, it is worth to take look at Wickr. It has both the Expiration
Timer and Burn-on-Read timer[5].

Expiration timer is synchronous. Looks like the motivation behind
it is to save data storage more than privacy[6]. XMPP already
implements similar functionality as "expire-at" AMP condition[7].

What we want instead is the Burn-on-Read semantics. That is what
Signal and Telegram implement.

It should be clearly specified when the timer starts on each of the

According to the Telegram FAQ[8], the timer starts counting as soon
as the message is read on the receiver device, and as soon as the
reading receipt is received on the sender device. This approach
cannot be applied to XMPP, because reading receipts are not guaranteed
to be enabled. Besides that, Telegram does not support more than
two devices per secret chat, so it is not clear how to extend it
to multiple device setting.

In Signal, protocol is asynchronous. Timer starts counting on the
sender device after the message is sent. CONTRIBUTING.md file in
Signal-Android repository states it as one of the design principles
of Signal: "There is no such thing as time. Protocol ideas that
require synchronized clocks are doomed to failure." I think we
should adopt this principle too, because we don't want message to
be kept for longer than they should on devices with lagging clocks.

So, the following semantics apply. On the sender device the timer
starts immediately. On each receiver device the timer starts counting
as soon as the message is read. On own devices, the message must
be considered read immediately.

Signal seems to violate its own principle of asynchronism here.
Instead of simply starting the timer on all own devices, it starts
the timer on the originating device and synchronizes the message
together with absolute timestamp of the timer start. The reason for
this absolute timestamp I can think of is own devices which were
offline when the message was sent. Perhaps we should also send
absolute timestamp to own devices and take minimum of the received
timestamp and current time as the moment of timer start. Or, invent
some other way to subtract delivery time from the timer value.

Similar synchronization concerns apply to the receiving side. What
happens when message expires on one of the devices? Signal avoids
this by synchronizing read state across devices, so timers start
almost simultaneously on all devices. We should also send read
receipts to own devices, even if sending read receipts to originating
parties is disabled, and start timers when we receive such "carbon
copy" read receipts.

4. A protocol to negotiate common disappearing message timer.

It is an essential feature, which Signal and Telegram implement.
Wire and Wickr don't, and it makes disappearing messages way less
usable: if one has it enabled, but someone else in a group doesn't,
everyone ends up with a partial conversation history. Even worse
when different timer values are used.

When user changes the setting, Signal sends special "expiration
timer update" to all other devices in a group. In XMPP it can be
implemented by sending a message without body, in the same way as
<composing/> chat state notifications are sent.

In rare case expiration timer update can be lost. To synchronize
the setting, timer values form normal messages are treated as
expiration timer updates too.

This can lead to a problem when user changes the setting, expiration
timer update is lost, and then it receives a message with old
setting. In this case the setting is reverted, and user has to set
it again.

However, this race condition should be rare and I can't find more
reliable solution which does not involve absolute timestamps and
timer update retransmissions. Described protocol is simple and good
enough already. This setting synchronization is a Byzantine agreement
problem, so there is no perfect solution anyway.

I have not looked into Telegram implementation of timer synchronization,
but it is unlikely we can learn much from it, as it only supports
two devices.

So far I have done this research on existing solutions and outlined
what I want to formally propose. Next steps would be writing a XEP
and implementing a prototype on top of some desktop OMEMO implementation,
most likely Gajim or Dino.

Any input and help are welcome.

[1] https://signal.org/blog/disappearing-messages/
[2] https://support.signal.org/hc/en-us/articles/213134237-Does-Signal-have-disappearing-messages-
[3] https://xmpp.org/extensions/xep-0334.html
[4] https://xmpp.org/extensions/xep-0384.html
[5] https://support.wickr.com/hc/en-us/articles/115007397548-Auto-Destruction-Expiration-and-Burn-on-read-BOR-
[6] https://medium.com/cryptoblog/the-rising-cost-of-storage-why-data-should-not-live-beyond-its-useful-life-1266a8e94983
[7] https://xmpp.org/extensions/xep-0079.html#conditions-def-expireat
[8] https://telegram.org/faq#q-how-do-self-destructing-messages-work

More information about the Standards mailing list