1711 строки
76 KiB
HTML
1711 строки
76 KiB
HTML
<!DOCTYPE html
|
|
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
|
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
<html><head>
|
|
<title>Off-the-Record Messaging Protocol version 3</title>
|
|
<style type="text/css">
|
|
body { background: white; color: black }
|
|
h1 { text-align: center }
|
|
dd ul.note { list-style: none }
|
|
dl.doublespace dd { margin-bottom: 2ex }
|
|
</style>
|
|
</head><body>
|
|
<h1>Off-the-Record Messaging Protocol version 3</h1>
|
|
<p>This document describes version 3 of the Off-the-Record Messaging
|
|
protocol. The main changes over version 2 include:</p>
|
|
<ul>
|
|
<li>Both fragmented and unfragmented messages contain sender and
|
|
recipient instance tags. This avoids an issue on IM networks that
|
|
always relay all messages to all sessions of a client who is logged
|
|
in multiple times. In this situation, OTR clients can attempt to
|
|
establish an OTR session indefinitely if there are interleaving
|
|
messages from each of the sessions.</li>
|
|
<li>An extra symmetric key is derived during AKE. This may be used for
|
|
secure communication over a different channel (e.g., file transfer,
|
|
voice chat).</li>
|
|
</ul>
|
|
<h2>Very high level overview</h2>
|
|
<p>OTR assumes a network model which provides in-order delivery of
|
|
messages, but that some messages may not get delivered at all
|
|
(for example, if the user disconnects). There may be
|
|
an active attacker, who is allowed to perform a Denial of
|
|
Service attack, but not to learn the contents of messages.</p>
|
|
<ol>
|
|
<li>Alice signals to Bob that she would like (using an OTR Query Message)
|
|
or is willing (using a whitespace-tagged plaintext message) to use OTR
|
|
to communicate. Either mechanism should convey the version(s) of OTR
|
|
that Alice is willing to use.</li>
|
|
<li>Bob initiates the authenticated key exchange (AKE) with Alice.
|
|
Versions 2 and 3 of OTR use a variant of the SIGMA protocol as its AKE.</li>
|
|
<li>Alice and Bob exchange Data Messages to send information to each
|
|
other.</li>
|
|
</ol>
|
|
<h2>High level overview</h2>
|
|
<h3>Requesting an OTR conversation</h3>
|
|
<p>There are two ways Alice can inform Bob that she is willing to use
|
|
the OTR protocol to speak with him: by sending him the OTR Query Message,
|
|
or by including a special "tag" consisting of whitespace characters in
|
|
one of her messages to him. Each method also includes a way for Alice
|
|
to communicate to Bob which versions of the OTR protocol she is willing
|
|
to speak with him.</p>
|
|
<p>The semantics of the OTR Query Message are that Alice is
|
|
<em>requesting</em> that Bob start an OTR conversation with her (if, of
|
|
course, he is willing and able to do so). On the other hand, the
|
|
semantics of the whitespace tag are that Alice is merely
|
|
<em>indicating</em> to Bob that she is willing and able to have an OTR
|
|
conversation with him. If Bob has a policy of "only use OTR when it's
|
|
explicitly requested", for example, then he <em>would</em> start an OTR
|
|
conversation upon receiving an OTR Query Message, but <em>would not</em>
|
|
upon receiving the whitespace tag.</p>
|
|
<h3>Authenticated Key Exchange (AKE)</h3>
|
|
<p>This section outlines the version of the SIGMA protocol used as the
|
|
AKE. All exponentiations are done modulo a particular 1536-bit prime,
|
|
and g is a generator of that group, as indicated in the detailed
|
|
description below. Alice and Bob's long-term authentication public keys
|
|
are pub<sub>A</sub> and pub<sub>B</sub>, respectively.</p>
|
|
<p>The general idea is that Alice and Bob do an <em>unauthenticated</em>
|
|
Diffie-Hellman (D-H) key exchange to set up an encrypted channel, and
|
|
then do mutual authentication <em>inside</em> that channel.</p>
|
|
<p>Bob will be initiating the AKE with Alice.</p>
|
|
<ul>
|
|
<li>Bob:
|
|
<ol>
|
|
<li>Picks a random value r (128 bits)</li>
|
|
<li>Picks a random value x (at least 320 bits)</li>
|
|
<li>Sends Alice AES<sub>r</sub>(g<sup>x</sup>), HASH(g<sup>x</sup>)</li>
|
|
</ol></li>
|
|
<li>Alice:
|
|
<ol>
|
|
<li>Picks a random value y (at least 320 bits)</li>
|
|
<li>Sends Bob g<sup>y</sup></li>
|
|
</ol></li>
|
|
<li>Bob:
|
|
<ol>
|
|
<li>Verifies that Alice's g<sup>y</sup> is a legal value (2 <=
|
|
g<sup>y</sup> <= modulus-2)</li>
|
|
<li>Computes s = (g<sup>y</sup>)<sup>x</sup></li>
|
|
<li>Computes two AES keys c, c' and four MAC keys m1, m1', m2, m2' by
|
|
hashing s in various ways</li>
|
|
<li>Picks keyid<sub>B</sub>, a serial number for his D-H key
|
|
g<sup>x</sup></li>
|
|
<li>Computes M<sub>B</sub> = MAC<sub>m1</sub>(g<sup>x</sup>, g<sup>y</sup>,
|
|
pub<sub>B</sub>, keyid<sub>B</sub>)</li>
|
|
<li>Computes X<sub>B</sub> = pub<sub>B</sub>, keyid<sub>B</sub>,
|
|
sig<sub>B</sub>(M<sub>B</sub>)</li>
|
|
<li>Sends Alice r, AES<sub>c</sub>(X<sub>B</sub>),
|
|
MAC<sub>m2</sub>(AES<sub>c</sub>(X<sub>B</sub>))</li>
|
|
</ol></li>
|
|
<li>Alice:
|
|
<ol>
|
|
<li>Uses r to decrypt the value of g<sup>x</sup> sent earlier</li>
|
|
<li>Verifies that HASH(g<sup>x</sup>) matches the value sent earlier</li>
|
|
<li>Verifies that Bob's g<sup>x</sup> is a legal value (2 <=
|
|
g<sup>x</sup> <= modulus-2)</li>
|
|
<li>Computes s = (g<sup>x</sup>)<sup>y</sup> (note that this will be the
|
|
same as the value of s Bob calculated)</li>
|
|
<li>Computes two AES keys c, c' and four MAC keys m1, m1', m2, m2' by
|
|
hashing s in various ways (the same as Bob)</li>
|
|
<li>Uses m2 to verify MAC<sub>m2</sub>(AES<sub>c</sub>(X<sub>B</sub>))</li>
|
|
<li>Uses c to decrypt AES<sub>c</sub>(X<sub>B</sub>) to obtain
|
|
X<sub>B</sub> = pub<sub>B</sub>, keyid<sub>B</sub>,
|
|
sig<sub>B</sub>(M<sub>B</sub>)</li>
|
|
<li>Computes M<sub>B</sub> = MAC<sub>m1</sub>(g<sup>x</sup>,
|
|
g<sup>y</sup>, pub<sub>B</sub>, keyid<sub>B</sub>)</li>
|
|
<li>Uses pub<sub>B</sub> to verify sig<sub>B</sub>(M<sub>B</sub>)</li>
|
|
|
|
<li>Picks keyid<sub>A</sub>, a serial number for her D-H key
|
|
g<sup>y</sup></li>
|
|
<li>Computes M<sub>A</sub> = MAC<sub>m1'</sub>(g<sup>y</sup>, g<sup>x</sup>,
|
|
pub<sub>A</sub>, keyid<sub>A</sub>)</li>
|
|
<li>Computes X<sub>A</sub> = pub<sub>A</sub>, keyid<sub>A</sub>,
|
|
sig<sub>A</sub>(M<sub>A</sub>)</li>
|
|
<li>Sends Bob AES<sub>c'</sub>(X<sub>A</sub>),
|
|
MAC<sub>m2'</sub>(AES<sub>c'</sub>(X<sub>A</sub>))</li>
|
|
</ol></li>
|
|
<li>Bob:
|
|
<ol>
|
|
<li>Uses m2' to verify MAC<sub>m2'</sub>(AES<sub>c'</sub>(X<sub>A</sub>))</li>
|
|
<li>Uses c' to decrypt AES<sub>c'</sub>(X<sub>A</sub>) to obtain
|
|
X<sub>A</sub> = pub<sub>A</sub>, keyid<sub>A</sub>,
|
|
sig<sub>A</sub>(M<sub>A</sub>)</li>
|
|
<li>Computes M<sub>A</sub> = MAC<sub>m1'</sub>(g<sup>y</sup>,
|
|
g<sup>x</sup>, pub<sub>A</sub>, keyid<sub>A</sub>)</li>
|
|
<li>Uses pub<sub>A</sub> to verify sig<sub>A</sub>(M<sub>A</sub>)</li>
|
|
</ol></li>
|
|
<li>If all of the verifications succeeded, Alice and Bob now know each
|
|
other's Diffie-Hellman public keys, and share the value s. Alice is
|
|
assured that s is known by someone with access to the private key
|
|
corresponding to pub<sub>B</sub>, and similarly for Bob.</li>
|
|
</ul>
|
|
<h3>Exchanging data</h3>
|
|
<p>This section outlines the method used to protect data being exchanged
|
|
between Alice and Bob. As above, all exponentiations are done modulo
|
|
a particular 1536-bit prime, and g is a generator of
|
|
that group, as indicated in the detailed description below.</p>
|
|
<p>Suppose Alice has a message (msg) to send to Bob.</p>
|
|
<ul>
|
|
<li>Alice:
|
|
<ol>
|
|
<li>Picks the most recent of her own D-H encryption keys that Bob has
|
|
acknowledged receiving (by using it in a Data Message, or failing that,
|
|
in the AKE). Let key<sub>A</sub> be that key, and let keyid<sub>A</sub>
|
|
be its serial number.</li>
|
|
<li>If the above key is Alice's most recent key, she generates a new D-H key
|
|
(next_dh), to get the serial number keyid<sub>A</sub>+1.</li>
|
|
<li>Picks the most recent of Bob's D-H encryption keys that she has
|
|
received from him (either in a Data Message or in the AKE). Let
|
|
key<sub>B</sub> by that key, and let keyid<sub>B</sub> be its serial
|
|
number.</li>
|
|
<li>Uses Diffie-Hellman to compute a shared secret from the two keys
|
|
key<sub>A</sub> and key<sub>B</sub>, and generates the
|
|
sending AES key, ek, and the sending MAC key, mk, as detailed
|
|
below.</li>
|
|
<li>Collects any old MAC keys that were used in previous messages, but
|
|
will never again be used (because their associated D-H keys are no
|
|
longer the most recent ones) into a list, oldmackeys.</li>
|
|
<li>Picks a value of the counter, ctr, so that the triple
|
|
(key<sub>A</sub>, key<sub>B</sub>, ctr) is never the same for more
|
|
than one Data Message Alice sends to Bob.</li>
|
|
<li>Computes T<sub>A</sub> = (keyid<sub>A</sub>, keyid<sub>B</sub>, next_dh,
|
|
ctr, AES-CTR<sub>ek,ctr</sub>(msg))</li>
|
|
<li>Sends Bob T<sub>A</sub>, MAC<sub>mk</sub>(T<sub>A</sub>),
|
|
oldmackeys</li>
|
|
</ol></li>
|
|
<li>Bob:
|
|
<ol>
|
|
<li>Uses Diffie-Hellman to compute a shared secret from the two keys
|
|
labelled by keyid<sub>A</sub> and keyid<sub>B</sub>, and generates the
|
|
receiving AES key, ek, and the receiving MAC key, mk, as detailed
|
|
below. (These will be the same as the keys Alice generated, above.)</li>
|
|
<li>Uses mk to verify MAC<sub>mk</sub>(T<sub>A</sub>).</li>
|
|
<li>Uses ek and ctr to decrypt
|
|
AES-CTR<sub>ek,ctr</sub>(msg).</li>
|
|
</ol>
|
|
</li>
|
|
</ul>
|
|
<h3>Socialist Millionaires' Protocol (SMP)</h3>
|
|
<p>While data messages are being exchanged, either Alice or Bob may
|
|
run SMP to detect impersonation or man-in-the-middle attacks.
|
|
As above, all exponentiations are done modulo a particular 1536-bit
|
|
prime, and g<sub>1</sub> is a generator of that group. All sent values
|
|
include zero-knowledge proofs that they were generated according to
|
|
this protocol, as indicated in the detailed description below.</p>
|
|
<p>Suppose Alice and Bob have secret information x and y respectively,
|
|
and they wish to know whether x = y. The Socialist Millionaires' Protocol
|
|
allows them to compare x and y without revealing any other information
|
|
than the value of (x == y). For OTR, the secrets contain
|
|
information about both parties' long-term authentication public keys,
|
|
as well as information entered by the users themselves. If x = y,
|
|
this means that Alice and Bob entered the same secret information, and
|
|
so must be the same entities who established that secret to begin with.</p>
|
|
<p>Assuming that Alice begins the exchange:</p>
|
|
<ul>
|
|
<li>Alice:
|
|
<ol>
|
|
<li>Picks random exponents a<sub>2</sub> and a<sub>3</sub></li>
|
|
<li>Sends Bob g<sub>2a</sub> = g<sub>1</sub><sup>a<sub>2</sub></sup> and
|
|
g<sub>3a</sub> = g<sub>1</sub><sup>a<sub>3</sub></sup></li>
|
|
</ol></li>
|
|
<li>Bob:
|
|
<ol>
|
|
<li>Picks random exponents b<sub>2</sub> and b<sub>3</sub></li>
|
|
<li>Computes g<sub>2b</sub> = g<sub>1</sub><sup>b<sub>2</sub></sup> and
|
|
g<sub>3b</sub> = g<sub>1</sub><sup>b<sub>3</sub></sup></li>
|
|
<li>Computes g<sub>2</sub> = g<sub>2a</sub><sup>b<sub>2</sub></sup> and
|
|
g<sub>3</sub> = g<sub>3a</sub><sup>b<sub>3</sub></sup></li>
|
|
<li>Picks random exponent r</li>
|
|
<li>Computes P<sub>b</sub> = g<sub>3</sub><sup>r</sup> and
|
|
Q<sub>b</sub> = g<sub>1</sub><sup>r</sup> g<sub>2</sub><sup>y</sup></li>
|
|
<li>Sends Alice g<sub>2b</sub>, g<sub>3b</sub>, P<sub>b</sub> and
|
|
Q<sub>b</sub></li>
|
|
</ol></li>
|
|
<li>Alice:
|
|
<ol>
|
|
<li>Computes g<sub>2</sub> = g<sub>2b</sub><sup>a<sub>2</sub></sup> and
|
|
g<sub>3</sub> = g<sub>3b</sub><sup>a<sub>3</sub></sup></li>
|
|
<li>Picks random exponent s</li>
|
|
<li>Computes P<sub>a</sub> = g<sub>3</sub><sup>s</sup> and
|
|
Q<sub>a</sub> = g<sub>1</sub><sup>s</sup> g<sub>2</sub><sup>x</sup></li>
|
|
<li>Computes R<sub>a</sub> = (Q<sub>a</sub> / Q<sub>b</sub>)
|
|
<sup>a<sub>3</sub></sup></li>
|
|
<li>Sends Bob P<sub>a</sub>, Q<sub>a</sub> and R<sub>a</sub></li>
|
|
</ol></li>
|
|
<li>Bob:
|
|
<ol>
|
|
<li>Computes R<sub>b</sub> = (Q<sub>a</sub> / Q<sub>b</sub>)
|
|
<sup>b<sub>3</sub></sup></li>
|
|
<li>Computes R<sub>ab</sub> = R<sub>a</sub><sup>b<sub>3</sub></sup></li>
|
|
<li>Checks whether R<sub>ab</sub> == (P<sub>a</sub> / P<sub>b</sub>)</li>
|
|
<li>Sends Alice R<sub>b</sub></li>
|
|
</ol></li>
|
|
<li>Alice:
|
|
<ol>
|
|
<li>Computes R<sub>ab</sub> = R<sub>b</sub><sup>a<sub>3</sub></sup></li>
|
|
<li>Checks whether R<sub>ab</sub> == (P<sub>a</sub> / P<sub>b</sub>)</li>
|
|
</ol></li>
|
|
<li>If everything is done correctly, then R<sub>ab</sub> should hold the
|
|
value of (P<sub>a</sub> / P<sub>b</sub>) times
|
|
(g<sub>2</sub><sup>a<sub>3</sub>b<sub>3</sub></sup>)<sup>(x - y)</sup>, which means that the test at the end of
|
|
the protocol will only succeed if x == y. Further, since
|
|
g<sub>2</sub><sup>a<sub>3</sub>b<sub>3</sub></sup> is a random number
|
|
not known to any party, if x is not equal to y, no other information is
|
|
revealed.</li>
|
|
</ul>
|
|
<h2>Details of the protocol</h2>
|
|
<h3>Unencoded messages</h3>
|
|
<p>This section describes the messages in the OTR protocol that are not
|
|
base-64 encoded binary.</p>
|
|
<h4>OTR Query Messages</h4>
|
|
<p>If Alice wishes to communicate to Bob that she would like to use OTR,
|
|
she sends a message containing the string "?OTR" followed by an
|
|
indication of what versions of OTR she is willing to use with Bob. The
|
|
version string is constructed as follows:</p>
|
|
<ul>
|
|
<li>If she is willing to use OTR version 1, the version string must
|
|
start with "?".</li>
|
|
<li>If she is willing to use OTR versions other than 1, a "v" followed
|
|
by the byte identifiers for the versions in question, followed by "?".
|
|
The byte identifier for OTR version 2 is "2", and similarly for 3. The
|
|
order of the identifiers between the "v" and the "?" does not matter,
|
|
but none should be listed more than once.</li>
|
|
</ul>
|
|
<p>For example:</p>
|
|
<dl>
|
|
<dt>"?OTR?"</dt>
|
|
<dd>Version 1 only</dd>
|
|
<dt>"?OTRv2?"</dt>
|
|
<dd>Version 2 only</dd>
|
|
<dt>"?OTRv23?"</dt>
|
|
<dd>Versions 2 and 3</dd>
|
|
<dt>"?OTR?v2?"</dt>
|
|
<dd>Versions 1 and 2</dd>
|
|
<dt>"?OTRv24x?"</dt>
|
|
<dd>Version 2, and hypothetical future versions identified by "4" and
|
|
"x"</dd>
|
|
<dt>"?OTR?v24x?"</dt>
|
|
<dd>Versions 1, 2, and hypothetical future versions identified by "4" and
|
|
"x"</dd>
|
|
<dt>"?OTR?v?"</dt>
|
|
<dd>Also version 1 only</dd>
|
|
<dt>"?OTRv?"</dt>
|
|
<dd>A bizarre claim that Alice would like to start an OTR conversation,
|
|
but is unwilling to speak any version of the protocol</dd>
|
|
</dl>
|
|
<p>These strings may be hidden from the user (for example, in
|
|
an attribute of an HTML tag), and/or may be accompanied by an
|
|
explanitory message ("Alice has requested an Off-the-Record private
|
|
conversation."). If Bob is willing to use OTR with Alice (with a
|
|
protocol version that Alice has offered), he should start the AKE.</p>
|
|
<h4>Tagged plaintext messages</h4>
|
|
<p>If Alice wishes to communicate to Bob that she is willing to use OTR,
|
|
she can attach a special whitespace tag to any plaintext message she
|
|
sends him. This tag may occur anywhere in the message, and may be
|
|
hidden from the user (as in the Query Messages, above).</p>
|
|
<p>The tag consists of the following 16 bytes, followed by one or more
|
|
sets of 8 bytes indicating the version of OTR Alice is willing to
|
|
use:</p>
|
|
<ul>
|
|
<li>Always send "\x20\x09\x20\x20\x09\x09\x09\x09"
|
|
"\x20\x09\x20\x09\x20\x09\x20\x20", followed by one or more of:</li>
|
|
<li>"\x20\x09\x20\x09\x20\x20\x09\x20" to indicate a willingness to use
|
|
OTR version 1 with Bob (note: this string must come before all other
|
|
whitespace version tags, if it is present, for backwards
|
|
compatibility)</li>
|
|
<li>"\x20\x20\x09\x09\x20\x20\x09\x20" to indicate a willingness to use
|
|
OTR version 2 with Bob</li>
|
|
<li>"\x20\x20\x09\x09\x20\x20\x09\x09" to indicate a willingness to use
|
|
OTR version 3 with Bob</li>
|
|
</ul>
|
|
<p>If Bob is willing to use OTR with Alice (with a protocol version that
|
|
Alice has offered), he should start the AKE. On the other hand, if
|
|
Alice receives a plaintext message from Bob (rather than an initiation
|
|
of the AKE), she should stop sending him the whitespace tag.</p>
|
|
<h4>OTR Error Messages</h4>
|
|
<p>Any message containing the string "?OTR Error:" is an OTR Error
|
|
Message. The following part of the message should contain
|
|
human-readable details of the error.</p>
|
|
<h3>Encoded messages</h3>
|
|
<p>This section describes the byte-level format of the base-64 encoded
|
|
binary OTR messages. The binary form of each of the messages is
|
|
described below. To transmit one of these messages, construct the ASCII
|
|
string consisting of the five bytes "?OTR:", followed by the base-64
|
|
encoding of the binary form of the message, followed by the byte
|
|
".".</p>
|
|
<p>For the Diffie-Hellman group computations, the group is the one
|
|
defined in RFC 3526 with 1536-bit modulus (hex, big-endian):</p>
|
|
<blockquote><pre>
|
|
FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1
|
|
29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD
|
|
EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245
|
|
E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED
|
|
EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE45B3D
|
|
C2007CB8 A163BF05 98DA4836 1C55D39A 69163FA8 FD24CF5F
|
|
83655D23 DCA3AD96 1C62F356 208552BB 9ED52907 7096966D
|
|
670C354E 4ABC9804 F1746C08 CA237327 FFFFFFFF FFFFFFFF
|
|
</pre></blockquote>
|
|
<p>and a generator (g) of 2. Note that this means that whenever you see a
|
|
Diffie-Hellman exponentiation in this document, it always means that the
|
|
exponentiation is done modulo the above 1536-bit number.</p>
|
|
<h4>Data types</h4>
|
|
<dl>
|
|
<dt>Bytes (BYTE):</dt>
|
|
<dd> 1 byte unsigned value</dd>
|
|
<dt>Shorts (SHORT):</dt>
|
|
<dd> 2 byte unsigned value, big-endian</dd>
|
|
<dt>Ints (INT):</dt>
|
|
<dd> 4 byte unsigned value, big-endian</dd>
|
|
<dt>Multi-precision integers (MPI):</dt>
|
|
<dd> 4 byte unsigned len, big-endian
|
|
<br /> len byte unsigned value, big-endian
|
|
<br /> (MPIs must use the minimum-length encoding; i.e. no leading 0x00
|
|
bytes. This is important when calculating public key
|
|
fingerprints.)</dd>
|
|
<dt>Opaque variable-length data (DATA):</dt>
|
|
<dd> 4 byte unsigned len, big-endian
|
|
<br /> len byte data</dd>
|
|
<dt>Initial CTR-mode counter value (CTR):</dt>
|
|
<dd> 8 bytes data</dd>
|
|
<dt>Message Authentication Code (MAC):</dt>
|
|
<dd> 20 bytes MAC data</dd>
|
|
</dl>
|
|
<h4>Public keys, signatures, and fingerprints</h4>
|
|
<p>OTR users have long-lived public keys that they use for
|
|
authentication (but <em>not</em> encryption). The current version of
|
|
the OTR protocol only supports DSA public keys, but there is a key type
|
|
marker for future extensibility.</p>
|
|
<dl>
|
|
<dt>OTR public authentication DSA key (PUBKEY):</dt>
|
|
<dd>Pubkey type (SHORT)
|
|
<ul class="note"><li>DSA public keys have type 0x0000</li></ul>
|
|
p (MPI)
|
|
<br />q (MPI)
|
|
<br />g (MPI)
|
|
<br />y (MPI)
|
|
<ul class="note"><li>(p,q,g,y) are the DSA public key parameters</li></ul>
|
|
</dd>
|
|
</dl>
|
|
<p>OTR public keys are used to generate <b>signatures</b>; different
|
|
types of keys produce signatures in different formats. The format for a
|
|
signature made by a DSA public key is as follows:</p>
|
|
<dl>
|
|
<dt>DSA signature (SIG):</dt>
|
|
<dd> (len is the length of the DSA public parameter q, which in
|
|
current implementations must be 20 bytes, or 160 bits)
|
|
<br /> len byte unsigned r, big-endian
|
|
<br /> len byte unsigned s, big-endian</dd>
|
|
</dl>
|
|
<p>OTR public keys have <b>fingerprints</b>, which are hex strings that
|
|
serve as identifiers for the public key. The fingerprint is calculated
|
|
by taking the SHA-1 hash of the byte-level representation of the public
|
|
key. However, there is an exception for backwards compatibility: if the
|
|
pubkey type is 0x0000, those two leading 0x00 bytes are omitted from the
|
|
data to be hashed. The encoding assures that, assuming the hash
|
|
function itself has no useful collisions, and DSA keys have length less
|
|
than 524281 bits (500 times larger than most DSA keys), no two public
|
|
keys will have the same fingerprint.</p>
|
|
<h4>Instance Tags</h4>
|
|
<p>Clients include instance tags in all OTR version 3 messages. Instance
|
|
tags are 32-bit values that are intended to be persistent. If the same
|
|
client is logged into the same account from multiple locations, the
|
|
intention is that the client will have different instance tags at each
|
|
location. As shown below, OTR version 3 messages (fragmented and
|
|
unfragmented) include the source and destination instance tags. If a client
|
|
receives a message that lists a destination instance tag different from its
|
|
own, the client should discard the message.</p>
|
|
<p>The smallest valid instance tag is 0x00000100. It is appropriate to set the
|
|
destination instance tag to '0' when an actual destination instance tag is
|
|
not known at the time the message is prepared. If a client receives a
|
|
message with the sender instance tag set to less than 0x00000100, it should
|
|
discard the message. Similarly, if a client receives a message with the
|
|
recipient instance tag set to greater than 0 but less than 0x00000100, it
|
|
should discard the message.
|
|
</p>
|
|
|
|
<p>This avoids an issue on IM networks that always relay all messages to
|
|
all sessions of a client who is logged in multiple times. In this
|
|
situation, OTR clients can attempt to establish an OTR session indefinitely
|
|
if there are interleaving messages from each of the sessions.</p>
|
|
<h4>D-H Commit Message</h4>
|
|
<p>This is the first message of the AKE. Bob sends it to Alice to
|
|
commit to a choice of D-H encryption key (but the key itself is not yet
|
|
revealed). This allows the secure session id to be much shorter than in
|
|
OTR version 1, while still preventing a man-in-the-middle attack on
|
|
it.</p>
|
|
<dl>
|
|
<dt>Protocol version (SHORT)</dt>
|
|
<dd>The version number of this protocol is 0x0003.</dd>
|
|
<dt>Message type (BYTE)</dt>
|
|
<dd>The D-H Commit Message has type 0x02.</dd>
|
|
<dt>Sender Instance tag (INT)</dt>
|
|
<dd>The instance tag of the person sending this message.</dd>
|
|
<dt>Receiver Instance tag (INT)</dt>
|
|
<dd>The instance tag of the intended recipient.
|
|
For a commit message this will often be 0, since the other party
|
|
may not have identified their instance tag yet.</dd>
|
|
<dt>Encrypted g<sup>x</sup> (DATA)</dt>
|
|
<dd>Produce this field as follows:
|
|
<ul>
|
|
<li>Choose a random value r (128 bits)</li>
|
|
<li>Choose a random value x (at least 320 bits)</li>
|
|
<li>Serialize g<sup>x</sup> as an MPI, gxmpi. [gxmpi will probably be
|
|
196 bytes long, starting with "\x00\x00\x00\xc0".]</li>
|
|
<li>Encrypt gxmpi using AES128-CTR, with key r and initial counter value
|
|
0. The result will be the same length as gxmpi.</li>
|
|
<li>Encode this encrypted value as the DATA field.</li>
|
|
</ul></dd>
|
|
<dt>Hashed g<sup>x</sup> (DATA)</dt>
|
|
<dd>This is the SHA256 hash of gxmpi.</dd>
|
|
</dl>
|
|
<h4>D-H Key Message</h4>
|
|
<p>This is the second message of the AKE. Alice sends it to Bob, and it
|
|
simply consists of Alice's D-H encryption key.</p>
|
|
<dl>
|
|
<dt>Protocol version (SHORT)</dt>
|
|
<dd>The version number of this protocol is 0x0003.</dd>
|
|
<dt>Message type (BYTE)</dt>
|
|
<dd>The D-H Key Message has type 0x0a.</dd>
|
|
<dt>Sender Instance tag (INT)</dt>
|
|
<dd>The instance tag of the person sending this message.</dd>
|
|
<dt>Receiver Instance tag (INT)</dt>
|
|
<dd>The instance tag of the intended recipient.</dd>
|
|
<dt>g<sup>y</sup> (MPI)</dt>
|
|
<dd>Choose a random value y (at least 320 bits), and calculate
|
|
g<sup>y</sup>.</dd>
|
|
</dl>
|
|
<h4>Reveal Signature Message</h4>
|
|
<p>This is the third message of the AKE. Bob sends it to Alice,
|
|
revealing his D-H encryption key (and thus opening an encrypted
|
|
channel), and also authenticating himself (and the parameters of the
|
|
channel, preventing a man-in-the-middle attack on the channel itself) to
|
|
Alice.</p>
|
|
<dl>
|
|
<dt>Protocol version (SHORT)</dt>
|
|
<dd>The version number of this protocol is 0x0003.</dd>
|
|
<dt>Message type (BYTE)</dt>
|
|
<dd>The Reveal Signature Message has type 0x11.</dd>
|
|
<dt>Sender Instance tag (INT)</dt>
|
|
<dd>The instance tag of the person sending this message.</dd>
|
|
<dt>Receiver Instance tag (INT)</dt>
|
|
<dd>The instance tag of the intended recipient.</dd>
|
|
<dt>Revealed key (DATA)</dt>
|
|
<dd>This is the value r picked earlier.</dd>
|
|
<dt>Encrypted signature (DATA)</dt>
|
|
<dd>This field is calculated as follows:
|
|
<ul>
|
|
<li>Compute the Diffie-Hellman shared secret s.</li>
|
|
<li>Use s to compute an AES key c and two MAC keys m1 and m2, as specified below.</li>
|
|
<li>Select keyid<sub>B</sub>, a serial number for the D-H key computed
|
|
earlier. It is an INT, and must be greater than 0.</li>
|
|
<li>Compute the 32-byte value M<sub>B</sub> to be the SHA256-HMAC of the
|
|
following data, using the key m1:<dl>
|
|
<dt>g<sup>x</sup> (MPI)</dt>
|
|
<dt>g<sup>y</sup> (MPI)</dt>
|
|
<dt>pub<sub>B</sub> (PUBKEY)</dt>
|
|
<dt>keyid<sub>B</sub> (INT)</dt>
|
|
</dl></li>
|
|
<li>Let X<sub>B</sub> be the following structure:<dl>
|
|
<dt>pub<sub>B</sub> (PUBKEY)</dt>
|
|
<dt>keyid<sub>B</sub> (INT)</dt>
|
|
<dt>sig<sub>B</sub>(M<sub>B</sub>) (SIG)</dt>
|
|
<dd>This is the signature, using the private part of the key
|
|
pub<sub>B</sub>, of the 32-byte M<sub>B</sub> (taken modulo q instead of
|
|
being truncated (as described in FIPS-186), and not hashed again).</dd>
|
|
</dl></li>
|
|
<li>Encrypt X<sub>B</sub> using AES128-CTR with key c and initial
|
|
counter value 0.</li>
|
|
<li>Encode this encrypted value as the DATA field.</li>
|
|
</ul></dd>
|
|
<dt>MAC'd signature (MAC)</dt>
|
|
<dd>This is the SHA256-HMAC-160 (that is, the first 160 bits of the
|
|
SHA256-HMAC) of the encrypted signature field (including the four-byte
|
|
length), using the key m2.</dd>
|
|
</dl>
|
|
<h4>Signature Message</h4>
|
|
<p>This is the final message of the AKE. Alice sends it to Bob,
|
|
authenticating herself and the channel parameters to him.</p>
|
|
<dl>
|
|
<dt>Protocol version (SHORT)</dt>
|
|
<dd>The version number of this protocol is 0x0003.</dd>
|
|
<dt>Message type (BYTE)</dt>
|
|
<dd>The Signature Message has type 0x12.</dd>
|
|
<dt>Sender Instance tag (INT)</dt>
|
|
<dd>The instance tag of the person sending this message.</dd>
|
|
<dt>Receiver Instance tag (INT)</dt>
|
|
<dd>The instance tag of the intended recipient.</dd>
|
|
<dt>Encrypted signature (DATA)</dt>
|
|
<dd>This field is calculated as follows:
|
|
<ul>
|
|
<li>Compute the Diffie-Hellman shared secret s.</li>
|
|
<li>Use s to compute an AES key c' and two MAC keys m1' and m2', as specified below.</li>
|
|
<li>Select keyid<sub>A</sub>, a serial number for the D-H key computed
|
|
earlier. It is an INT, and must be greater than 0.</li>
|
|
<li>Compute the 32-byte value M<sub>A</sub> to be the SHA256-HMAC of the
|
|
following data, using the key m1':<dl>
|
|
<dt>g<sup>y</sup> (MPI)</dt>
|
|
<dt>g<sup>x</sup> (MPI)</dt>
|
|
<dt>pub<sub>A</sub> (PUBKEY)</dt>
|
|
<dt>keyid<sub>A</sub> (INT)</dt>
|
|
</dl></li>
|
|
<li>Let X<sub>A</sub> be the following structure:<dl>
|
|
<dt>pub<sub>A</sub> (PUBKEY)</dt>
|
|
<dt>keyid<sub>A</sub> (INT)</dt>
|
|
<dt>sig<sub>A</sub>(M<sub>A</sub>) (SIG)</dt>
|
|
<dd>This is the signature, using the private part of the key
|
|
pub<sub>A</sub>, of the 32-byte M<sub>A</sub> (which does not need to be
|
|
hashed again to produce the signature).</dd>
|
|
</dl></li>
|
|
<li>Encrypt X<sub>A</sub> using AES128-CTR with key c' and initial
|
|
counter value 0.</li>
|
|
<li>Encode this encrypted value as the DATA field.</li>
|
|
</ul></dd>
|
|
<dt>MAC'd signature (MAC)</dt>
|
|
<dd>This is the SHA256-HMAC-160 (that is, the first 160 bits of the
|
|
SHA256-HMAC) of the encrypted signature field (including the four-byte
|
|
length), using the key m2'.</dd>
|
|
</dl>
|
|
<h4>Data Message</h4>
|
|
<p>This message is used to transmit a private message to the
|
|
correspondent. It is also used to reveal old MAC keys.</p>
|
|
<p>The plaintext message (either before encryption, or after decryption)
|
|
consists of a human-readable message (encoded in UTF-8, optionally with
|
|
HTML markup), optionally followed by:</p>
|
|
<ul>
|
|
<li>a single NUL (a BYTE with value 0x00), <b>and</b></li>
|
|
<li>zero or more TLV (type/length/value) records (with no padding
|
|
between them)</li>
|
|
</ul>
|
|
<p>Each TLV record is of the form:</p>
|
|
<dl>
|
|
<dt>Type (SHORT)</dt>
|
|
<dd>The type of this record. Records with unrecognized types should be
|
|
ignored.</dd>
|
|
<dt>Length (SHORT)</dt>
|
|
<dd>The length of the following field</dd>
|
|
<dt>Value (len BYTEs) [where len is the value of the Length field]</dt>
|
|
<dd>Any pertinent data for the record type.</dd>
|
|
</dl>
|
|
<p>Some TLV examples:</p>
|
|
<dl>
|
|
<dt>\x00\x01\x00\x00</dt>
|
|
<dd>A TLV of type 1, containing no data</dd>
|
|
<dt>\x00\x00\x00\x05\x68\x65\x6c\x6c\x6f</dt>
|
|
<dd>A TLV of type 0, containing the value "hello"</dd>
|
|
</dl>
|
|
<p>The currently defined TLV record types are:</p>
|
|
<dl>
|
|
<dt>Type 0: Padding</dt>
|
|
<dd>The value may be an arbitrary amount of data, which should be
|
|
ignored. This type can be used to disguise the length of the plaintext
|
|
message.</dd>
|
|
<dt>Type 1: Disconnected</dt>
|
|
<dd>If the user requests to close the private connection, you may send a
|
|
message (possibly with empty human-readable part) containing a record
|
|
with this TLV type just before you discard the session keys, and
|
|
transition to MSGSTATE_PLAINTEXT (see below). If you receive a TLV
|
|
record of this type, you should transition to MSGSTATE_FINISHED (see
|
|
below), and inform the user that his correspondent has closed his end of
|
|
the private connection, and the user should do the same.</dd>
|
|
<dt>Type 2: SMP Message 1</dt>
|
|
<dd>The value represents an initiating message of the Socialist
|
|
Millionaires' Protocol, described below.</dd>
|
|
<dt>Type 3: SMP Message 2</dt>
|
|
<dd>The value represents the second message in an instance of SMP.</dd>
|
|
<dt>Type 4: SMP Message 3</dt>
|
|
<dd>The value represents the third message in an instance of SMP.</dd>
|
|
<dt>Type 5: SMP Message 4</dt>
|
|
<dd>The value represents the final message in an instance of SMP.</dd>
|
|
<dt>Type 6: SMP Abort Message</dt>
|
|
<dd>If the user cancels SMP prematurely or encounters an error in the
|
|
protocol and cannot continue, you may send a message (possibly with empty
|
|
human-readable part) with this TLV type to instruct the other party's
|
|
client to abort the protocol. The associated length should be zero and
|
|
the associated value should be empty. If you receive a TLV of this type,
|
|
you should change the SMP state to SMP_EXPECT1 (see below).</dd>
|
|
<dt>Type 7: SMP Message 1Q</dt>
|
|
<dd>Like a SMP Message 1, but whose value begins with a NUL-terminated
|
|
user-specified question.</dd>
|
|
<dt>Type 8: Extra symmetric key</dt>
|
|
<dd>If you wish to use the extra symmetric key, compute it yourself as
|
|
outlined in the section "Extra symmetric key", below. Then send this
|
|
type 8 TLV to your buddy to indicate that you'd like to use the extra
|
|
symmetric key for something. The value of the TLV begins with a 4-byte
|
|
indication of what this symmetric key will be used for (file transfer,
|
|
voice encryption, etc.). After that, the contents are use-specific
|
|
(which file, etc.). There are no currently defined uses. Note that the
|
|
value of the key itself is <em>not</em> placed into the TLV; your buddy
|
|
will compute it on his/her own.
|
|
</dd>
|
|
</dl>
|
|
<p>SMP Message TLVs (types 2-5) all carry data sharing the same general
|
|
format:</p>
|
|
<dl>
|
|
<dt>MPI count (INT)</dt>
|
|
<dd>The number of MPIs contained in the remainder of the TLV.</dd>
|
|
<dt>MPI 1 (MPI)</dt>
|
|
<dd>The first MPI of the TLV, serialized into a byte array.</dd>
|
|
<dt>MPI 2 (MPI)</dt>
|
|
<dd>The second MPI of the TLV, serialized into a byte array.</dd>
|
|
<dt>etc.</dt>
|
|
</dl>
|
|
<p>There should be as many MPIs as declared in the MPI count field. For
|
|
the exact MPIs passed for each SMP TLV, see the SMP state machine
|
|
below.</p>
|
|
<p>A message with an empty human-readable part (the plaintext is of zero
|
|
length, or starts with a NUL) is a "heartbeat" packet, and should not
|
|
be displayed to the user. (But it's still useful to effect key
|
|
rotations.)</p>
|
|
<p>Data Message format:</p>
|
|
<dl>
|
|
<dt>Protocol version (SHORT)</dt>
|
|
<dd>The version number of this protocol is 0x0003.</dd>
|
|
<dt>Message type (BYTE)</dt>
|
|
<dd>The Data Message has type 0x03.</dd>
|
|
<dt>Sender Instance tag (INT)</dt>
|
|
<dd>The instance tag of the person sending this message.</dd>
|
|
<dt>Receiver Instance tag (INT)</dt>
|
|
<dd>The instance tag of the intended recipient.</dd>
|
|
<dt>Flags (BYTE)</dt>
|
|
<dd>The bitwise-OR of the flags for this message. Usually you should
|
|
set this to 0x00. The only currently defined flag is:<dl>
|
|
<dt>IGNORE_UNREADABLE (0x01)</dt>
|
|
<dd>If you receive a Data Message with this flag set, and you are unable
|
|
to decrypt the message or verify the MAC (because, for example, you
|
|
don't have the right keys), just ignore the message instead of producing
|
|
some kind of error or notification to the user.</dd>
|
|
</dl></dd>
|
|
<dt>Sender keyid (INT)</dt>
|
|
<dd>Must be strictly greater than 0, and increment by 1 with each key
|
|
change</dd>
|
|
<dt>Recipient keyid (INT)</dt>
|
|
<dd>Must therefore be strictly greater than 0, as the receiver has no
|
|
key with id 0.
|
|
<br />The sender and recipient keyids are those used to encrypt and MAC
|
|
this message.</dd>
|
|
<dt>DH y (MPI)</dt>
|
|
<dd>The *next* [i.e. sender_keyid+1] public key for the sender</dd>
|
|
<dt>Top half of counter init (CTR)</dt>
|
|
<dd>This should monotonically increase (as a big-endian value) for
|
|
each message sent with the same (sender keyid, recipient keyid)
|
|
pair, and must not be all 0x00.</dd>
|
|
<dt>Encrypted message (DATA)</dt>
|
|
<dd>Using the appropriate encryption key (see below) derived from the
|
|
sender's and recipient's DH public keys (with the keyids given in
|
|
this message), perform AES128 counter-mode (CTR) encryption of the
|
|
message. The initial counter is a 16-byte value whose first 8
|
|
bytes are the above "top half of counter init" value, and whose
|
|
last 8 bytes are all 0x00. Note that counter mode does not change
|
|
the length of the message, so no message padding needs to be done.
|
|
If you *want* to do message padding (to disguise the length of
|
|
your message), use the above TLV of type 0.</dd>
|
|
<dt>Authenticator (MAC)</dt>
|
|
<dd>The SHA1-HMAC, using the appropriate MAC key (see below) of everything
|
|
from the Protocol version to the end of the encrypted message</dd>
|
|
<dt>Old MAC keys to be revealed (DATA)</dt>
|
|
<dd>See "Revealing MAC Keys", below.</dd>
|
|
</dl>
|
|
<h3>Socialist Millionaires' Protocol (SMP)</h3>
|
|
<p>The Socialist Millionaires' Protocol allows two parties with secret
|
|
information x and y respectively to check whether (x==y) without revealing
|
|
any additional information about the secrets. The protocol used by OTR is
|
|
based on the work of Boudot, Schoenmakers and Traore (2001). A full
|
|
justification for its use in OTR is made by Alexander and Goldberg,
|
|
in a paper published in 2007. The following is a technical account
|
|
of what is transmitted during the course of the protocol.</p>
|
|
<h4>Secret information</h4>
|
|
<p>The secret information x and y compared during this protocol contains
|
|
not only information entered by the users, but also information unique to
|
|
the conversation in which SMP takes place. Specifically, the format is:</p>
|
|
<dl>
|
|
<dt>Version (BYTE)</dt>
|
|
<dd>The version of SMP used. The version described here is 1.</dd>
|
|
<dt>Initiator fingerprint (20 BYTEs)</dt>
|
|
<dd>The fingerprint that the party initiating SMP is using in
|
|
the current conversation.</dd>
|
|
<dt>Responder fingerprint (20 BYTEs)</dt>
|
|
<dd>The fingerprint that the party that did not initiate SMP is
|
|
using in the current conversation.</dd>
|
|
<dt>Secure Session ID</dt>
|
|
<dd>The ssid described below.</dd>
|
|
<dt>User-specified secret</dt>
|
|
<dd>The input string given by the user at runtime.</dd>
|
|
</dl>
|
|
<p>Then the SHA256 hash of the above is taken, and the digest becomes the
|
|
actual secret (x or y) to be used in SMP. The additional fields insure
|
|
that not only do both parties know the same secret input string, but no
|
|
man-in-the-middle is capable of reading their communication either.</p>
|
|
<h3>The SMP state machine</h3>
|
|
<p>Whenever the OTR message state machine has MSGSTATE_ENCRYPTED set
|
|
(see below), the SMP state machine may progress. If at any point
|
|
MSGSTATE_ENCRYPTED becomes unset, SMP must abandon its state and return
|
|
to its initial setup. The SMP state consists of one main variable, as
|
|
well as information from the partial computations at each protocol step.</p>
|
|
<h4>Expected Message</h4>
|
|
<p>This main state variable for SMP controls what SMP-specific TLVs will
|
|
be accepted. This variable has no effect on type 0 or type 1 TLVs, which
|
|
are always allowed. smpstate can take one of four values:</p>
|
|
<dl>
|
|
<dt>SMPSTATE_EXPECT1</dt>
|
|
<dd>This state indicates that only type 2 (SMP message 1) and type 7
|
|
(SMP message 1Q) TLVs should be accepted. This is the default state when
|
|
SMP has not yet begun. This state is also reached whenever an error
|
|
occurs or SMP is aborted, and the protocol must be restarted from the
|
|
beginning.</dd>
|
|
<dt>SMPSTATE_EXPECT2</dt>
|
|
<dd>This state indicates that only type 3 TLVs (SMP message 2) should
|
|
be accepted.</dd>
|
|
<dt>SMPSTATE_EXPECT3</dt>
|
|
<dd>This state indicates that only type 4 TLVs (SMP message 3) should
|
|
be accepted.</dd>
|
|
<dt>SMPSTATE_EXPECT4</dt>
|
|
<dd>This state indicates that only type 5 TLVs (SMP message 4) should
|
|
be accepted.</dd>
|
|
</dl>
|
|
<h4>State Transitions</h4>
|
|
<p>There are 7 actions that an OTR client must handle:</p>
|
|
<ul>
|
|
<li>Received TLVs:
|
|
<ul>
|
|
<li>SMP Message 1</li>
|
|
<li>SMP Message 2</li>
|
|
<li>SMP Message 3</li>
|
|
<li>SMP Message 4</li>
|
|
<li>SMP Abort Message</li>
|
|
</ul></li>
|
|
<li>User actions:</li>
|
|
<ul>
|
|
<li>User requests to begin SMP</li>
|
|
<li>User requests to abort SMP</li>
|
|
</ul></li>
|
|
</ul>
|
|
<p>The following sections outline what is to be done in each case. They
|
|
all assume that MSGSTATE_ENCRYPTED is set. For simplicity, they also
|
|
assume that Alice has begun SMP, and Bob is responding to her.</p>
|
|
<h4>SMP Hash function</h4>
|
|
<p>In the following actions, there are many places where a SHA256 hash of
|
|
an integer followed by one or two MPIs is taken. The input to this hash
|
|
function is:</p>
|
|
<dl>
|
|
<dt>Version (BYTE)</dt>
|
|
<dd>This distinguishes calls to the hash function at different points in
|
|
the protocol, to prevent Alice from replaying Bob's zero knowledge proofs
|
|
or vice versa.</dd>
|
|
<dt>First MPI (MPI)</dt>
|
|
<dd>The first MPI given as input, serialized in the usual way.</dd>
|
|
<dt>Second MPI (MPI)</dt>
|
|
<dd>The second MPI given as input, if present, serialized in the usual way.
|
|
If only one MPI is given as input, this field is simply omitted.</dd>
|
|
</dl>
|
|
<h4>Receiving a type 2 TLV (SMP message 1)</h4>
|
|
<p>SMP message 1 is sent by Alice to begin a DH exchange to determine two
|
|
new generators, g<sub>2</sub> and g<sub>3</sub>. It contains the
|
|
following mpi values:</p>
|
|
<dl>
|
|
<dt>g<sub>2a</sub></dt>
|
|
<dd>Alice's half of the DH exchange to determine g<sub>2</sub>.</dd>
|
|
<dt>c2, D2</dt>
|
|
<dd>A zero-knowledge proof that Alice knows the exponent associated with
|
|
her transmitted value g<sub>2a</sub>.</dd>
|
|
<dt>g<sub>3a</sub></dt>
|
|
<dd>Alice's half of the DH exchange to determine g<sub>3</sub>.</dd>
|
|
<dt>c3, D3</dt>
|
|
<dd>A zero-knowledge proof that Alice knows the exponent associated with
|
|
her transmitted value g<sub>3a</sub>.</dd>
|
|
</dl>
|
|
<p>A type 7 (SMP Message 1Q) TLV is the same as the above, but is
|
|
preceded by a user-specified question, which is associated with the
|
|
user-specified portion of the secret.</p>
|
|
<p>When Bob receives this TLV he should do:</p>
|
|
<dl>
|
|
<dt>If smpstate is not SMPSTATE_EXPECT1:</dt>
|
|
<dd>Set smpstate to SMPSTATE_EXPECT1 and send a type 6 TLV (SMP abort)
|
|
to Alice.</dd>
|
|
<dt>If smpstate is SMPSTATE_EXPECT1:</dt>
|
|
<dd>Verify Alice's zero-knowledge proofs for g<sub>2a</sub> and
|
|
g<sub>3a</sub>:
|
|
<ol>
|
|
<li>Check that both g<sub>2a</sub> and g<sub>3a</sub> are >= 2 and
|
|
<= modulus-2.</li>
|
|
<li>Check that c2 = SHA256(1, g<sub>1</sub><sup>D2</sup>
|
|
g<sub>2a</sub><sup>c2</sup>).</li>
|
|
<li>Check that c3 = SHA256(2, g<sub>1</sub><sup>D3</sup>
|
|
g<sub>3a</sub><sup>c3</sup>).</li>
|
|
</ol>
|
|
Create a type 3 TLV (SMP message 2) and send it to Alice:
|
|
<ol>
|
|
<li>Determine Bob's secret input y, which is to be compared to Alice's
|
|
secret x.</li>
|
|
<li>Pick random exponents b<sub>2</sub> and b<sub>3</sub>.
|
|
These will used during the DH exchange to pick generators.</li>
|
|
<li>Pick random exponents r2, r3, r4, r5 and r6.
|
|
These will be used to add a blinding factor to the final results, and
|
|
to generate zero-knowledge proofs that this message was created honestly.</li>
|
|
<li>Compute g<sub>2b</sub> = g<sub>1</sub><sup>b<sub>2</sub></sup> and
|
|
g<sub>3b</sub> = g<sub>1</sub><sup>b<sub>3</sub></sup></li>
|
|
<li>Generate a zero-knowledge proof that the exponent b<sub>2</sub> is
|
|
known by setting c2 = SHA256(3, g<sub>1</sub><sup>r2</sup>) and
|
|
D2 = r2 - b<sub>2</sub> c2 mod q. In the zero-knowledge proofs the D values
|
|
are calculated modulo q = (p - 1) / 2, where p is the same 1536-bit prime
|
|
as elsewhere. The random exponents are 1536-bit numbers.</li>
|
|
<li>Generate a zero-knowledge proof that the exponent b<sub>3</sub> is
|
|
known by setting c3 = SHA256(4, g<sub>1</sub><sup>r3</sup>) and
|
|
D3 = r3 - b<sub>3</sub> c3 mod q.</li>
|
|
<li>Compute g<sub>2</sub> = g<sub>2a</sub><sup>b<sub>2</sub></sup> and
|
|
g<sub>3</sub> = g<sub>3a</sub><sup>b<sub>3</sub></sup></li>
|
|
<li>Compute P<sub>b</sub> = g<sub>3</sub><sup>r4</sup> and
|
|
Q<sub>b</sub> = g<sub>1</sub><sup>r4</sup> g<sub>2</sub><sup>y</sup></li>
|
|
<li>Generate a zero-knowledge proof that P<sub>b</sub> and Q<sub>b</sub>
|
|
were created according to the protocol by setting
|
|
cP = SHA256(5, g<sub>3</sub><sup>r5</sup>, g<sub>1</sub><sup>r5</sup>
|
|
g<sub>2</sub><sup>r6</sup>), D5 = r5 - r4 cP mod q and D6 = r6 - y cP mod q.</li>
|
|
<li>Store the values of g<sub>3a</sub>, g<sub>2</sub>, g<sub>3</sub>,
|
|
b<sub>3</sub>, P<sub>b</sub> and Q<sub>b</sub> for use later in the
|
|
protocol.</li>
|
|
<li>Send Alice a type 3 TLV (SMP message 2) containing g<sub>2b</sub>,
|
|
c2, D2, g<sub>3b</sub>, c3, D3, P<sub>b</sub>, Q<sub>b</sub>, cP, D5
|
|
and D6, in that order.</li>
|
|
</ol>
|
|
Set smpstate to SMPSTATE_EXPECT3.</dd>
|
|
</dl>
|
|
<h4>Receiving a type 3 TLV (SMP message 2)</h4>
|
|
<p>SMP message 2 is sent by Bob to complete the DH exchange to
|
|
determine the new generators, g<sub>2</sub> and g<sub>3</sub>.
|
|
It also begins the construction of the values used in the final
|
|
comparison of the protocol. It contains the following mpi values:</p>
|
|
<dl>
|
|
<dt>g<sub>2b</sub></dt>
|
|
<dd>Bob's half of the DH exchange to determine g<sub>2</sub>.</dd>
|
|
<dt>c2, D2</dt>
|
|
<dd>A zero-knowledge proof that Bob knows the exponent associated with
|
|
his transmitted value g<sub>2b</sub>.</dd>
|
|
<dt>g<sub>3b</sub></dt>
|
|
<dd>Bob's half of the DH exchange to determine g<sub>3</sub>.</dd>
|
|
<dt>c3, D3</dt>
|
|
<dd>A zero-knowledge proof that Bob knows the exponent associated with
|
|
his transmitted value g<sub>3b</sub>.</dd>
|
|
<dt>P<sub>b</sub>, Q<sub>b</sub></dt>
|
|
<dd>These values are used in the final comparison to determine if Alice
|
|
and Bob share the same secret.</dd>
|
|
<dt>cP, D5, D6</dt>
|
|
<dd>A zero-knowledge proof that P<sub>b</sub> and Q<sub>b</sub> were
|
|
created according to the protcol given above.</dd>
|
|
</dl>
|
|
<p>When Alice receives this TLV she should do:</p>
|
|
<dl>
|
|
<dt>If smpstate is not SMPSTATE_EXPECT2:</dt>
|
|
<dd>Set smpstate to SMPSTATE_EXPECT1 and send a type 6 TLV (SMP abort)
|
|
to Bob.</dd>
|
|
<dt>If smpstate is SMPSTATE_EXPECT2:</dt>
|
|
<dd>Verify Bob's zero-knowledge proofs for g<sub>2b</sub>,
|
|
g<sub>3b</sub>, P<sub>b</sub> and Q<sub>b</sub>:
|
|
<ol>
|
|
<li>Check that g<sub>2b</sub>,
|
|
g<sub>3b</sub>, P<sub>b</sub> and Q<sub>b</sub> are >= 2 and
|
|
<= modulus-2.</li>
|
|
<li>Check that c2 = SHA256(3, g<sub>1</sub><sup>D2</sup>
|
|
g<sub>2b</sub><sup>c2</sup>).</li>
|
|
<li>Check that c3 = SHA256(4, g<sub>1</sub><sup>D3</sup>
|
|
g<sub>3b</sub><sup>c3</sup>).</li>
|
|
<li>Check that cP = SHA256(5, g<sub>3</sub><sup>D5</sup>
|
|
P<sub>b</sub><sup>cP</sup>, g<sub>1</sub><sup>D5</sup>
|
|
g<sub>2</sub><sup>D6</sup> Q<sub>b</sub><sup>cP</sup>).</li>
|
|
</ol>
|
|
Create a type 4 TLV (SMP message 3) and send it to Bob:
|
|
<ol>
|
|
<li>Pick random exponents r4, r5, r6 and r7.
|
|
These will be used to add a blinding factor to the final results, and
|
|
to generate zero-knowledge proofs that this message was created honestly.</li>
|
|
<li>Compute g<sub>2</sub> = g<sub>2b</sub><sup>a<sub>2</sub></sup> and
|
|
g<sub>3</sub> = g<sub>3b</sub><sup>a<sub>3</sub></sup></li>
|
|
<li>Compute P<sub>a</sub> = g<sub>3</sub><sup>r4</sup> and
|
|
Q<sub>a</sub> = g<sub>1</sub><sup>r4</sup> g<sub>2</sub><sup>x</sup></li>
|
|
<li>Generate a zero-knowledge proof that P<sub>a</sub> and Q<sub>a</sub>
|
|
were created according to the protocol by setting
|
|
cP = SHA256(6, g<sub>3</sub><sup>r5</sup>, g<sub>1</sub><sup>r5</sup>
|
|
g<sub>2</sub><sup>r6</sup>), D5 = r5 - r4 cP mod q and D6 = r6 - x cP mod q.</li>
|
|
<li>Compute R<sub>a</sub> = (Q<sub>a</sub> / Q<sub>b</sub>)
|
|
<sup>a<sub>3</sub></sup></li>
|
|
<li>Generate a zero-knowledge proof that R<sub>a</sub> was created
|
|
according to the protocol by setting cR = SHA256(7, g<sub>1</sub><sup>r7</sup>,
|
|
(Q<sub>a</sub> / Q<sub>b</sub>)<sup>r7</sup>) and
|
|
D7 = r7 - a<sub>3</sub> cR mod q.</li>
|
|
<li>Store the values of g<sub>3b</sub>, (P<sub>a</sub> / P<sub>b</sub>),
|
|
(Q<sub>a</sub> / Q<sub>b</sub>) and a<sub>3</sub> for use later in the
|
|
protocol.</li>
|
|
<li>Send Bob a type 4 TLV (SMP message 3) containing P<sub>a</sub>,
|
|
Q<sub>a</sub>, cP, D5, D6, R<sub>a</sub>, cR and D7 in that order.</li>
|
|
</ol>
|
|
Set smpstate to SMPSTATE_EXPECT4.</dd>
|
|
</dl>
|
|
<h4>Receiving a type 4 TLV (SMP message 3)</h4>
|
|
<p>SMP message 3 is Alice's final message in the SMP exchange. It
|
|
has the last of the information required by Bob to determine if x = y.
|
|
It contains the following mpi values:</p>
|
|
<dl>
|
|
<dt>P<sub>a</sub>, Q<sub>a</sub></dt>
|
|
<dd>These values are used in the final comparison to determine if Alice
|
|
and Bob share the same secret.</dd>
|
|
<dt>cP, D5, D6</dt>
|
|
<dd>A zero-knowledge proof that P<sub>a</sub> and Q<sub>a</sub> were
|
|
created according to the protcol given above.</dd>
|
|
<dt>R<sub>a</sub></dt>
|
|
<dd>This value is used in the final comparison to determine if Alice
|
|
and Bob share the same secret.</dd>
|
|
<dt>cR, D7</dt>
|
|
<dd>A zero-knowledge proof that R<sub>a</sub> was
|
|
created according to the protcol given above.</dd>
|
|
<dt>
|
|
</dl>
|
|
<p>When Bob receives this TLV he should do:</p>
|
|
<dl>
|
|
<dt>If smpstate is not SMPSTATE_EXPECT3:</dt>
|
|
<dd>Set smpstate to SMPSTATE_EXPECT1 and send a type 6 TLV (SMP abort)
|
|
to Bob.</dd>
|
|
<dt>If smpstate is SMPSTATE_EXPECT3:</dt>
|
|
<dd>Verify Alice's zero-knowledge proofs for P<sub>a</sub>, Q<sub>a</sub>
|
|
and R<sub>a</sub>:
|
|
<ol>
|
|
<li>Check that P<sub>a</sub>, Q<sub>a</sub> and R<sub>a</sub> are >= 2 and
|
|
<= modulus-2.</li>
|
|
<li>Check that cP = SHA256(6, g<sub>3</sub><sup>D5</sup>
|
|
P<sub>a</sub><sup>cP</sup>, g<sub>1</sub><sup>D5</sup> g<sub>2</sub><sup>D6</sup>
|
|
Q<sub>a</sub><sup>cP</sup>).</li>
|
|
<li>Check that cR = SHA256(7, g<sub>1</sub><sup>D7</sup>
|
|
g<sub>3a</sub><sup>cR</sup>, (Q<sub>a</sub> / Q<sub>b</sub>)<sup>D7</sup>
|
|
R<sub>a</sub><sup>cR</sup>).</li>
|
|
</ol>
|
|
Create a type 5 TLV (SMP message 4) and send it to Alice:
|
|
<ol>
|
|
<li>Pick a random exponent r7.
|
|
This will be used to generate Bob's final zero-knowledge proof that
|
|
this message was created honestly.</li>
|
|
<li>Compute R<sub>b</sub> = (Q<sub>a</sub> / Q<sub>b</sub>)
|
|
<sup>b<sub>3</sub></sup></li>
|
|
<li>Generate a zero-knowledge proof that R<sub>b</sub> was created
|
|
according to the protocol by setting cR = SHA256(8, g<sub>1</sub><sup>r7</sup>,
|
|
(Q<sub>a</sub> / Q<sub>b</sub>)<sup>r7</sup>) and
|
|
D7 = r7 - b<sub>3</sub> cR mod q.</li>
|
|
<li>Send Alice a type 5 TLV (SMP message 4) containing R<sub>b</sub>,
|
|
cR and D7 in that order.</li>
|
|
</ol>
|
|
Check whether the protocol was successful:
|
|
<ol>
|
|
<li>Compute R<sub>ab</sub> = R<sub>a</sub><sup>b<sub>3</sub></sup>.</li>
|
|
<li>Determine if x = y by checking the equivalent condition that
|
|
(P<sub>a</sub> / P<sub>b</sub>) = R<sub>ab</sub>.</li>
|
|
</ol>
|
|
Set smpstate to SMPSTATE_EXPECT1, as no more messages are expected from
|
|
Alice.</dd>
|
|
</dl>
|
|
<h4>Receiving a type 5 TLV (SMP message 4)</h4>
|
|
<p>SMP message 4 is Bob's final message in the SMP exchange. It
|
|
has the last of the information required by Alice to determine if x = y.
|
|
It contains the following mpi values:</p>
|
|
<dl>
|
|
<dt>R<sub>b</sub></dt>
|
|
<dd>This value is used in the final comparison to determine if Alice
|
|
and Bob share the same secret.</dd>
|
|
<dt>cR, D7</dt>
|
|
<dd>A zero-knowledge proof that R<sub>b</sub> was
|
|
created according to the protcol given above.</dd>
|
|
<dt>
|
|
</dl>
|
|
<p>When Alice receives this TLV she should do:</p>
|
|
<dl>
|
|
<dt>If smpstate is not SMPSTATE_EXPECT4:</dt>
|
|
<dd>Set smpstate to SMPSTATE_EXPECT1 and send a type 6 TLV (SMP abort)
|
|
to Bob.</dd>
|
|
<dt>If smpstate is SMPSTATE_EXPECT4:</dt>
|
|
<dd>Verify Bob's zero-knowledge proof for R<sub>b</sub>:
|
|
<ol>
|
|
<li>Check that R<sub>b</sub> is >= 2 and
|
|
<= modulus-2.</li>
|
|
<li>Check that cR = SHA256(8, g<sub>1</sub><sup>D7</sup>
|
|
g<sub>3b</sub><sup>cR</sup>, (Q<sub>a</sub> / Q<sub>b</sub>)<sup>D7</sup>
|
|
R<sub>b</sub><sup>cR</sup>).</li>
|
|
</ol>
|
|
Check whether the protocol was successful:
|
|
<ol>
|
|
<li>Compute R<sub>ab</sub> = R<sub>b</sub><sup>a<sub>3</sub></sup>.</li>
|
|
<li>Determine if x = y by checking the equivalent condition that
|
|
(P<sub>a</sub> / P<sub>b</sub>) = R<sub>ab</sub>.</li>
|
|
</ol>
|
|
Set smpstate to SMPSTATE_EXPECT1, as no more messages are expected from
|
|
Bob.</dd>
|
|
</dl>
|
|
<h4>User requests to begin SMP</h4>
|
|
<dl>
|
|
<dt>If smpstate is not set to SMPSTATE_EXPECT1:</dt>
|
|
<dd>SMP is already underway. If you wish to restart SMP, send a
|
|
type 6 TLV (SMP abort) to the other party and then proceed as if
|
|
smpstate was SMPSTATE_EXPECT1. Otherwise, you may simply continue the
|
|
current SMP instance.</dd>
|
|
<dt>If smpstate is set to SMPSTATE_EXPECT1:</dt>
|
|
<dd>No current exchange is underway. In this case, Alice should
|
|
create a valid type 2 TLV (SMP message 1) as follows:
|
|
<ol>
|
|
<li>Determine her secret input x, which is to be compared to Bob's
|
|
secret y.</li>
|
|
<li>Pick random values a<sub>2</sub> and a<sub>3</sub> (1536 bits).
|
|
These will be Alice's exponents for the DH exchange to pick generators.</li>
|
|
<li>Pick random values r2 and r3 (1536 bits).
|
|
These will be used to generate zero-knowledge proofs that this message
|
|
was created according to the protocol.</li>
|
|
<li>Compute g<sub>2a</sub> = g<sub>1</sub><sup>a<sub>2</sub></sup> and
|
|
g<sub>3a</sub> = g<sub>1</sub><sup>a<sub>3</sub></sup></li>
|
|
<li>Generate a zero-knowledge proof that the exponent a<sub>2</sub> is
|
|
known by setting c2 = SHA256(1, g<sub>1</sub><sup>r2</sup>) and
|
|
D2 = r2 - a<sub>2</sub> c2 mod q.</li>
|
|
<li>Generate a zero-knowledge proof that the exponent a<sub>3</sub> is
|
|
known by setting c3 = SHA256(2, g<sub>1</sub><sup>r3</sup>) and
|
|
D3 = r3 - a<sub>3</sub> c3 mod q.</li>
|
|
<li>Store the values of x, a<sub>2</sub> and a<sub>3</sub>
|
|
for use later in the protocol.</li>
|
|
<li>Send Bob a type 2 TLV (SMP message 1) containing g<sub>2a</sub>,
|
|
c2, D2, g<sub>3a</sub>, c3 and D3 in that order.</li>
|
|
</ol>
|
|
Set smpstate to SMPSTATE_EXPECT2.</dd>
|
|
</dl>
|
|
<h4>User requests to abort SMP</h4>
|
|
<p>In all cases, send a type 6 TLV (SMP abort) to the correspondent and
|
|
set smpstate to SMPSTATE_EXPECT1.</p>
|
|
<h3>Key Management</h3>
|
|
<p>For each correspondent, keep track of:</p>
|
|
<dl>
|
|
<dt>Your two most recent DH public/private key pairs</dt>
|
|
<dd>our_dh[our_keyid] (most recent) and our_dh[our_keyid-1] (previous)</dd>
|
|
<dt>His two most recent DH public keys</dt>
|
|
<dd>their_y[their_keyid] (most recent) and their_y[their_keyid-1]
|
|
(previous)</dd>
|
|
</dl>
|
|
|
|
<p>When starting a private conversation with a correspondent, generate
|
|
two DH key pairs for yourself, and set our_keyid = 2. Note that all DH
|
|
key pairs should have a private part that is at least 320 bits long.</p>
|
|
|
|
<dl class="doublespace">
|
|
<dt>When you send AKE messages:</dt>
|
|
<dd>Send the public part of our_dh[our_keyid-1], with the keyid field,
|
|
of course, set to (our_keyid-1).</dd>
|
|
|
|
<dt>Upon completing the AKE:</dt>
|
|
<dd>If the specified keyid equals either their_keyid or their_keyid-1,
|
|
and the DH pubkey contained in the AKE messages matches the
|
|
one you've stored for that keyid, that's great. Otherwise, forget
|
|
all values of their_y[], and of their_keyid, and set their_keyid to
|
|
the keyid value given in the AKE messages, and
|
|
their_y[their_keyid] to the DH pubkey value given in the AKE
|
|
messages. their_y[their_keyid-1] should be set to NULL.</dd>
|
|
|
|
<dt>When you send a Data Message:</dt>
|
|
<dd>Set the sender keyid to (our_keyid-1), and the recipient keyid to
|
|
(their_keyid). Set the DH pubkey in the Data message to the public
|
|
part of our_dh[our_keyid]. Use our_dh[our_keyid-1] and
|
|
their_y[their_keyid] to calculate session keys, as outlined below.
|
|
Use the "sending AES key" to encrypt the message, and the "sending
|
|
MAC key" to calculate its MAC.</dd>
|
|
|
|
<dt>When you receive a Data Message:</dt>
|
|
<dd>Use the keyids in the message to select which of your DH key pairs
|
|
and which of his DH pubkeys to use to verify the MAC. If the keyids
|
|
do not represent either the most recent key or the previous key (for
|
|
either the sender or receiver), reject the message. Also reject the
|
|
message if the sender keyid is their_keyid-1, but
|
|
their_y[their_keyid-1] is NULL.
|
|
|
|
<p>Otherwise, calculate the session keys as outlined below. Use the
|
|
"receiving MAC key" to verify the MAC on the message. If it does not
|
|
verify, reject the message.</p>
|
|
|
|
<p>Check that the counter in the Data message is strictly larger than the
|
|
last counter you saw using this pair of keys. If not, reject the
|
|
message.</p>
|
|
|
|
<p>If the MAC verifies, decrypt the message using the "receiving AES
|
|
key".</p>
|
|
|
|
<p>Finally, check if keys need rotation:</p>
|
|
<ul>
|
|
<li>If the "recipient keyid" in the Data message equals our_keyid, then
|
|
he's seen the public part of our most recent DH key pair, so you
|
|
must securely forget our_dh[our_keyid-1], increment our_keyid, and set
|
|
our_dh[our_keyid] to a new DH key pair which you generate.</li>
|
|
<li>If the "sender keyid" in the Data message equals their_keyid,
|
|
increment their_keyid, and set their_y[their_keyid] to the new DH
|
|
pubkey specified in the Data message.</li>
|
|
</ul></dd>
|
|
</dl>
|
|
|
|
<h4>Computing AES keys, MAC keys, and the secure session id</h4>
|
|
<p>OTR uses Diffie-Hellman to calculate shared secrets in the usual way:
|
|
if Bob knows x, and tells Alice g<sup>x</sup>, and Alice knows y, and
|
|
tells Bob g<sup>y</sup>, then they each can calculate s =
|
|
g<sup>xy</sup>: Alice calculates (g<sup>x</sup>)<sup>y</sup>, and Bob
|
|
calculates (g<sup>y</sup>)<sup>x</sup>.</p>
|
|
<p>During the AKE, Alice and Bob each calculate s in this way, and then
|
|
they each compute seven values based on s:</p>
|
|
<ul>
|
|
<li>A 64-bit secure session id, ssid</li>
|
|
<li>Two 128-bit AES encryption keys, c and c'</li>
|
|
<li>Four 256-bit SHA256-HMAC keys, m1, m2, m1', and m2'</li>
|
|
</ul>
|
|
<p>This is done in the following way:</p>
|
|
<ul>
|
|
<li>Write the value of s as a minimum-length MPI, as specified above
|
|
(4-byte big-endian len, len-byte big-endian value). Let this
|
|
(4+len)-byte value be "secbytes".</li>
|
|
<li>For a given byte b, define h2(b) to be the 256-bit output of the
|
|
SHA256 hash of the (5+len) bytes consisting of the byte b followed by
|
|
secbytes.</li>
|
|
<li>Let ssid be the first 64 bits of h2(0x00).</li>
|
|
<li>Let c be the first 128 bits of h2(0x01), and let c' be the second
|
|
128 bits of h2(0x01).</li>
|
|
<li>Let m1 be h2(0x02).</li>
|
|
<li>Let m2 be h2(0x03).</li>
|
|
<li>Let m1' be h2(0x04).</li>
|
|
<li>Let m2' be h2(0x05).</li>
|
|
</ul>
|
|
<p>c, m1, and m2 are used to create and verify the Reveal Signature
|
|
Message; c', m1', and m2' are used to create and verify the Signature
|
|
message.</p>
|
|
<p>If the user requests to see the secure session id, it should be
|
|
displayed as two 32-bit bigendian unsigned values, in C "%08x" format.
|
|
If the user transmitted the Reveal Signature message during the AKE that
|
|
produced this ssid, then display the first 32 bits in bold, and the
|
|
second 32 bits in non-bold. If the user transmitted the Signature
|
|
message instead, display the first 32 bits in non-bold, and the
|
|
second 32 bits in bold. This session id can be used by the parties to
|
|
verify (say, over the telephone, assuming the parties recognize each
|
|
others' voices) that there is no man-in-the-middle by having each side
|
|
read his bold part to the other. [Note that this only needs to be done
|
|
in the event that the users do not trust that their long-term signature
|
|
keys have not been compromised.]</p>
|
|
<p>During the exchange of Data Messages, Alice and Bob use the keyids
|
|
listed in the Data Message to select Diffie-Hellman keys to use to
|
|
compute s, and the (4+len)-byte value of secbytes, as above.</p>
|
|
<p>From this, they calculate four values:</p>
|
|
<ul>
|
|
<li>Two 128-bit AES encryption keys, the "sending AES key", and the
|
|
"receiving AES key"</li>
|
|
<li>Two 160-bit SHA1-HMAC keys, the "sending MAC key", and the
|
|
"receiving MAC key"</li>
|
|
</ul>
|
|
<p>These keys are calculated as follows:</p>
|
|
<ul>
|
|
<li>Alice (and similarly for Bob) determines if she is the "low" end
|
|
or the "high" end of this Data Message. If Alice's public key is
|
|
numerically greater than Bob's public key, then she
|
|
is the "high" end. Otherwise, she is the "low" end. Note that who is the
|
|
"low" end and who is the "high" end can change every time a new D-H
|
|
public key is exchanged in a Data Message.</li>
|
|
<li>She sets the values of "sendbyte" and "recvbyte" according to
|
|
whether she is the the "low" or the "high" end of the Data Message:
|
|
<ul>
|
|
<li>If she is the "high" end, she sets "sendbyte" to 0x01 and "recvbyte"
|
|
to 0x02.</li>
|
|
<li>If she is the "low" end, she sets "sendbyte" to 0x02 and "recvbyte"
|
|
to 0x01.</li>
|
|
</ul></li>
|
|
<li>For a given byte b, define h1(b) to be the 160-bit output of the
|
|
SHA-1 hash of the (5+len) bytes consisting of the byte b, followed by
|
|
secbytes.</li>
|
|
<li>The "sending AES key" is the first 16 bytes of h1(sendbyte).</li>
|
|
<li>The "sending MAC key" is the 20-byte SHA-1 hash of the 16-byte
|
|
sending AES key.</li>
|
|
<li>The "receiving AES key" is the first 16 bytes of h1(recvbyte).</li>
|
|
<li>The "receiving MAC key" is the 20-byte SHA-1 hash of the 16-byte
|
|
receiving AES key.</li>
|
|
</ul>
|
|
<h4>Extra symmetric key</h4>
|
|
<p>OTR version 3 defines an additional symmetric key that can be derived
|
|
by the communicating parties to use for application-specific purposes,
|
|
such as file transfer, voice encryption, etc. When one party wishes to
|
|
use the extra symmetric key, he or she creates a type 8 TLV attached to
|
|
a Data Message (see above). The key itself is then derived using the
|
|
same "secbytes" used to compute the encryption and MAC keys used to
|
|
protect the Data Message.
|
|
The extra symmetric key is derived by calculating
|
|
h2(0xFF) and keeping the entire 256 bits, using the same definition
|
|
of h2 as above.</p>
|
|
<p>Upon receipt of the Data Message containing the type 8 TLV, the
|
|
recipient will compute the extra symmetric key in the same way. Note
|
|
that the value of the extra symmetric key is <em>not</em> contained in
|
|
the TLV itself.</p>
|
|
<h4>Revealing MAC keys</h4>
|
|
<p>Whenever you are about to forget either one of your old D-H key pairs, or
|
|
one of your correspondent's old D-H public keys, take all of the
|
|
receiving MAC keys
|
|
that were generated by that key (note that there are up to two: the
|
|
receiving MAC keys produced by the pairings of that key with
|
|
each of two of the other side's keys; but note that you only need to
|
|
take MAC keys that were actually used to verify a MAC on a message), and
|
|
put them (as a set of
|
|
concatenated 20-byte values) into the "Old MAC keys to be revealed"
|
|
section of the next Data Message you send. This in done to allow the
|
|
forgeability of OTR transcripts: once the MAC keys are revealed, anyone
|
|
can modify an OTR message and still have it appear valid. But since we
|
|
don't reveal the MAC keys until their corresponding pubkeys are being
|
|
discarded, there is no danger of accepting a message as valid which
|
|
uses a MAC key which has already been revealed.</p>
|
|
<h3>Fragmentation</h3>
|
|
<p>Some networks may have a maximum message size that is too small to
|
|
contain an encoded OTR message. In that event, the sender may choose
|
|
to split the message into a number of <em>fragments</em>. This section
|
|
describes the format of the fragments. All OTR version 2 and 3 clients
|
|
must be able to assemble received fragments, but performing
|
|
fragmentation on outgoing messages is optional.</p>
|
|
|
|
<dl class="doublespace">
|
|
<dt>Transmitting Fragments</dt>
|
|
<dd>If you have information about the maximum size of message you are
|
|
able to send (the different IM networks have different limits), you
|
|
can fragment an encoded OTR message as follows:
|
|
<ul>
|
|
<li>Start with the OTR message as you would normally transmit it. For
|
|
example, a Data Message would start with "?OTR:AAED" and end
|
|
with ".".</li>
|
|
<li>Break it up into sufficiently small pieces. Let the number of
|
|
pieces be (n), and the pieces be
|
|
piece[1],piece[2],...,piece[n].</li>
|
|
<li>Transmit (n) OTR version 3 fragmented messages with the following
|
|
(printf-like) structure (as k runs from 1 to n inclusive):
|
|
|
|
<p>"?OTR|%x|%x,%hu,%hu,%s," , sender_instance, receiver_instance,
|
|
k , n , piece[k]</p>
|
|
|
|
OTR version 2 messages get fragmented in a similar format, but
|
|
without the instance tags fields:
|
|
|
|
<p>"?OTR,%hu,%hu,%s," ,
|
|
k , n , piece[k]</p></li>
|
|
|
|
<li>Note that k and n are unsigned short ints (2 bytes), and each has
|
|
a maximum value of 65535. Also, each piece[k] must be
|
|
non-empty. The instance tags (if applicable) and the k and n
|
|
values may have leading zeroes.</li>
|
|
</ul>
|
|
<p>Note that fragments are not themselves messages that can be
|
|
fragmented: you can't fragment a fragment.</p></dd>
|
|
|
|
<dt>Receiving Fragments:</dt>
|
|
|
|
<dd>If you receive a message containing "?OTR|" (note that you'll need
|
|
to check for this _before_ checking for any of the other "?OTR:"
|
|
markers):
|
|
|
|
<ul>
|
|
<li>Parse it as the printf statement above into k, n, and
|
|
piece.</li>
|
|
<li>If the recipient's own instance tag does not match the listed
|
|
receiver instance tag, and the listed receiver instance tag is not
|
|
zero, the recipient should discard the message and optionally pass
|
|
along a warning for the user.</li>
|
|
<li>Let (K,N) be your currently stored fragment number, and F be your
|
|
currently stored fragment. [If you have no currently stored
|
|
fragment, then K = N = 0 and F = "".]</li>
|
|
|
|
<li>If k == 0 or n == 0 or k > n, discard this (illegal)
|
|
fragment.</li>
|
|
|
|
<li>If k == 1:
|
|
<ul>
|
|
<li>Forget any stored fragment you may have</li>
|
|
<li>Store (piece) as F.</li>
|
|
<li>Store (k,n) as (K,N).</li>
|
|
</ul></li>
|
|
|
|
<li>If n == N and k == K+1:
|
|
<ul>
|
|
<li>Append (piece) to F.</li>
|
|
<li>Store (k,n) as (K,N).</li>
|
|
</ul></li>
|
|
|
|
<li>Otherwise:
|
|
<ul>
|
|
<li>Forget any stored fragment you may have</li>
|
|
<li>Store "" as F.</li>
|
|
<li>Store (0,0) as (K,N).</li>
|
|
</ul></li>
|
|
</ul>
|
|
|
|
<p>After this, if N > 0 and K == N, treat F as the received
|
|
message.</p>
|
|
|
|
<p>If you receive a non-OTR message, or an unfragmented message,
|
|
forget any stored fragment you may have, store "" as F and store
|
|
(0,0) as (K,N).</p>
|
|
|
|
<p>OTR version 2 fragmented messages follow the same behaviour as
|
|
described above, but do not list the sender and receiver instance
|
|
tags.</dd>
|
|
</dl>
|
|
|
|
<p>For example, here is a Data Message we would like to transmit over a
|
|
network with an unreasonably small maximum message size:</p>
|
|
|
|
<blockquote><pre>
|
|
?OTR:AAMDJ+MVmSfjFZcAAAAAAQAAAAIAAADA1g5IjD1ZGLDVQEyCgCyn9hb
|
|
rL3KAbGDdzE2ZkMyTKl7XfkSxh8YJnudstiB74i4BzT0W2haClg6dMary/jo
|
|
9sMudwmUdlnKpIGEKXWdvJKT+hQ26h9nzMgEditLB8vjPEWAJ6gBXvZrY6ZQ
|
|
rx3gb4v0UaSMOMiR5sB7Eaulb2Yc6RmRnnlxgUUC2alosg4WIeFN951PLjSc
|
|
ajVba6dqlDi+q1H5tPvI5SWMN7PCBWIJ41+WvF+5IAZzQZYgNaVLbAAAAAAA
|
|
AAAEAAAAHwNiIi5Ms+4PsY/L2ipkTtquknfx6HodLvk3RAAAAAA==.
|
|
</pre></blockquote>
|
|
|
|
<p>We could fragment this message into (for example) three
|
|
pieces:</p>
|
|
|
|
<blockquote><pre>
|
|
?OTR|5a73a599|27e31597,00001,00003,?OTR:AAMDJ+MVmSfjFZcAAAAA
|
|
AQAAAAIAAADA1g5IjD1ZGLDVQEyCgCyn9hbrL3KAbGDdzE2ZkMyTKl7XfkSx
|
|
h8YJnudstiB74i4BzT0W2haClg6dMary/jo9sMudwmUdlnKpIGEKXWdvJKT+
|
|
hQ26h9nzMgEditLB8v,
|
|
</pre></blockquote>
|
|
|
|
<blockquote><pre>
|
|
?OTR|5a73a599|27e31597,00002,00003,jPEWAJ6gBXvZrY6ZQrx3gb4v0
|
|
UaSMOMiR5sB7Eaulb2Yc6RmRnnlxgUUC2alosg4WIeFN951PLjScajVba6dq
|
|
lDi+q1H5tPvI5SWMN7PCBWIJ41+WvF+5IAZzQZYgNaVLbAAAAAAAAAAEAAAA
|
|
HwNiIi5Ms+4PsY/L2i,
|
|
</pre></blockquote>
|
|
|
|
<blockquote><pre>
|
|
?OTR|5a73a599|27e31597,00003,00003,pkTtquknfx6HodLvk3RAAAAAA
|
|
==.,
|
|
</pre></blockquote>
|
|
<h3>The protocol state machine</h3>
|
|
<p>An OTR client maintains separate state for every correspondent. For
|
|
example, Alice may have an active OTR conversation with Bob, while
|
|
having an unprotected conversation with Charlie. This state consists of
|
|
two main state variables, as well as some other information (such as
|
|
encryption keys). The two main state variables are:</p>
|
|
<h4>Message state</h4>
|
|
<p>The message state variable, msgstate, controls what happens to
|
|
outgoing messages typed by the user. It can take one of three
|
|
values:</p>
|
|
<dl>
|
|
<dt>MSGSTATE_PLAINTEXT</dt>
|
|
<dd>This state indicates that outgoing messages are sent without
|
|
encryption. This is the state that is used before an OTR conversation
|
|
is initiated. This is the initial state, and the only way to
|
|
subsequently enter this state is for the user to explicitly request to
|
|
do so via some UI operation.</dd>
|
|
<dt>MSGSTATE_ENCRYPTED</dt>
|
|
<dd>This state indicates that outgoing messages are sent encrypted.
|
|
This is the state that is used during an OTR conversation. The only way
|
|
to enter this state is for the authentication state machine (below) to
|
|
successfully complete.</dd>
|
|
<dt>MSGSTATE_FINISHED</dt>
|
|
<dd>This state indicates that outgoing messages are not delivered at
|
|
all. This state is entered only when the other party indicates he has
|
|
terminated his side of the OTR conversation. For example, if Alice and
|
|
Bob are having an OTR conversation, and Bob instructs his OTR client to
|
|
end its private session with Alice (for example, by logging out), Alice
|
|
will be notified of this, and <em>her</em> client will switch to
|
|
MSGSTATE_FINISHED mode. This prevents Alice from accidentally sending a
|
|
message to Bob in plaintext. (Consider what happens if Alice was in the
|
|
middle of typing a private message to Bob when he suddenly logs out,
|
|
just as Alice hits Enter.)</dd>
|
|
</dl>
|
|
<h4>Authentication state</h4>
|
|
<p>The authentication state variable, authstate, can take one of four
|
|
values (plus one extra for OTR version 1 compatibility):</p>
|
|
<dl>
|
|
<dt>AUTHSTATE_NONE</dt>
|
|
<dd>This state indicates that the authentication protocol is not
|
|
currently in progress. This is the initial state.</dd>
|
|
<dt>AUTHSTATE_AWAITING_DHKEY</dt>
|
|
<dd>After Bob initiates the authentication protocol by sending Alice
|
|
the D-H Commit Message, he enters this state to await Alice's reply.</dd>
|
|
<dt>AUTHSTATE_AWAITING_REVEALSIG</dt>
|
|
<dd>After Alice receives Bob's D-H Commit Message, and replies with her
|
|
own D-H Key Message, she enters this state to await Bob's reply.</dd>
|
|
<dt>AUTHSTATE_AWAITING_SIG</dt>
|
|
<dd>After Bob receives Alice's D-H Key Message, and replies with his own
|
|
Reveal Signature Message, he enters this state to await Alice's reply.</dd>
|
|
<dt>AUTHSTATE_V1_SETUP</dt>
|
|
<dd>For OTR version 1 compatibility, if Bob sends a version 1 Key
|
|
Exchange Message to Alice, he enters this state to await Alice's
|
|
reply.</dd>
|
|
</dl>
|
|
<p>After:</p>
|
|
<ul>
|
|
<li>Alice (in AUTHSTATE_AWAITING_REVEALSIG) receives Bob's Reveal
|
|
Signature Message (and replies with her own Signature Message), <b>or</b>
|
|
</li>
|
|
<li>Bob (in AUTHSTATE_AWAITING_SIG) receives Alice's Signature Message,
|
|
/li>
|
|
</ul>
|
|
<p>then,
|
|
assuming the signature verifications succeed, the msgstate
|
|
variable is transitioned to MSGSTATE_ENCRYPTED. Regardless of whether
|
|
the signature verifications succeed, the authstate variable is
|
|
transitioned to AUTHSTATE_NONE.</p>
|
|
<h4>Policies</h4>
|
|
<p>OTR clients can set different <b>policies</b> for different
|
|
correspondents. For example, Alice could set up her client so that it
|
|
speaks only OTR version 3, except with Charlie, who she knows has only
|
|
an old client; so that it will opportunistically start an OTR conversation
|
|
whenever it detects the correspondent supports it; or so that it refuses
|
|
to send non-encrypted messages to Bob, ever.</p>
|
|
<p>The policies that can be set (on a global or per-correspondent basis)
|
|
are any combination of the following boolean flags:</p>
|
|
<dl>
|
|
<dt>ALLOW_V1</dt>
|
|
<dd>Allow version 1 of the OTR protocol to be used (in general this
|
|
document will not address OTR protocol version 1; see previous
|
|
protocol documents for these details).</dd>
|
|
<dt>ALLOW_V2</dt>
|
|
<dd>Allow version 2 of the OTR protocol to be used.</dd>
|
|
<dt>ALLOW_V3</dt>
|
|
<dd>Allow version 3 of the OTR protocol to be used.</dd>
|
|
<dt>REQUIRE_ENCRYPTION</dt>
|
|
<dd>Refuse to send unencrypted messages.</dd>
|
|
<dt>SEND_WHITESPACE_TAG</dt>
|
|
<dd>Advertise your support of OTR using the whitespace tag.</dd>
|
|
<dt>WHITESPACE_START_AKE</dt>
|
|
<dd>Start the OTR AKE when you receive a whitespace tag.</dd>
|
|
<dt>ERROR_START_AKE</dt>
|
|
<dd>Start the OTR AKE when you receive an OTR Error Message.</dd>
|
|
</dl>
|
|
<p>Note that it is possible for UIs simply to offer the old
|
|
"combinations" of options, and not ask about each one separately.</p>
|
|
<h4>State transitions</h4>
|
|
<p>There are twelve actions an OTR client must handle:</p>
|
|
<ul>
|
|
<li>Received messages:
|
|
<ul>
|
|
<li>Plaintext without the whitespace tag</li>
|
|
<li>Plaintext with the whitespace tag</li>
|
|
<li>Query Message</li>
|
|
<li>Error Message</li>
|
|
<li>D-H Commit Message</li>
|
|
<li>D-H Key Message</li>
|
|
<li>Reveal Signature Message</li>
|
|
<li>Signature Message</li>
|
|
<li>Data Message</li>
|
|
</ul></li>
|
|
<li>User actions:
|
|
<ul>
|
|
<li>User requests to start an OTR conversation</li>
|
|
<li>User requests to end an OTR conversation</li>
|
|
<li>User types a message to be sent</li>
|
|
</ul></li>
|
|
</ul>
|
|
<p>The following sections will outline what actions to take in each
|
|
case. They all assume that at least one of ALLOW_V1, ALLOW_V2 or
|
|
ALLOW_V3 is set; if not, then OTR is completely disabled, and no
|
|
special handling of messages should be done at all. For version 1
|
|
messages, please refer to previous OTR protocol documents. For version
|
|
3 messages, someone receiving a message with a recipient instance tag
|
|
specified that does not equal their own should discard the message
|
|
and optionally warn the user. The exception here is the D-H Commit
|
|
Message where the recipient instance tag may be 0, indicating that no
|
|
particular instance is specified.</p>
|
|
<h4>Receiving plaintext without the whitespace tag</h4>
|
|
<dl>
|
|
<dt>If msgstate is MSGSTATE_PLAINTEXT:</dt>
|
|
<dd>Simply display the message to the user. If REQUIRE_ENCRYPTION is
|
|
set, warn him that the message was received unencrypted.</dd>
|
|
<dt>If msgstate is MSGSTATE_ENCRYPTED or MSGSTATE_FINISHED:</dt>
|
|
<dd>Display the message to the user, but warn him that the message was
|
|
received unencrypted.</dd>
|
|
</dl>
|
|
<h4>Receiving plaintext with the whitespace tag</h4>
|
|
<dl>
|
|
<dt>If msgstate is MSGSTATE_PLAINTEXT:</dt>
|
|
<dd>Remove the whitespace tag and display the message to the user. If
|
|
REQUIRE_ENCRYPTION is set, warn him that the message was received
|
|
unencrypted.</dd>
|
|
<dt>If msgstate is MSGSTATE_ENCRYPTED or MSGSTATE_FINISHED:</dt>
|
|
<dd>Remove the whitespace tag and display the message to the user, but
|
|
warn him that the message was received unencrypted.</dd>
|
|
</dl>
|
|
<p>In any event, if WHITESPACE_START_AKE is set:</p>
|
|
<dl>
|
|
<dt>If the tag offers OTR version 3 and ALLOW_V3 is set:</dt>
|
|
<dd>Send a version 3 D-H Commit Message, and transition authstate to
|
|
AUTHSTATE_AWAITING_DHKEY.</dd>
|
|
<dt>Otherwise, if the tag offers OTR version 2 and ALLOW_V2 is set:</dt>
|
|
<dd>Send a version 2 D-H Commit Message, and transition authstate to
|
|
AUTHSTATE_AWAITING_DHKEY.</dd>
|
|
</dl>
|
|
<h4>Receiving a Query Message</h4>
|
|
<dl>
|
|
<dt>If the query message offers OTR version 3 and ALLOW_V3 is set:</dt>
|
|
<dd>Send a version 3 D-H Commit Message, and transition authstate to
|
|
AUTHSTATE_AWAITING_DHKEY.</dd>
|
|
<dt>Otherwise, if the message offers OTR version 2 and ALLOW_V2 is set:</dt>
|
|
<dd>Send a version 2 D-H Commit Message, and transition authstate to
|
|
AUTHSTATE_AWAITING_DHKEY.</dd>
|
|
</dl>
|
|
<h4>Receiving an Error Message</h4>
|
|
<p>Display the message to the user. If ERROR_START_AKE is set, reply
|
|
with a Query Message.</p>
|
|
<h4>User requests to start an OTR conversation</h4>
|
|
<p>Send an OTR Query Message to the correspondent.</p>
|
|
<h4>Receiving a D-H Commit Message</h4>
|
|
<p>If the message is version 2 and ALLOW_V2 is not set, ignore this message.
|
|
Similarly if the message is version 3 and ALLOW_V3 is not set, ignore the
|
|
message. Otherwise:</p>
|
|
<dl>
|
|
<dt>If authstate is AUTHSTATE_NONE:</dt>
|
|
<dd>Reply with a D-H Key Message, and transition authstate to
|
|
AUTHSTATE_AWAITING_REVEALSIG.</dd>
|
|
<dt>If authstate is AUTHSTATE_AWAITING_DHKEY:</dt>
|
|
<dd>This is the trickiest transition in the whole protocol. It
|
|
indicates that you have already sent a D-H Commit message to your
|
|
correspondent, but that he either didn't receive it, or just didn't
|
|
receive it <em>yet</em>, and has sent you one as well. The symmetry
|
|
will be broken by comparing the hashed g<sup>x</sup> you sent in your
|
|
D-H Commit Message with the one you received, considered as 32-byte
|
|
unsigned big-endian values.
|
|
<dl>
|
|
<dt>If yours is the higher hash value:</dt>
|
|
<dd>Ignore the incoming D-H Commit message, but resend your D-H
|
|
Commit message.</dd>
|
|
<dt>Otherwise:</dt>
|
|
<dd>Forget your old g<sup>x</sup> value that you sent (encrypted)
|
|
earlier, and pretend you're in AUTHSTATE_NONE; i.e. reply with a D-H Key
|
|
Message, and transition authstate to AUTHSTATE_AWAITING_REVEALSIG.</dd>
|
|
</dl></dd>
|
|
<dt>If authstate is AUTHSTATE_AWAITING_REVEALSIG:</dt>
|
|
<dd>Retransmit your D-H Key Message (the same
|
|
one as you sent when you entered AUTHSTATE_AWAITING_REVEALSIG). Forget
|
|
the old D-H Commit message, and use this new one instead. There
|
|
are a number of reasons this might happen, including:
|
|
<ul>
|
|
<li>Your correspondent simply started a new AKE.</li>
|
|
<li>Your correspondent resent his D-H Commit message, as specified
|
|
above.</li>
|
|
<li>On some networks, like AIM, if your correspondent is logged in
|
|
multiple times, each of his clients will send a D-H Commit Message in
|
|
response to a Query Message; resending the same D-H Key Message in
|
|
response to each of those messages will prevent compounded confusion,
|
|
since each of his clients will see each of the D-H Key Messages you
|
|
send. [And the problem gets even worse if you are <em>each</em> logged
|
|
in multiple times.]</li>
|
|
</ul></dd>
|
|
<dt>If authstate is AUTHSTATE_AWAITING_SIG or AUTHSTATE_V1_SETUP:</dt>
|
|
<dd>Reply with a new D-H Key message, and transition authstate to
|
|
AUTHSTATE_AWAITING_REVEALSIG.</dd>
|
|
</dl>
|
|
<h4>Receiving a D-H Key Message</h4>
|
|
<p>If the message is version 2 and ALLOW_V2 is not set, ignore this
|
|
message. Similarly if the message is version 3 and ALLOW_V3 is not
|
|
set, ignore this message. Otherwise:</p>
|
|
<dl>
|
|
<dt>If authstate is AUTHSTATE_AWAITING_DHKEY:</dt>
|
|
<dd>Reply with a Reveal Signature Message and transition authstate to
|
|
AUTHSTATE_AWAITING_SIG.</dd>
|
|
<dt>If authstate is AUTHSTATE_AWAITING_SIG:</dt>
|
|
<dd>
|
|
<dl>
|
|
<dt>If this D-H Key message is the same the one you received earlier
|
|
(when you entered AUTHSTATE_AWAITING_SIG):</dt>
|
|
<dd>Retransmit your Reveal Signature Message.</dd>
|
|
<dt>Otherwise:</dt>
|
|
<dd>Ignore the message.</dd>
|
|
</dl></dd>
|
|
<dt>If authstate is AUTHSTATE_NONE, AUTHSTATE_AWAITING_REVEALSIG, or
|
|
AUTHSTATE_V1_SETUP:</dt>
|
|
<dd>Ignore the message.</dd>
|
|
</dl>
|
|
<h4>Receiving a Reveal Signature Message</h4>
|
|
<p>If the message is version 2 and ALLOW_V2 is not set, ignore this message.
|
|
Similarly if the message is version 3 and ALLOW_V3 is not set, ignore the
|
|
message. Otherwise:</p>
|
|
<dl>
|
|
<dt>If authstate is AUTHSTATE_AWAITING_REVEALSIG:</dt>
|
|
<dd>Use the received value of r to decrypt the value of g<sup>x</sup>
|
|
received in the D-H Commit Message, and verify the hash therein.
|
|
Decrypt the encrypted signature, and verify the signature and the MACs.
|
|
If everything checks out:
|
|
<ul>
|
|
<li>Reply with a Signature Message.</li>
|
|
<li>Transition authstate to AUTHSTATE_NONE.</li>
|
|
<li>Transition msgstate to MSGSTATE_ENCRYPTED.</li>
|
|
<li>If there is a recent stored message, encrypt it and send it as a
|
|
Data Message.</li>
|
|
</ul>
|
|
Otherwise, ignore the message.</dd>
|
|
<dt>If authstate is AUTHSTATE_NONE, AUTHSTATE_AWAITING_DHKEY,
|
|
AUTHSTATE_AWAITING_SIG, or AUTHSTATE_V1_SETUP:</dt>
|
|
<dd>Ignore the message.</dd>
|
|
</dl>
|
|
<h4>Receiving a Signature Message</h4>
|
|
<p>If the message is version 2 and ALLOW_V2 is not set, ignore this message.
|
|
Similarly if the message is version 3 and ALLOW_V3 is not set, ignore the
|
|
message. Otherwise:</p>
|
|
<dl>
|
|
<dt>If authstate is AUTHSTATE_AWAITING_SIG:</dt>
|
|
<dd>Decrypt the encrypted signature, and verify the signature and the MACs.
|
|
If everything checks out:
|
|
<ul>
|
|
<li>Transition authstate to AUTHSTATE_NONE.</li>
|
|
<li>Transition msgstate to MSGSTATE_ENCRYPTED.</li>
|
|
<li>If there is a recent stored message, encrypt it and send it as a
|
|
Data Message.</li>
|
|
</ul>
|
|
Otherwise, ignore the message.</dd>
|
|
<dt>If authstate is AUTHSTATE_NONE, AUTHSTATE_AWAITING_DHKEY,
|
|
or AUTHSTATE_AWAITING_REVEALSIG:</dt>
|
|
<dd>Ignore the message.</dd>
|
|
</dl>
|
|
<h4>User types a message to be sent</h4>
|
|
<dl>
|
|
<dt>If msgstate is MSGSTATE_PLAINTEXT:</dt>
|
|
<dd><dl><dt>If REQUIRE_ENCRYPTION is set:</dt>
|
|
<dd>Store the plaintext message for possible retransmission, and send a
|
|
Query Message.</dd>
|
|
<dt>Otherwise:</dt>
|
|
<dd>If SEND_WHITESPACE_TAG is set, and you have not received a plaintext
|
|
message from this correspondent since last entering MSGSTATE_PLAINTEXT,
|
|
attach the whitespace tag to the message. Send the (possibly modified)
|
|
message as plaintext.</dd></dl></dd>
|
|
<dt>If msgstate is MSGSTATE_ENCRYPTED:</dt>
|
|
<dd>Encrypt the message, and send it as a Data Message. Store the
|
|
plaintext message for possible retransmission.</dd>
|
|
<dt>If msgstate is MSGSTATE_FINISHED:</dt>
|
|
<dd>Inform the user that the message cannot be sent at this time. Store
|
|
the plaintext message for possible retransmission.</dd>
|
|
</dl>
|
|
<h4>Receiving a Data Message</h4>
|
|
<dl>
|
|
<dt>If msgstate is MSGSTATE_ENCRYPTED:</dt>
|
|
<dd>Verify the information (MAC, keyids, ctr value, etc.) in the
|
|
message.
|
|
<dl>
|
|
<dt>If the verification succeeds:</dt>
|
|
<dd>
|
|
<ul>
|
|
<li>Decrypt the message and display the human-readable part (if
|
|
non-empty) to the user.</li>
|
|
<li>Update the D-H encryption keys, if necessary.</li>
|
|
<li>If you have not sent a message to this correspondent in some
|
|
(configurable) time, send a "heartbeat" message, consisting of a Data
|
|
Message encoding an empty plaintext. The heartbeat message should have
|
|
the IGNORE_UNREADABLE flag set.</li>
|
|
<li>If the received message contains a TLV type 1, forget all encryption
|
|
keys for this correspondent, and transition msgstate to
|
|
MSGSTATE_FINISHED.</li>
|
|
</ul>
|
|
</dd>
|
|
<dt>Otherwise, inform the user that an unreadable encrypted message was
|
|
received, and reply with an Error Message.</dt>
|
|
</dl></dd>
|
|
<dt>If msgstate is MSGSTATE_PLAINTEXT or MSGSTATE_FINISHED:</dt>
|
|
<dd>Inform the user that an unreadable encrypted message was received,
|
|
and reply with an Error Message.</dd>
|
|
</dl>
|
|
<h4>User requests to end an OTR conversation</h4>
|
|
<dl>
|
|
<dt>If msgstate is MSGSTATE_PLAINTEXT:</dt>
|
|
<dd>Do nothing.</dd>
|
|
<dt>If msgstate is MSGSTATE_ENCRYPTED:</dt>
|
|
<dd>Send a Data Message, encoding a message with an empty human-readable
|
|
part, and TLV type 1. Transition msgstate to MSGSTATE_PLAINTEXT.</dd>
|
|
<dt>If msgstate is MSGSTATE_FINISHED:</dt>
|
|
<dd>Transition msgstate to MSGSTATE_PLAINTEXT.</dd>
|
|
</dl>
|
|
</body></html>
|