[Pkg-privacy-commits] [libotr] 35/225: Merged Version_3_Dev branch
Ximin Luo
infinity0 at moszumanska.debian.org
Sat Aug 22 12:44:49 UTC 2015
This is an automated email from the git hooks/post-receive script.
infinity0 pushed a commit to branch master
in repository libotr.
commit 026379304f1a6d20405a19bfea177d181e681c0f
Author: cypherpunk <cypherpunk>
Date: Tue Jul 24 19:18:06 2007 +0000
Merged Version_3_Dev branch
---
AUTHORS | 2 +-
ChangeLog | 40 +++
NEWS | 5 +
README | 12 +-
UPGRADING | 309 +++++++++++++++++
configure.ac | 4 +-
libotr.m4 | 2 +-
src/Makefile.am | 4 +-
src/auth.c | 2 +-
src/auth.h | 2 +-
src/b64.c | 11 +-
src/b64.h | 4 +-
src/context.c | 12 +-
src/context.h | 6 +-
src/dh.c | 2 +-
src/dh.h | 2 +-
src/mem.c | 2 +-
src/mem.h | 2 +-
src/message.c | 302 ++++++++++++++++-
src/message.h | 37 +-
src/privkey-t.h | 2 +-
src/privkey.c | 21 +-
src/privkey.h | 8 +-
src/proto.c | 105 +++++-
src/proto.h | 12 +-
src/serial.h | 2 +-
src/sm.c | 884 ++++++++++++++++++++++++++++++++++++++++++++++++
src/sm.h | 74 ++++
src/tlv.c | 2 +-
src/tlv.h | 8 +-
src/userstate.c | 2 +-
src/userstate.h | 2 +-
src/version.h | 6 +-
toolkit/ctrmode.c | 4 +-
toolkit/ctrmode.h | 4 +-
toolkit/otr_mackey.c | 2 +-
toolkit/otr_modify.c | 6 +-
toolkit/otr_parse.c | 2 +-
toolkit/otr_readforge.c | 5 +-
toolkit/otr_remac.c | 2 +-
toolkit/otr_sesskeys.c | 2 +-
toolkit/parse.c | 4 +-
toolkit/parse.h | 2 +-
toolkit/readotr.c | 2 +-
toolkit/readotr.h | 2 +-
toolkit/sesskeys.c | 2 +-
toolkit/sesskeys.h | 2 +-
toolkit/sha1hmac.c | 2 +-
toolkit/sha1hmac.h | 2 +-
49 files changed, 1850 insertions(+), 85 deletions(-)
diff --git a/AUTHORS b/AUTHORS
index 6cf447a..50a839d 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -2,6 +2,6 @@ Off-the-Record Messaging Library and Toolkit
Authors:
- Nikita Borisov and Ian Goldberg <otr at cypherpunks.ca>
+ Ian Goldberg, Chris Alexander, Nikita Borisov <otr at cypherpunks.ca>
See the README file for mailing list information
diff --git a/ChangeLog b/ChangeLog
index ddf6af7..e0f1190 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,43 @@
+2007-07-24:
+
+ * src/proto.h:
+ * src/proto.c:
+ * src/message.c: Implemented fragmentation of large messages
+
+ * src/message.h: New callback for fragmentation
+
+ * src/privkey.h:
+ * src/privkey.c (otrl_privkey_fingerprint_raw): New function to
+ return a raw hash of an account's public key
+
+ * src/proto.c: Keep track of the API version number passed to
+ otrl_init()
+
+ * src/context.h:
+ * src/context.c:
+ * src/tlv.h:
+ * src/sm.h:
+ * src/sm.c: Implemented the Socialist Millionaires' Protocol for
+ authenticating buddies without using user-visible fingerprints
+
+ * src/b64.h:
+ * src/b64.c (decode, otrl_base64_decode): Corrected char vs.
+ unsigned char
+
+ * README:
+ * configure.ac:
+ * src/version.h: Change version number to 3.1.0
+
+ * Most files: Update copyright information
+
+2007-07-23
+
+ * src/message.h:
+ * src/message.c: Added account_name and account_name_free callbacks
+ to OtrlMessageAppOps to let the application choose how to
+ display the account name in OTR Error Messages. Based on a
+ patch from Evan Schoenberg <evan.s at dreskin.net>.
+
2006-07-24
* src/privkey.h:
diff --git a/NEWS b/NEWS
index d2df6be..c92d939 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,8 @@
+24 Jul 2007:
+- Added fragmentation support for large messages
+- Added new method for buddy authentication which does not require the
+ (explicit) use of fingerprints.
+
02 Nov 2005:
- Released 3.0.0
diff --git a/README b/README
index 19a3034..f974d43 100644
--- a/README
+++ b/README
@@ -1,5 +1,5 @@
Off-the-Record Messaging Library and Toolkit
- v3.0.0, 2 Nov 2005
+ v3.1.0, XX XXX 2007
This is a library and toolkit which implements Off-the-Record (OTR) Messaging.
@@ -19,7 +19,7 @@ OTR allows you to have private conversations over IM by providing:
is compromised.
For more information on Off-the-Record Messaging, see
-http://www.cypherpunks.ca/otr/
+http://otr.cypherpunks.ca/
LIBRARY USAGE
@@ -239,7 +239,7 @@ The Off-the-Record Messaging library (in the src directory) is
covered by the following (LGPL) license:
Off-the-Record Messaging library
- Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
<otr at cypherpunks.ca>
This library is free software; you can redistribute it and/or
@@ -260,7 +260,7 @@ The Off-the-Record Messaging Toolkit (in the toolkit directory) is covered
by the following (GPL) license:
Off-the-Record Messaging Toolkit
- Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
<otr at cypherpunks.ca>
This program is free software; you can redistribute it and/or modify
@@ -282,7 +282,7 @@ CONTACT
To report problems, comments, suggestions, patches, etc., you can email
the authors:
-Nikita Borisov and Ian Goldberg <otr at cypherpunks.ca>
+Ian Goldberg, Chris Alexander, and Nikita Borisov <otr at cypherpunks.ca>
For more information on Off-the-Record Messaging, visit
-http://www.cypherpunks.ca/otr/
+http://otr.cypherpunks.ca/
diff --git a/UPGRADING b/UPGRADING
new file mode 100644
index 0000000..95c9dc9
--- /dev/null
+++ b/UPGRADING
@@ -0,0 +1,309 @@
+Table of Contents
+
+1. Preface/Introduction?
+2. Major Additions
+2.1. Fragmentation
+2.2. Socialist Millionaires' Protocol
+3. Required Changes
+3.1. OtrlMessageAppOps Callbacks
+3.1.1. Max Message Size
+3.1.2. Account Name
+3.2. Using Fragmentation
+3.3. Using SMP
+3.3.1. Initiating
+3.3.2. Responding
+3.3.3. Aborting
+3.3.4. Control Flow and Errors
+3.4. Miscellaneous
+
+1. Preface/Introduction?
+
+2. Major Additions
+
+This section describes the new features in OTR 3.1.0 along with a short
+history or motivation for each.
+
+2.1. Fragmentation
+
+Most IM networks supported by Pidgin have fixed maximum message sizes
+(MMS) of approximately 1-3 kB. The longer messages in the initial key
+exchange and the new socialist millionaires' protocol may exceed these
+common MMS values. To allow these protocols to work properly even over
+networks with low MMS values, support for fragmentation was added.
+
+OTR version 3.0.0 added support for recombining message fragments to
+recover the original message. Now that users may be assumed to be able to
+handle message fragments, support for fragmenting and sending large
+messages has been added to OTR 3.1.0.
+
+2.2. Socialist Millionaires' Protocol
+
+In version 3.0.0, the only method available to authenticate a buddy was
+fingerprint verification. However, many users who are unfamiliar with
+cryptography do not understand what a fingerprint is or how it is useful.
+Also, the verification itself relied on the user obtaining an authentic
+copy of the other party's fingerprint somehow. The simplest way to do so
+may be to relay the displayed hexadecimal values during a phone call,
+but this is a large enough hassle that many users omit fingerprint
+verification altogether.
+
+To allow for a method of authentication that is both easier to understand
+and easier to use, OTR version 3.1.0 includes the Socialist Millionaires'
+Protocol (SMP). SMP runs as follows: each user inputs a secret string,
+say "x" and "y". They then exchange a series of messages which reveal
+the value of (x==y), but no additional information about the inputs.
+This allows users to determine whether they hold the same secret
+information with no danger of revealing that secret to an attacker.
+
+To see how this is useful for authentication in OTR, assume that Alice
+and Bob are chatting over OTR for the first time, though they know each
+other well in real life. Alice may send Bob the following message:
+"Let's make our shared secret the name of that restaurant we both like
+in Ottawa."
+
+Now Alice and Bob run SMP. If Alice is actually talking to Bob directly,
+then they will both type in the same restaurant name and SMP will return
+success (x==y). However, if an attacker is impersonating Bob or trying
+to eavesdrop on the conversation, they will have no idea which restaurant
+Alice has in mind, and will type in an incorrect value, causing SMP to
+fail. Note that for security reasons, the values compared in the SMP
+are actually hashes of several pieces of data, including both parties'
+fingerprints, along with their respective secrets. The users, however,
+are never exposed to this additional data.
+
+Thus, SMP turns the problem of obtaining an authentic copy of a
+fingerprint into the much simpler problem of obtaining any shared secret,
+or simply of drawing on shared experiences to generate one.
+
+For detailed information on how SMP works, see the paper by Boudot,
+Schoenmakers and Traore titled "A Fair and Efficient Solution to the
+Socialist Millionaires Problem" (2001), on which our solution is based.
+
+3. Required Changes
+
+3.1. OtrlMessageAppOps Callbacks
+
+Three new callbacks have been added to the end of OtrlMessageAppOps. If
+the version number passed to otrl_init is less than 3.1.0 then libotr will
+not call any of the new callbacks. As well, you may disable individual
+callbacks by setting them to NULL. In either case, libotr will revert to
+the standard behaviour of version 3.0.0.
+
+3.1.1. Max Message Size
+
+The first new callback has the following signature:
+
+ int (*max_message_size)(void *opdata, ConnContext *context);
+
+This method is called whenever a message is about to be sent with
+fragmentation enabled. The return value is checked against the size of
+the message to be sent to determine whether fragmentation is necessary.
+
+Although the maximum message size depends on a number of factors, we
+found experimentally that the following rough values based solely on the
+(pidgin) protocol name work well:
+ "prpl-msn", 1409
+ "prpl-icq", 2346
+ "prpl-aim", 2343
+ "prpl-yahoo", 832
+ "prpl-gg", 1999
+ "prpl-irc", 417
+ "prpl-oscar", 2343
+
+Setting max_message_size to NULL will disable the fragmentation of all
+sent messages; returning 0 from this callback will disable fragmentation
+of a particular message. The latter is useful, for example, for
+protocols like XMPP (Jabber) that do not require fragmentation at all.
+
+3.1.2. Account Name
+
+The other two new callbacks have the following signatures:
+
+ const char *(*account_name)(void *opdata, const char *account,
+ const char *protocol);
+ void (*account_name_free)(void *opdata, const char *account_name);
+
+Normally, if an error message needs to be sent from Alice to Bob,
+containing Alice's account name, the value of ConnContext->accountname
+will be used. However, if this default name is unsuitable for your
+application, you can use the above methods to provide replacement values
+for displayed account names.
+
+account_name is called when libotr requires a human-readable version of
+an account name. account_name_free is called once the name has
+been used, and the memory allocated by account_name (if any) must be
+released.
+
+Setting account_name to NULL will cause libotr to use
+ConnContext->accountname as the displayed name for an account.
+
+3.2. Using Fragmentation
+
+To make use of fragmentation, first make sure that the max_message_size
+callback described in 3.1.1. has been implemented. Then, whenever you
+would normally send a message through your IM client, call
+otrl_message_fragment_and_send instead:
+
+gcry_error_t otrl_message_fragment_and_send(const OtrlMessageAppOps *ops,
+ void *opdata, ConnContext *context, const char *message,
+ OtrlFragmentPolicy fragPolicy, char **returnFragment);
+
+Here, message is the original, encrypted, unfragmented message.
+This method will break the message into fragments and send either all of
+them or almost all of them according to the OtrlFragmentPolicy:
+
+OTRL_FRAGMENT_SEND_ALL sends all fragments at once
+OTRL_FRAGMENT_SEND_ALL_BUT_FIRST sends all but the first fragment
+OTRL_FRAGMENT_SEND_ALL_BUT_LAST sends all but the last fragment
+
+You may wish to use one of the latter two options if you still wish to
+pass a message through your IM client. In this case, the unsent
+fragment will be returned in returnFragment and should be sent as a
+regular message. In order to reassemble the fragments, however, they
+must be received in order, so at most one of the latter two options
+will result in readable messages.
+
+3.3. Using SMP
+
+Recall from section 2.2. above that SMP takes one input string from each
+user and outputs either failure or success.
+
+3.3.1. Initiating
+
+If you wish to initiate SMP for a user named Alice, you would use
+otrl_message_initiate_smp.
+
+void otrl_message_initiate_smp(OtrlUserState us, const OtrlMessageAppOps *ops,
+ void *opdata, ConnContext *context, const unsigned char *secret,
+ size_t secretlen);
+
+Here, secret and secretlen describe the secret text as entered by Alice,
+for example, ("kitten", 6). The other parameters are common to many
+otrl_message functions. This method will cause a message to be sent
+containing an appropriate OTRL_TLV_SMP1 (see below).
+
+3.3.2. Responding
+
+If you wish to continue SMP by supplying the secret for a second user
+named Bob, you would use otrl_message_respond_smp:
+
+void otrl_message_respond_smp(OtrlUserState us, const OtrlMessageAppOps *ops,
+ void *opdata, ConnContext *context, const unsigned char *secret,
+ size_t secretlen);
+
+The arguments for this method are the same as otrl_message_initiate_smp.
+This method will send a message with an appropriate OTRL_TLV_SMP2
+(see below).
+
+3.3.3. Aborting
+
+If you wish to abort SMP for any reason, including errors occuring
+during the protocol, you should use otrl_message_abort_smp:
+
+void otrl_message_abort_smp(OtrlUserState us, const OtrlMessageAppOps *ops,
+ void *opdata, ConnContext *context);
+
+This method will cause the other user to abandon the current state of
+SMP by sending an appropriate OTRL_TLV_SMP_ABORT (see below).
+
+3.3.4. Control Flow and Errors
+
+The protocol itself consists of 4 messages passed between the two users,
+say Alice and Bob. These messages are identified through their TLVs:
+
+OTRL_TLV_SMP1 The initial message, containing Alice's secret
+OTRL_TLV_SMP2 A response containing Bob's secret
+OTRL_TLV_SMP3 The next message in the chain, from Alice to Bob
+OTRL_TLV_SMP4 The final message in the chain, from Bob to Alice
+OTRL_TLV_SMP_ABORT Indicates an error has occurred. Will reset SMP state
+
+To determine whether the protocol is proceeding correctly, additional
+information has been added to ConnContext. You may access
+context->smstate->nextExpected to find out which TLV should come next,
+so you can compare this to what was actually received and take an
+appropriate action. The value is of type NextExpectedSMP and could be
+any of:
+
+OTRL_SMP_EXPECT1 Next SMP TLV should be OTRL_TLV_SMP1
+OTRL_SMP_EXPECT2 Next SMP TLV should be OTRL_TLV_SMP2
+OTRL_SMP_EXPECT3 Next SMP TLV should be OTRL_TLV_SMP3
+OTRL_SMP_EXPECT4 Next SMP TLV should be OTRL_TLV_SMP4
+
+If at any point, an SMP TLV of an unexpected type is received, the
+protocol should abort. Also, if the correct TLV type is received, then
+the state should be updated accordingly. A typical control flow looks
+like this:
+
+ OtrlTLV *tlvs = NULL;
+ OtrlTLV *tlv = NULL;
+ [Initialize tlvs to the list of tlvs. This can be done
+ as part of otrl_message_receiving.]
+
+ ConnContext *context = [correct context];
+ NextExpectedSMP nextMsg = context->smstate->nextExpected;
+
+ tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1);
+ if (tlv) {
+ if (nextMsg != OTRL_SMP_EXPECT1)
+ [abort SMP];
+ else {
+ [get secret from user and continue SMP];
+ }
+ }
+ tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP2);
+ if (tlv) {
+ if (nextMsg != OTRL_SMP_EXPECT2)
+ [abort SMP];
+ else {
+ // If we received TLV2, we will send TLV3 and expect TLV4
+ context->smstate->nextExpected = OTRL_SMP_EXPECT4;
+ }
+ }
+ tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP3);
+ if (tlv) {
+ if (nextMsg != OTRL_SMP_EXPECT3)
+ [abort SMP];
+ else {
+ // If we received TLV3, we will send TLV4
+ // We will not expect more messages, so prepare for next SMP
+ context->smstate->nextExpected = OTRL_SMP_EXPECT1;
+ // Report result to user
+ }
+ }
+ tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP4);
+ if (tlv) {
+ if (nextMsg != OTRL_SMP_EXPECT4)
+ [abort SMP];
+ else {
+ // We will not expect more messages, so prepare for next SMP
+ context->smstate->nextExpected = OTRL_SMP_EXPECT1;
+ // Report result to user
+ }
+ }
+ tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP_ABORT);
+ if (tlv) {
+ // The message we are waiting for will not arrive, so reset
+ // and prepare for the next SMP
+ context->smstate->nextExpected = OTRL_SMP_EXPECT1;
+ }
+
+To report the result to the user after receiving OTRL_TLV_SMP3 or
+OTRL_TLV_SMP4, check whether context->active_fingerprint->trust is a
+non-empty string. (That is, check that it's not NULL, and that its
+first character is not '\0'.) If that is the case, then the SMP
+completed successfully. Otherwise, the parties entered different secrets.
+
+3.4 Miscellaneous
+
+b64.h underwent a minor change in OTR 3.1.0. It was purely a
+housekeeping change and should not require any changes to dependent code.
+
+The arguments to otrl_base64_encode and otrl_base64_decode did not agree
+in terms of which were of type char* and which were unsigned char*
+instead. This has been corrected. The new method signatures are:
+
+size_t otrl_base64_encode(char *base64data, const unsigned char *data,
+ size_t datalen);
+size_t otrl_base64_decode(unsigned char *data, const char *base64data,
+ size_t base64len);
+
diff --git a/configure.ac b/configure.ac
index 97300a0..1d3b44c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -16,8 +16,8 @@ dnl For a backwards-incompatible API change (e.g. changing data structures):
dnl Change the libotr package version from a.b.c to (a+1).0.0
dnl Change the libotr libtool version from x:y:z to (x+1):0:0
-AM_INIT_AUTOMAKE(libotr, 3.0.0)
-LIBOTR_LIBTOOL_VERSION="2:0:0"
+AM_INIT_AUTOMAKE(libotr, 3.1.0)
+LIBOTR_LIBTOOL_VERSION="3:0:1"
AC_SUBST(LIBOTR_LIBTOOL_VERSION)
diff --git a/libotr.m4 b/libotr.m4
index ec6d998..a21ac3e 100644
--- a/libotr.m4
+++ b/libotr.m4
@@ -1,6 +1,6 @@
dnl
dnl Off-the-Record Messaging library
-dnl Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+dnl Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
dnl <otr at cypherpunks.ca>
dnl
dnl This library is free software; you can redistribute it and/or
diff --git a/src/Makefile.am b/src/Makefile.am
index 933aa11..c75fcbe 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -3,11 +3,11 @@ INCLUDES = @LIBGCRYPT_CFLAGS@
lib_LTLIBRARIES = libotr.la
libotr_la_SOURCES = privkey.c context.c proto.c b64.c dh.c mem.c message.c \
- userstate.c tlv.c auth.c
+ userstate.c tlv.c auth.c sm.c
libotr_la_LDFLAGS = -version-info @LIBOTR_LIBTOOL_VERSION@ @LIBS@ @LIBGCRYPT_LIBS@
otrincdir = $(includedir)/libotr
otrinc_HEADERS = b64.h context.h dh.h mem.h message.h privkey.h proto.h \
- version.h userstate.h tlv.h serial.h auth.h privkey-t.h
+ version.h userstate.h tlv.h serial.h auth.h sm.h privkey-t.h
diff --git a/src/auth.c b/src/auth.c
index 56f053d..f8916ca 100644
--- a/src/auth.c
+++ b/src/auth.c
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging library
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This library is free software; you can redistribute it and/or
diff --git a/src/auth.h b/src/auth.h
index 8fa936c..a42c7e2 100644
--- a/src/auth.h
+++ b/src/auth.h
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging library
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This library is free software; you can redistribute it and/or
diff --git a/src/b64.c b/src/b64.c
index a461c88..4964c57 100644
--- a/src/b64.c
+++ b/src/b64.c
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging library
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This library is free software; you can redistribute it and/or
@@ -64,7 +64,7 @@ VERSION HISTORY:
/*
** Translation Table as described in RFC1113
*/
-static const unsigned char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
/*
** Translation Table to decode (created by author)
@@ -118,8 +118,7 @@ size_t otrl_base64_encode(char *base64data, const unsigned char *data,
return base64len;
}
-static size_t decode(unsigned char *out, const unsigned char *in,
- size_t b64len)
+static size_t decode(unsigned char *out, const char *in, size_t b64len)
{
size_t written = 0;
unsigned char c = 0;
@@ -151,11 +150,11 @@ static size_t decode(unsigned char *out, const unsigned char *in,
* The buffer data must contain at least (base64len / 4) * 3 bytes of
* space. This function will return the number of bytes actually used.
*/
-size_t otrl_base64_decode(char *data, const unsigned char *base64data,
+size_t otrl_base64_decode(unsigned char *data, const char *base64data,
size_t base64len)
{
size_t datalen = 0;
- unsigned char b64[4];
+ char b64[4];
size_t b64accum = 0;
while(base64len > 0) {
diff --git a/src/b64.h b/src/b64.h
index 03d9b21..f7a1692 100644
--- a/src/b64.h
+++ b/src/b64.h
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging library
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This library is free software; you can redistribute it and/or
@@ -36,7 +36,7 @@ size_t otrl_base64_encode(char *base64data, const unsigned char *data,
* The buffer data must contain at least (base64len / 4) * 3 bytes of
* space. This function will return the number of bytes actually used.
*/
-size_t otrl_base64_decode(char *data, const unsigned char *base64data,
+size_t otrl_base64_decode(unsigned char *data, const char *base64data,
size_t base64len);
/*
diff --git a/src/context.c b/src/context.c
index 3205d3b..0b22f98 100644
--- a/src/context.c
+++ b/src/context.c
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging library
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This library is free software; you can redistribute it and/or
@@ -32,6 +32,7 @@ static ConnContext * new_context(const char * user, const char * accountname,
const char * protocol)
{
ConnContext * context;
+ OtrlSMState *smstate;
context = malloc(sizeof(*context));
assert(context != NULL);
context->username = strdup(user);
@@ -43,6 +44,12 @@ static ConnContext * new_context(const char * user, const char * accountname,
context->fragment_k = 0;
context->msgstate = OTRL_MSGSTATE_PLAINTEXT;
otrl_auth_new(&(context->auth));
+
+ smstate = malloc(sizeof(OtrlSMState));
+ assert(smstate != NULL);
+ otrl_sm_state_new(smstate);
+ context->smstate = smstate;
+
context->fingerprint_root.fingerprint = NULL;
context->fingerprint_root.context = context;
context->fingerprint_root.next = NULL;
@@ -221,6 +228,7 @@ void otrl_context_force_finished(ConnContext *context)
gcry_free(context->lastmessage);
context->lastmessage = NULL;
context->may_retransmit = 0;
+ otrl_sm_state_free(context->smstate);
}
/* Force a context into the OTRL_MSGSTATE_PLAINTEXT state. */
@@ -285,9 +293,11 @@ void otrl_context_forget(ConnContext *context)
free(context->username);
free(context->accountname);
free(context->protocol);
+ free(context->smstate);
context->username = NULL;
context->accountname = NULL;
context->protocol = NULL;
+ context->smstate = NULL;
/* Free the application data, if it exists */
if (context->app_data && context->app_data_free) {
diff --git a/src/context.h b/src/context.h
index 4aec29d..c680d33 100644
--- a/src/context.h
+++ b/src/context.h
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging library
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This library is free software; you can redistribute it and/or
@@ -24,6 +24,7 @@
#include "dh.h"
#include "auth.h"
+#include "sm.h"
typedef enum {
OTRL_MSGSTATE_PLAINTEXT, /* Not yet started an encrypted
@@ -124,6 +125,9 @@ typedef struct context {
void *app_data;
/* A function to free the above data when we forget this context */
void (*app_data_free)(void *);
+
+ OtrlSMState *smstate; /* The state of the current
+ socialist millionaires exchange */
} ConnContext;
#include "userstate.h"
diff --git a/src/dh.c b/src/dh.c
index 9c22601..9a4a055 100644
--- a/src/dh.c
+++ b/src/dh.c
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging library
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This library is free software; you can redistribute it and/or
diff --git a/src/dh.h b/src/dh.h
index f41b023..a35edbb 100644
--- a/src/dh.h
+++ b/src/dh.h
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging library
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This library is free software; you can redistribute it and/or
diff --git a/src/mem.c b/src/mem.c
index d525577..b9fc384 100644
--- a/src/mem.c
+++ b/src/mem.c
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging library
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This library is free software; you can redistribute it and/or
diff --git a/src/mem.h b/src/mem.h
index f26f5fe..caa2343 100644
--- a/src/mem.h
+++ b/src/mem.h
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging library
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This library is free software; you can redistribute it and/or
diff --git a/src/message.c b/src/message.c
index 26bea8f..1439439 100644
--- a/src/message.c
+++ b/src/message.c
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging library
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This library is free software; you can redistribute it and/or
@@ -30,6 +30,10 @@
#include "proto.h"
#include "auth.h"
#include "message.h"
+#include "sm.h"
+
+/* The API version */
+extern unsigned int otrl_api_version;
/* How long after sending a packet should we wait to send a heartbeat? */
#define HEARTBEAT_INTERVAL 60
@@ -221,7 +225,7 @@ gcry_error_t otrl_message_sending(OtrlUserState us,
protocol, recipient, "Your message was not sent. "
"Either end your private conversation, or restart "
"it.")) && ops->notify) {
- const char *fmt = "%s has already closed his private "
+ const char *fmt = "%s has already closed his/her private "
"connection to you";
char *primary = malloc(strlen(fmt) + strlen(recipient) - 1);
if (primary) {
@@ -251,10 +255,11 @@ static gcry_error_t send_or_error_auth(const OtrlMessageAppOps *ops,
if (!err) {
const char *msg = context->auth.lastauthmsg;
if (msg && *msg) {
- if (ops->inject_message) {
+ otrl_message_fragment_and_send(ops, opdata, context, msg, OTRL_FRAGMENT_SEND_ALL, NULL);
+ /*if (ops->inject_message) {
ops->inject_message(opdata, context->accountname,
context->protocol, context->username, msg);
- }
+ }*/
}
} else {
const char *buf_format = "Error setting up private conversation: %s";
@@ -456,11 +461,7 @@ static void maybe_resend(EncrData *edata)
char *buf;
/* Resend the message */
- if (edata->ops->inject_message) {
- edata->ops->inject_message(edata->opdata,
- edata->context->accountname, edata->context->protocol,
- edata->context->username, resendmsg);
- }
+ otrl_message_fragment_and_send(edata->ops, edata->opdata, edata->context, resendmsg, OTRL_FRAGMENT_SEND_ALL, NULL);
free(resendmsg);
edata->context->lastsent = now;
@@ -494,6 +495,127 @@ static void maybe_resend(EncrData *edata)
}
}
+/* Set the trust level based on the result of the SMP */
+static void set_smp_trust(const OtrlMessageAppOps *ops, void *opdata,
+ ConnContext *context, int trusted)
+{
+ otrl_context_set_trust(context->active_fingerprint, trusted ? "smp" : "");
+
+ /* Write the new info to disk, redraw the ui, and redraw the
+ * OTR buttons. */
+ if (ops->write_fingerprints) {
+ ops->write_fingerprints(opdata);
+ }
+}
+
+static void init_respond_smp(OtrlUserState us, const OtrlMessageAppOps *ops,
+ void *opdata, ConnContext *context, const unsigned char *secret,
+ size_t secretlen, int initiating)
+{
+ unsigned char *smpmsg = NULL;
+ int smpmsglen;
+ unsigned char combined_secret[SM_DIGEST_SIZE];
+ gcry_error_t err;
+ unsigned char our_fp[20];
+ unsigned char *combined_buf;
+ size_t combined_buf_len;
+
+ if (!context || context->msgstate != OTRL_MSGSTATE_ENCRYPTED) return;
+
+ /*
+ * Construct the combined secret as a SHA256 hash of:
+ * Version byte (0x01), Initiator fingerprint (20 bytes),
+ * responder fingerprint (20 bytes), secure session id, input secret
+ */
+ otrl_privkey_fingerprint_raw(us, our_fp, context->accountname,
+ context->protocol);
+
+ combined_buf_len = 41 + context->sessionid_len + secretlen;
+ combined_buf = malloc(combined_buf_len);
+ combined_buf[0] = 0x01;
+ if (initiating) {
+ memmove(combined_buf + 1, our_fp, 20);
+ memmove(combined_buf + 21,
+ context->active_fingerprint->fingerprint, 20);
+ } else {
+ memmove(combined_buf + 1,
+ context->active_fingerprint->fingerprint, 20);
+ memmove(combined_buf + 21, our_fp, 20);
+ }
+ memmove(combined_buf + 41, context->sessionid,
+ context->sessionid_len);
+ memmove(combined_buf + 41 + context->sessionid_len,
+ secret, secretlen);
+ gcry_md_hash_buffer(SM_HASH_ALGORITHM, combined_secret, combined_buf,
+ combined_buf_len);
+ free(combined_buf);
+
+ if (initiating) {
+ otrl_sm_step1(context->smstate, combined_secret, SM_DIGEST_SIZE,
+ &smpmsg, &smpmsglen);
+ } else {
+ otrl_sm_step2b(context->smstate, combined_secret, SM_DIGEST_SIZE,
+ &smpmsg, &smpmsglen);
+ }
+
+ /* Send msg with next smp msg content */
+ OtrlTLV *sendtlv = otrl_tlv_new(initiating ? OTRL_TLV_SMP1 : OTRL_TLV_SMP2,
+ smpmsglen, smpmsg);
+ char *sendsmp = NULL;
+ err = otrl_proto_create_data(&sendsmp, context, "", sendtlv,
+ OTRL_MSGFLAGS_IGNORE_UNREADABLE);
+ if (!err) {
+ /* Send it, and set the next expected message to the
+ * logical response */
+ err = otrl_message_fragment_and_send(ops, opdata, context,
+ sendsmp, OTRL_FRAGMENT_SEND_ALL, NULL);
+ context->smstate->nextExpected =
+ initiating ? OTRL_SMP_EXPECT2 : OTRL_SMP_EXPECT3;
+ }
+ free(sendsmp);
+ otrl_tlv_free(sendtlv);
+ free(smpmsg);
+}
+
+/* Initiate the Socialist Millionaires' Protocol */
+void otrl_message_initiate_smp(OtrlUserState us, const OtrlMessageAppOps *ops,
+ void *opdata, ConnContext *context, const unsigned char *secret,
+ size_t secretlen)
+{
+ init_respond_smp(us, ops, opdata, context, secret, secretlen, 1);
+}
+
+/* Respond to a buddy initiating the Socialist Millionaires' Protocol */
+void otrl_message_respond_smp(OtrlUserState us, const OtrlMessageAppOps *ops,
+ void *opdata, ConnContext *context, const unsigned char *secret,
+ size_t secretlen)
+{
+ init_respond_smp(us, ops, opdata, context, secret, secretlen, 0);
+}
+
+/* Abort the SMP. Called when an unexpected SMP message breaks the
+ * normal flow. */
+void otrl_message_abort_smp(OtrlUserState us, const OtrlMessageAppOps *ops,
+ void *opdata, ConnContext *context)
+{
+ context->smstate->nextExpected = OTRL_SMP_EXPECT1;
+
+ OtrlTLV *sendtlv = otrl_tlv_new(OTRL_TLV_SMP_ABORT, 0,
+ (const unsigned char *)"");
+ char *sendsmp = NULL;
+ gcry_error_t err;
+ err = otrl_proto_create_data(&sendsmp,
+ context, "", sendtlv,
+ OTRL_MSGFLAGS_IGNORE_UNREADABLE);
+ if (!err) {
+ /* Send the abort signal so our buddy knows we've stopped */
+ err = otrl_message_fragment_and_send(ops, opdata, context,
+ sendsmp, OTRL_FRAGMENT_SEND_ALL, NULL);
+ }
+ free(sendsmp);
+ otrl_tlv_free(sendtlv);
+}
+
/* Handle a message just received from the network. It is safe to pass
* all received messages to this routine. add_appdata is a function
* that will be called in the event that a new ConnContext is created.
@@ -766,11 +888,14 @@ int otrl_message_receiving(OtrlUserState us, const OtrlMessageAppOps *ops,
case OTRL_MSGTYPE_DATA:
switch(context->msgstate) {
gcry_error_t err;
- OtrlTLV *tlvs;
+ OtrlTLV *tlvs, *tlv;
char *plaintext;
char *buf;
- char *format;
+ const char *format;
+ const char *displayaccountname;
unsigned char flags;
+ NextExpectedSMP nextMsg;
+
case OTRL_MSGSTATE_PLAINTEXT:
case OTRL_MSGSTATE_FINISHED:
/* See if we're supposed to ignore this message in
@@ -806,16 +931,29 @@ int otrl_message_receiving(OtrlUserState us, const OtrlMessageAppOps *ops,
}
format = "?OTR Error: You sent encrypted "
"data to %s, who wasn't expecting it.";
- buf = malloc(strlen(format) + strlen(context->accountname)
+ if (otrl_api_version >= 0x00030100 &&
+ ops->account_name) {
+ displayaccountname = ops->account_name(opdata,
+ context->accountname, protocol);
+ } else {
+ displayaccountname = NULL;
+ }
+ buf = malloc(strlen(format) + strlen(displayaccountname ?
+ displayaccountname : context->accountname)
- 1);
if (buf) {
- sprintf(buf, format, context->accountname);
+ sprintf(buf, format, displayaccountname ?
+ displayaccountname : context->accountname);
if (ops->inject_message) {
ops->inject_message(opdata, accountname, protocol,
sender, buf);
}
free(buf);
}
+ if (displayaccountname && otrl_api_version >= 0x00030100 &&
+ ops->account_name_free) {
+ ops->account_name_free(opdata, displayaccountname);
+ }
break;
@@ -863,7 +1001,75 @@ int otrl_message_receiving(OtrlUserState us, const OtrlMessageAppOps *ops,
if (otrl_tlv_find(tlvs, OTRL_TLV_DISCONNECTED)) {
otrl_context_force_finished(context);
}
-
+
+ /* If TLVs contain SMP data, process it */
+ nextMsg = context->smstate->nextExpected;
+ tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP1);
+ if (tlv && nextMsg == OTRL_SMP_EXPECT1) {
+ /* We can only do the verification half now.
+ * We must wait for the secret to be entered
+ * to continue. */
+ otrl_sm_step2a(context->smstate, tlv->data, tlv->len);
+ }
+ tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP2);
+ if (tlv && nextMsg == OTRL_SMP_EXPECT2) {
+ unsigned char* nextmsg;
+ int nextmsglen;
+ OtrlTLV *sendtlv;
+ char *sendsmp;
+ otrl_sm_step3(context->smstate, tlv->data, tlv->len,
+ &nextmsg, &nextmsglen);
+
+ /* Send msg with next smp msg content */
+ sendtlv = otrl_tlv_new(OTRL_TLV_SMP3, nextmsglen,
+ nextmsg);
+ err = otrl_proto_create_data(&sendsmp,
+ context, "", sendtlv,
+ OTRL_MSGFLAGS_IGNORE_UNREADABLE);
+ if (!err) {
+ err = otrl_message_fragment_and_send(ops, opdata, context, sendsmp, OTRL_FRAGMENT_SEND_ALL, NULL);
+ }
+ free(sendsmp);
+ otrl_tlv_free(sendtlv);
+ free(nextmsg);
+ }
+ tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP3);
+ if (tlv && nextMsg == OTRL_SMP_EXPECT3) {
+ unsigned char* nextmsg;
+ int nextmsglen;
+ OtrlTLV *sendtlv;
+ char *sendsmp;
+ err = otrl_sm_step4(context->smstate, tlv->data,
+ tlv->len, &nextmsg, &nextmsglen);
+ /* Set trust level based on result */
+ set_smp_trust(ops, opdata, context,
+ (err == gcry_error(GPG_ERR_NO_ERROR)));
+
+ /* Send msg with next smp msg content */
+ sendtlv = otrl_tlv_new(OTRL_TLV_SMP4, nextmsglen,
+ nextmsg);
+ err = otrl_proto_create_data(&sendsmp,
+ context, "", sendtlv,
+ OTRL_MSGFLAGS_IGNORE_UNREADABLE);
+ if (!err) {
+ err = otrl_message_fragment_and_send(ops, opdata, context, sendsmp, OTRL_FRAGMENT_SEND_ALL, NULL);
+ }
+ free(sendsmp);
+ otrl_tlv_free(sendtlv);
+ free(nextmsg);
+ }
+ tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP4);
+ if (tlv && nextMsg == OTRL_SMP_EXPECT4) {
+ err = otrl_sm_step5(context->smstate, tlv->data,
+ tlv->len);
+ /* Set trust level based on result */
+ set_smp_trust(ops, opdata, context,
+ (err == gcry_error(GPG_ERR_NO_ERROR)));
+ }
+ tlv = otrl_tlv_find(tlvs, OTRL_TLV_SMP_ABORT);
+ if (tlv) {
+ context->smstate->nextExpected = OTRL_SMP_EXPECT1;
+ }
if (plaintext[0] == '\0') {
/* If it's a heartbeat (an empty message), don't
* display it to the user, but log a debug message. */
@@ -1080,6 +1286,74 @@ int otrl_message_receiving(OtrlUserState us, const OtrlMessageAppOps *ops,
return edata.ignore_message;
}
+/* Send a message to the network, fragmenting first if necessary.
+ * All messages to be sent to the network should go through this
+ * method immediately before they are sent, ie after encryption. */
+gcry_error_t otrl_message_fragment_and_send(const OtrlMessageAppOps *ops,
+ void *opdata, ConnContext *context, const char *message,
+ OtrlFragmentPolicy fragPolicy, char **returnFragment)
+{
+ int mms = 0;
+ if (message && ops->inject_message) {
+ if (otrl_api_version >= 0x030100 && ops->max_message_size) {
+ mms = ops->max_message_size(opdata, context);
+ }
+ int msglen;
+ msglen = strlen(message);
+
+ /* Don't incur overhead of fragmentation unless necessary */
+ if(mms != 0 && msglen > mms) {
+ char **fragments;
+ gcry_error_t err;
+ int fragment_count = ((msglen - 1) / (mms -19)) + 1;
+ /* like ceil(msglen/(mms - 19)) */
+ err = otrl_proto_fragment_create(mms, fragment_count, &fragments,
+ message);
+ if (err) {
+ return err;
+ }
+
+ /* Determine which fragments to send and which to return
+ * based on given Fragment Policy. If the first fragment
+ * should be returned instead of sent, store it. */
+ if (fragPolicy == OTRL_FRAGMENT_SEND_ALL_BUT_FIRST) {
+ *returnFragment = strdup(fragments[0]);
+ } else {
+ ops->inject_message(opdata, context->accountname,
+ context->protocol, context->username, fragments[0]);
+ }
+ int i;
+ for (i=1; i<fragment_count-1; i++) {
+ ops->inject_message(opdata, context->accountname,
+ context->protocol, context->username, fragments[i]);
+ }
+ /* If the last fragment should be stored instead of sent,
+ * store it */
+ if (fragPolicy == OTRL_FRAGMENT_SEND_ALL_BUT_LAST) {
+ *returnFragment = strdup(fragments[fragment_count-1]);
+ } else {
+ ops->inject_message(opdata, context->accountname,
+ context->protocol, context->username, fragments[fragment_count-1]);
+ }
+ /* Now free all fragment memory */
+ otrl_proto_fragment_free(&fragments, fragment_count);
+
+ } else {
+ /* No fragmentation necessary */
+ if (fragPolicy == OTRL_FRAGMENT_SEND_ALL) {
+ ops->inject_message(opdata, context->accountname,
+ context->protocol, context->username, message);
+ } else {
+ /* Copy and return the entire given message. */
+ int l = strlen(message) + 1;
+ *returnFragment = malloc(sizeof(char)*l);
+ strcpy(*returnFragment, message);
+ }
+ }
+ }
+ return gcry_error(GPG_ERR_NO_ERROR);
+}
+
/* Put a connection into the PLAINTEXT state, first sending the
* other side a notice that we're doing so if we're currently ENCRYPTED,
* and we think he's logged in. */
diff --git a/src/message.h b/src/message.h
index 56c8d04..9ef8e93 100644
--- a/src/message.h
+++ b/src/message.h
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging library
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This library is free software; you can redistribute it and/or
@@ -69,7 +69,7 @@ typedef struct s_OtrlMessageAppOps {
* state), this is called so the UI can be updated. */
void (*update_context_list)(void *opdata);
- /* Return a newly-allocated string containing a human-friendly name
+ /* Return a newly allocated string containing a human-friendly name
* for the given protocol id */
const char *(*protocol_name)(void *opdata, const char *protocol);
@@ -97,6 +97,17 @@ typedef struct s_OtrlMessageAppOps {
/* Log a message. The passed message will end in "\n". */
void (*log_message)(void *opdata, const char *message);
+ /* Find the maximum message size supported by this protocol. */
+ int (*max_message_size)(void *opdata, ConnContext *context);
+
+ /* Return a newly allocated string containing a human-friendly
+ * representation for the given account */
+ const char *(*account_name)(void *opdata, const char *account,
+ const char *protocol);
+
+ /* Deallocate a string returned by account_name */
+ void (*account_name_free)(void *opdata, const char *account_name);
+
} OtrlMessageAppOps;
/* Deallocate a message allocated by other otrl_message_* routines. */
@@ -161,6 +172,13 @@ int otrl_message_receiving(OtrlUserState us, const OtrlMessageAppOps *ops,
void (*add_appdata)(void *data, ConnContext *context),
void *data);
+/* Send a message to the network, fragmenting first if necessary.
+ * All messages to be sent to the network should go through this
+ * method immediately before they are sent, ie after encryption. */
+gcry_error_t otrl_message_fragment_and_send(const OtrlMessageAppOps *ops,
+ void *opdata, ConnContext *context, const char *message,
+ OtrlFragmentPolicy fragPolicy, char **returnFragment);
+
/* Put a connection into the PLAINTEXT state, first sending the
* other side a notice that we're doing so if we're currently ENCRYPTED,
* and we think he's logged in. */
@@ -168,4 +186,19 @@ void otrl_message_disconnect(OtrlUserState us, const OtrlMessageAppOps *ops,
void *opdata, const char *accountname, const char *protocol,
const char *username);
+/* Initiate the Socialist Millionaires' Protocol */
+void otrl_message_initiate_smp(OtrlUserState us, const OtrlMessageAppOps *ops,
+ void *opdata, ConnContext *context, const unsigned char *secret,
+ size_t secretlen);
+
+/* Respond to a buddy initiating the Socialist Millionaires' Protocol */
+void otrl_message_respond_smp(OtrlUserState us, const OtrlMessageAppOps *ops,
+ void *opdata, ConnContext *context, const unsigned char *secret,
+ size_t secretlen);
+
+/* Abort the SMP. Called when an unexpected SMP message breaks the
+ * normal flow. */
+void otrl_message_abort_smp(OtrlUserState us, const OtrlMessageAppOps *ops,
+ void *opdata, ConnContext *context);
+
#endif
diff --git a/src/privkey-t.h b/src/privkey-t.h
index 57dc116..66a1033 100644
--- a/src/privkey-t.h
+++ b/src/privkey-t.h
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging library
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This library is free software; you can redistribute it and/or
diff --git a/src/privkey.c b/src/privkey.c
index d1adaf0..6ae44ee 100644
--- a/src/privkey.c
+++ b/src/privkey.c
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging library
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This library is free software; you can redistribute it and/or
@@ -71,6 +71,25 @@ char *otrl_privkey_fingerprint(OtrlUserState us, char fingerprint[45],
return fingerprint;
}
+/* Calculate a raw hash of our DSA public key. Return it in the passed
+ * fingerprint buffer. Return NULL on error, or a pointer to the given
+ * buffer on success. */
+unsigned char *otrl_privkey_fingerprint_raw(OtrlUserState us,
+ unsigned char hash[20], const char *accountname, const char *protocol)
+{
+ OtrlPrivKey *p = otrl_privkey_find(us, accountname, protocol);
+
+ if (p) {
+ /* Calculate the hash */
+ gcry_md_hash_buffer(GCRY_MD_SHA1, hash, p->pubkey_data,
+ p->pubkey_datalen);
+ } else {
+ return NULL;
+ }
+
+ return hash;
+}
+
/* Create a public key block from a private key */
static gcry_error_t make_pubkey(unsigned char **pubbufp, size_t *publenp,
gcry_sexp_t privkey)
diff --git a/src/privkey.h b/src/privkey.h
index 5073c18..65c73ef 100644
--- a/src/privkey.h
+++ b/src/privkey.h
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging library
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This library is free software; you can redistribute it and/or
@@ -33,6 +33,12 @@ void otrl_privkey_hash_to_human(char human[45], const unsigned char hash[20]);
char *otrl_privkey_fingerprint(OtrlUserState us, char fingerprint[45],
const char *accountname, const char *protocol);
+/* Calculate a raw hash of our DSA public key. Return it in the passed
+ * fingerprint buffer. Return NULL on error, or a pointer to the given
+ * buffer on success. */
+unsigned char *otrl_privkey_fingerprint_raw(OtrlUserState us,
+ unsigned char hash[20], const char *accountname, const char *protocol);
+
/* Read a sets of private DSA keys from a file on disk into the given
* OtrlUserState. */
gcry_error_t otrl_privkey_read(OtrlUserState us, const char *filename);
diff --git a/src/proto.c b/src/proto.c
index fdd2a99..e0e738f 100644
--- a/src/proto.c
+++ b/src/proto.c
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging library
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This library is free software; you can redistribute it and/or
@@ -37,11 +37,17 @@
#include "tlv.h"
#include "serial.h"
+/* For now, we need to know the API version the client is using so that
+ * we don't use any UI callbacks it hasn't set. */
+unsigned int otrl_api_version = 0;
+
/* Initialize the OTR library. Pass the version of the API you are
* using. */
void otrl_init(unsigned int ver_major, unsigned int ver_minor,
unsigned int ver_sub)
{
+ unsigned int api_version;
+
/* The major versions have to match, and you can't be using a newer
* minor version than we expect. */
if (ver_major != OTRL_VERSION_MAJOR || ver_minor > OTRL_VERSION_MINOR) {
@@ -52,11 +58,21 @@ void otrl_init(unsigned int ver_major, unsigned int ver_minor,
exit(1);
}
+ /* Set the API version. If we get called multiple times for some
+ * reason, take the smallest value. */
+ api_version = (ver_major << 16) | (ver_minor << 8) | (ver_sub);
+ if (otrl_api_version == 0 || otrl_api_version > api_version) {
+ otrl_api_version = api_version;
+ }
+
/* Initialize the memory module */
otrl_mem_init();
/* Initialize the DH module */
otrl_dh_init();
+
+ /* Initialize the SM module */
+ otrl_sm_init();
}
/* Return a pointer to a static string containing the version number of
@@ -199,10 +215,10 @@ char *otrl_proto_default_query_msg(const char *ourname, OtrlPolicy policy)
* get passed to the main IM application for processing (and
* free()ing). */
const char *format = "?OTR%s\n<b>%s</b> has requested an "
- "<a href=\"http://www.cypherpunks.ca/otr/\">Off-the-Record "
+ "<a href=\"http://otr.cypherpunks.ca/\">Off-the-Record "
"private conversation</a>. However, you do not have a plugin "
- "to support that.\nSee <a href=\"http://www.cypherpunks.ca/otr/\">"
- "http://www.cypherpunks.ca/otr/</a> for more information.";
+ "to support that.\nSee <a href=\"http://otr.cypherpunks.ca/\">"
+ "http://otr.cypherpunks.ca/</a> for more information.";
/* Figure out the version tag */
v1_supported = (policy & OTRL_POLICY_ALLOW_V1);
@@ -360,7 +376,7 @@ gcry_error_t otrl_proto_create_data(char **encmessagep, ConnContext *context,
size_t reveallen = 20 * context->numsavedkeys;
size_t base64len;
char *base64buf = NULL;
- char *msgbuf = NULL;
+ unsigned char *msgbuf = NULL;
enum gcry_mpi_format format = GCRYMPI_FMT_USG;
char *msgdup;
int version = context->protocol_version;
@@ -461,7 +477,7 @@ gcry_error_t otrl_proto_create_data(char **encmessagep, ConnContext *context,
base64len = ((buflen + 2) / 3) * 4;
base64buf = malloc(5 + base64len + 1 + 1);
if (base64buf == NULL) {
- err = GPG_ERR_ENOMEM;
+ err = gcry_error(GPG_ERR_ENOMEM);
goto err;
}
memmove(base64buf, "?OTR:", 5);
@@ -705,7 +721,7 @@ gcry_error_t otrl_proto_accept_data(char **plaintextp, OtrlTLV **tlvsp,
}
gcry_mpi_release(sender_next_y);
- *plaintextp = data;
+ *plaintextp = (char *)data;
/* See if there are TLVs */
nul = data;
@@ -811,3 +827,78 @@ OtrlFragmentResult otrl_proto_fragment_accumulate(char **unfragmessagep,
return res;
}
+
+/* Create a fragmented message. */
+gcry_error_t otrl_proto_fragment_create(int mms, int fragment_count,
+ char ***fragments, const char *message)
+{
+ char *fragdata;
+ int fragdatalen = 0;
+ unsigned short curfrag = 0;
+ int index = 0;
+ int msglen = strlen(message);
+ int headerlen = 19; /* Should vary by number of msgs */
+
+ char **fragmentarray = malloc(fragment_count * sizeof(char*));
+ if(!fragmentarray) return gcry_error(GPG_ERR_ENOMEM);
+
+ /*
+ * Find the next message fragment and store it in the array.
+ */
+ for(curfrag = 1; curfrag <= fragment_count; curfrag++) {
+ if (msglen - index < mms - headerlen) {
+ fragdatalen = msglen - index;
+ } else {
+ fragdatalen = mms - headerlen;
+ }
+ int i;
+ fragdata = malloc(fragdatalen + 1);
+ if(!fragdata) {
+ for (i=0; i<curfrag-1; free(fragmentarray[i++])) {}
+ free(fragmentarray);
+ return gcry_error(GPG_ERR_ENOMEM);
+ }
+ strncpy(fragdata, message, fragdatalen);
+ fragdata[fragdatalen] = 0;
+
+ char *fragmentmsg = malloc(fragdatalen+headerlen+1);
+ if(!fragmentmsg) {
+ for (i=0; i<curfrag-1; free(fragmentarray[i++])) {}
+ free(fragmentarray);
+ free(fragdata);
+ return gcry_error(GPG_ERR_ENOMEM);
+ }
+
+ /*
+ * Create the actual fragment and store it in the array
+ */
+ snprintf(fragmentmsg, fragdatalen + headerlen, "?OTR,%05hu,%05hu,%s,", curfrag, fragment_count, fragdata);
+ fragmentmsg[fragdatalen + headerlen] = 0;
+
+ fragmentarray[curfrag-1] = fragmentmsg;
+
+ free(fragdata);
+ index += fragdatalen;
+ message += fragdatalen;
+ }
+
+ *fragments = fragmentarray;
+ return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+/* Free a string array containing fragment messages. */
+void otrl_proto_fragment_free(char ***fragments, unsigned short arraylen)
+{
+ int i;
+ char **fragmentarray = *fragments;
+ if(fragmentarray) {
+ for(i = 0; i < arraylen; i++)
+ {
+ if(fragmentarray[i]) {
+ free(fragmentarray[i]);
+ }
+ }
+ free(fragmentarray);
+ }
+}
+
diff --git a/src/proto.h b/src/proto.h
index bb2cf08..4a988ba 100644
--- a/src/proto.h
+++ b/src/proto.h
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging library
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This library is free software; you can redistribute it and/or
@@ -84,6 +84,12 @@ typedef enum {
OTRL_FRAGMENT_COMPLETE
} OtrlFragmentResult;
+typedef enum {
+ OTRL_FRAGMENT_SEND_ALL,
+ OTRL_FRAGMENT_SEND_ALL_BUT_FIRST,
+ OTRL_FRAGMENT_SEND_ALL_BUT_LAST
+} OtrlFragmentPolicy;
+
/* Initialize the OTR library. Pass the version of the API you are
* using. */
void otrl_init(unsigned int ver_major, unsigned int ver_minor,
@@ -137,4 +143,8 @@ gcry_error_t otrl_proto_accept_data(char **plaintextp, OtrlTLV **tlvsp,
OtrlFragmentResult otrl_proto_fragment_accumulate(char **unfragmessagep,
ConnContext *context, const char *msg);
+gcry_error_t otrl_proto_fragment_create(int mms, int fragment_count,
+ char ***fragments, const char *message);
+
+void otrl_proto_fragment_free(char ***fragments, unsigned short arraylen);
#endif
diff --git a/src/serial.h b/src/serial.h
index 981a9e4..005b86c 100644
--- a/src/serial.h
+++ b/src/serial.h
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging library
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This library is free software; you can redistribute it and/or
diff --git a/src/sm.c b/src/sm.c
new file mode 100644
index 0000000..d997e42
--- /dev/null
+++ b/src/sm.c
@@ -0,0 +1,884 @@
+/*
+ * Off-the-Record Messaging library
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
+ * <otr at cypherpunks.ca>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General
+ * Public License as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* system headers */
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+/* libgcrypt headers */
+#include <gcrypt.h>
+
+/* libotr headers */
+#include "sm.h"
+#include "serial.h"
+
+static const int SM_MSG1_LEN = 6;
+static const int SM_MSG2_LEN = 11;
+static const int SM_MSG3_LEN = 8;
+static const int SM_MSG4_LEN = 3;
+
+/* The modulus p */
+static const char* SM_MODULUS_S = "0x"
+ "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1"
+ "29024E088A67CC74020BBEA63B139B22514A08798E3404DD"
+ "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245"
+ "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED"
+ "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3D"
+ "C2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F"
+ "83655D23DCA3AD961C62F356208552BB9ED529077096966D"
+ "670C354E4ABC9804F1746C08CA237327FFFFFFFFFFFFFFFF";
+/* The order of the group q = (p-1)/2 */
+static const char* SM_ORDER_S = "0x"
+ "7FFFFFFFFFFFFFFFE487ED5110B4611A62633145C06E0E68"
+ "948127044533E63A0105DF531D89CD9128A5043CC71A026E"
+ "F7CA8CD9E69D218D98158536F92F8A1BA7F09AB6B6A8E122"
+ "F242DABB312F3F637A262174D31BF6B585FFAE5B7A035BF6"
+ "F71C35FDAD44CFD2D74F9208BE258FF324943328F6722D9E"
+ "E1003E5C50B1DF82CC6D241B0E2AE9CD348B1FD47E9267AF"
+ "C1B2AE91EE51D6CB0E3179AB1042A95DCF6A9483B84B4B36"
+ "B3861AA7255E4C0278BA36046511B993FFFFFFFFFFFFFFFF";
+static const char *SM_GENERATOR_S = "0x02";
+static const int SM_MOD_LEN_BITS = 1536;
+static const int SM_MOD_LEN_BYTES = 192;
+
+static gcry_mpi_t SM_MODULUS = NULL;
+static gcry_mpi_t SM_GENERATOR = NULL;
+static gcry_mpi_t SM_ORDER = NULL;
+static gcry_mpi_t SM_MODULUS_MINUS_2 = NULL;
+
+/*
+ * Call this once, at plugin load time. It sets up the modulus and
+ * generator MPIs.
+ */
+void otrl_sm_init(void)
+{
+ gcry_check_version(NULL);
+ gcry_mpi_scan(&SM_MODULUS, GCRYMPI_FMT_HEX, SM_MODULUS_S, 0, NULL);
+ gcry_mpi_scan(&SM_ORDER, GCRYMPI_FMT_HEX, SM_ORDER_S, 0, NULL);
+ gcry_mpi_scan(&SM_GENERATOR, GCRYMPI_FMT_HEX, SM_GENERATOR_S,
+ 0, NULL);
+ SM_MODULUS_MINUS_2 = gcry_mpi_new(SM_MOD_LEN_BITS);
+ gcry_mpi_sub_ui(SM_MODULUS_MINUS_2, SM_MODULUS, 2);
+}
+
+/*
+ * Initialize the fields of a SM state.
+ */
+void otrl_sm_state_new(OtrlSMState *smst)
+{
+ smst->secret = NULL;
+ smst->x2 = NULL;
+ smst->x3 = NULL;
+ smst->g1 = NULL;
+ smst->g2 = NULL;
+ smst->g3 = NULL;
+ smst->g3o = NULL;
+ smst->p = NULL;
+ smst->q = NULL;
+ smst->pab = NULL;
+ smst->qab = NULL;
+ smst->nextExpected = OTRL_SMP_EXPECT1;
+}
+
+/*
+ * Initialize the fields of a SM state. Called the first time that
+ * a user begins an SMP session.
+ */
+void otrl_sm_state_init(OtrlSMState *smst)
+{
+ otrl_sm_state_free(smst);
+ smst->secret = gcry_mpi_new(SM_MOD_LEN_BITS);
+ smst->x2 = NULL;
+ smst->x3 = NULL;
+ smst->g1 = gcry_mpi_copy(SM_GENERATOR);
+ smst->g2 = gcry_mpi_new(SM_MOD_LEN_BITS);
+ smst->g3 = gcry_mpi_new(SM_MOD_LEN_BITS);
+ smst->g3o = gcry_mpi_new(SM_MOD_LEN_BITS);
+ smst->p = gcry_mpi_new(SM_MOD_LEN_BITS);
+ smst->q = gcry_mpi_new(SM_MOD_LEN_BITS);
+ smst->pab = gcry_mpi_new(SM_MOD_LEN_BITS);
+ smst->qab = gcry_mpi_new(SM_MOD_LEN_BITS);
+}
+
+/*
+ * Initialize the fields of a SM message1.
+ * [0] = g2a, [1] = c2, [2] = d2, [3] = g3a, [4] = c3, [5] = d3
+ */
+void otrl_sm_msg1_init(gcry_mpi_t **msg1)
+{
+ gcry_mpi_t *msg = malloc(SM_MSG1_LEN * sizeof(gcry_mpi_t));
+ msg[0] = gcry_mpi_new(SM_MOD_LEN_BITS);
+ msg[1] = NULL;
+ msg[2] = gcry_mpi_new(SM_MOD_LEN_BITS);
+ msg[3] = gcry_mpi_new(SM_MOD_LEN_BITS);
+ msg[4] = NULL;
+ msg[5] = gcry_mpi_new(SM_MOD_LEN_BITS);
+
+ *msg1 = msg;
+}
+
+/*
+ * Initialize the fields of a SM message2.
+ * [0] = g2b, [1] = c2, [2] = d2, [3] = g3b, [4] = c3, [5] = d3
+ * [6] = pb, [7] = qb, [8] = cp, [9] = d5, [10] = d6
+ */
+void otrl_sm_msg2_init(gcry_mpi_t **msg2)
+{
+ gcry_mpi_t *msg = malloc(SM_MSG2_LEN * sizeof(gcry_mpi_t));
+ msg[0] = gcry_mpi_new(SM_MOD_LEN_BITS);
+ msg[1] = NULL;
+ msg[2] = gcry_mpi_new(SM_MOD_LEN_BITS);
+ msg[3] = gcry_mpi_new(SM_MOD_LEN_BITS);
+ msg[4] = NULL;
+ msg[5] = gcry_mpi_new(SM_MOD_LEN_BITS);
+ msg[6] = gcry_mpi_new(SM_MOD_LEN_BITS);
+ msg[7] = gcry_mpi_new(SM_MOD_LEN_BITS);
+ msg[8] = NULL;
+ msg[9] = gcry_mpi_new(SM_MOD_LEN_BITS);
+ msg[10] = gcry_mpi_new(SM_MOD_LEN_BITS);
+
+ *msg2 = msg;
+}
+
+/*
+ * Initialize the fields of a SM message3.
+ * [0] = pa, [1] = qa, [2] = cp, [3] = d5, [4] = d6, [5] = ra,
+ * [6] = cr, [7] = d7
+ */
+void otrl_sm_msg3_init(gcry_mpi_t **msg3)
+{
+ gcry_mpi_t *msg = malloc(SM_MSG3_LEN * sizeof(gcry_mpi_t));
+ msg[0] = gcry_mpi_new(SM_MOD_LEN_BITS);
+ msg[1] = gcry_mpi_new(SM_MOD_LEN_BITS);
+ msg[2] = NULL;
+ msg[3] = gcry_mpi_new(SM_MOD_LEN_BITS);
+ msg[4] = gcry_mpi_new(SM_MOD_LEN_BITS);
+ msg[5] = gcry_mpi_new(SM_MOD_LEN_BITS);
+ msg[6] = NULL;
+ msg[7] = gcry_mpi_new(SM_MOD_LEN_BITS);
+
+ *msg3 = msg;
+}
+
+/*
+ * Initialize the fields of a SM message4.
+ * [0] = rb, [1] = cr, [2] = d7
+ */
+void otrl_sm_msg4_init(gcry_mpi_t **msg4)
+{
+ gcry_mpi_t *msg = malloc(SM_MSG4_LEN * sizeof(gcry_mpi_t));
+ msg[0] = gcry_mpi_new(SM_MOD_LEN_BITS);
+ msg[1] = NULL;
+ msg[2] = gcry_mpi_new(SM_MOD_LEN_BITS);
+
+ *msg4 = msg;
+}
+
+/*
+ * Deallocate the contents of a OtrlSMState (but not the OtrlSMState
+ * itself)
+ */
+void otrl_sm_state_free(OtrlSMState *smst)
+{
+ gcry_mpi_release(smst->secret);
+ gcry_mpi_release(smst->x2);
+ gcry_mpi_release(smst->x3);
+ gcry_mpi_release(smst->g1);
+ gcry_mpi_release(smst->g2);
+ gcry_mpi_release(smst->g3);
+ gcry_mpi_release(smst->g3o);
+ gcry_mpi_release(smst->p);
+ gcry_mpi_release(smst->q);
+ gcry_mpi_release(smst->pab);
+ gcry_mpi_release(smst->qab);
+ otrl_sm_state_new(smst);
+}
+
+/*
+ * Deallocate the contents of a message
+ */
+void otrl_sm_msg_free(gcry_mpi_t **message, int msglen)
+{
+ gcry_mpi_t *msg = *message;
+ int i;
+ for (i=0; i<msglen; i++) {
+ gcry_mpi_release(msg[i]);
+ }
+ free(msg);
+ *message = NULL;
+}
+
+static gcry_mpi_t randomExponent(void)
+{
+ unsigned char *secbuf = NULL;
+ gcry_mpi_t randexpon = NULL;
+
+ /* Generate a random exponent */
+ secbuf = gcry_random_bytes_secure(SM_MOD_LEN_BYTES, GCRY_STRONG_RANDOM);
+ gcry_mpi_scan(&randexpon, GCRYMPI_FMT_USG, secbuf, SM_MOD_LEN_BYTES, NULL);
+ gcry_free(secbuf);
+
+ return randexpon;
+}
+
+/*
+ * Hash one or two mpis. To hash only one mpi, b may be set to NULL.
+ */
+static gcry_error_t otrl_sm_hash(gcry_mpi_t* hash, int version,
+ const gcry_mpi_t a, const gcry_mpi_t b)
+{
+ unsigned char* input;
+ unsigned char output[SM_DIGEST_SIZE];
+ unsigned int sizea;
+ unsigned int sizeb;
+ unsigned int totalsize;
+ unsigned char* dataa;
+ unsigned char* datab;
+
+ gcry_mpi_aprint(GCRYMPI_FMT_USG, &dataa, &sizea, a);
+ totalsize = 1 + 4 + sizea;
+ if (b) {
+ gcry_mpi_aprint(GCRYMPI_FMT_USG, &datab, &sizeb, b);
+ totalsize += 4 + sizeb;
+ } else {
+ sizeb = 0;
+ }
+
+ input = malloc(totalsize);
+ input[0] = (unsigned char)version;
+ input[1] = (unsigned char)((sizea >> 24) & 0xFF);
+ input[2] = (unsigned char)((sizea >> 16) & 0xFF);
+ input[3] = (unsigned char)((sizea >> 8) & 0xFF);
+ input[4] = (unsigned char)(sizea & 0xFF);
+ memmove(input + 5, dataa, sizea);
+ if (b) {
+ input[5 + sizea] = (unsigned char)((sizeb >> 24) & 0xFF);
+ input[6 + sizea] = (unsigned char)((sizeb >> 16) & 0xFF);
+ input[7 + sizea] = (unsigned char)((sizeb >> 8) & 0xFF);
+ input[8 + sizea] = (unsigned char)(sizeb & 0xFF);
+ memmove(input + 9 + sizea, datab, sizeb);
+ }
+
+ gcry_md_hash_buffer(SM_HASH_ALGORITHM, output, input, totalsize);
+ gcry_mpi_scan(hash, GCRYMPI_FMT_USG, output, SM_DIGEST_SIZE, NULL);
+ free(input);
+ input = NULL;
+
+ /* free memory */
+ gcry_free(dataa);
+ if (b) gcry_free(datab);
+
+ return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+/* This method should be passed a pointer to an uninitialized buffer,
+ * and a list of mpis with a list length. When returns, the buffer will
+ * point to newly-allocated memory (using malloc) containing a
+ * reversible serialization. */
+static gcry_error_t serialize_mpi_array(unsigned char **buffer, int *buflen,
+ unsigned int count, gcry_mpi_t *mpis)
+{
+ size_t totalsize = 0, lenp, nextsize;
+ unsigned int i, j;
+ size_t *list_sizes = malloc(count * sizeof(size_t));
+ unsigned char **tempbuffer = malloc(count * sizeof(unsigned char *));
+ unsigned char *bufp;
+
+ for (i=0; i<count; i++) {
+ gcry_mpi_aprint(GCRYMPI_FMT_USG, &(tempbuffer[i]), &(list_sizes[i]),
+ mpis[i]);
+ totalsize += list_sizes[i];
+ }
+
+ *buflen = (count+1)*4 + totalsize;
+ *buffer = malloc(*buflen * sizeof(char));
+
+ bufp = *buffer;
+ lenp = totalsize;
+
+ write_int(count);
+ for(i=0; i<count; i++)
+ {
+ nextsize = list_sizes[i];
+ write_int(nextsize);
+
+ for(j=0; j<nextsize; j++)
+ bufp[j] = tempbuffer[i][j];
+
+ bufp += nextsize;
+ lenp -= nextsize;
+ gcry_free(tempbuffer[i]);
+ }
+ free(tempbuffer);
+ free(list_sizes);
+
+ return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+/* Takes a buffer containing serialized and concatenated mpis
+ * and converts it to an array of gcry_mpi_t structs.
+ * The buffer is assumed to consist of a 4-byte int containing the
+ * number of mpis in the array, followed by {size, data} pairs for
+ * each mpi. If malformed, method returns GCRY_ERROR_INV_VALUE */
+static gcry_error_t unserialize_mpi_array(gcry_mpi_t **mpis,
+ unsigned int expcount, const unsigned char *buffer, const int buflen)
+{
+ int i;
+ int lenp = buflen;
+ unsigned int thecount = 0;
+ const unsigned char* bufp = buffer;
+ *mpis = NULL;
+
+ read_int(thecount);
+ if (thecount != expcount) goto invval;
+
+ *mpis = malloc(thecount * sizeof(gcry_mpi_t));
+
+ for (i=0; i<thecount; i++) {
+ (*mpis)[i] = NULL;
+ }
+
+ for (i=0; i<thecount; i++) {
+ read_mpi((*mpis)[i]);
+ }
+
+ return gcry_error(GPG_ERR_NO_ERROR);
+
+invval:
+ if (*mpis) {
+ for (i=0; i<thecount; i++) {
+ gcry_mpi_release((*mpis)[i]);
+ }
+ free(*mpis);
+ *mpis = NULL;
+ }
+ return gcry_error(GPG_ERR_INV_VALUE);
+}
+
+/* Check that an MPI is in the right range to be a (non-unit) group
+ * element */
+static int check_group_elem(gcry_mpi_t g)
+{
+ if (gcry_mpi_cmp_ui(g, 2) < 0 ||
+ gcry_mpi_cmp(g, SM_MODULUS_MINUS_2) > 0) {
+ return 1;
+ }
+ return 0;
+}
+
+/* Check that an MPI is in the right range to be a (non-zero) exponent */
+static int check_expon(gcry_mpi_t x)
+{
+ if (gcry_mpi_cmp_ui(x, 1) < 0 ||
+ gcry_mpi_cmp(x, SM_ORDER) >= 0) {
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Proof of knowledge of a discrete logarithm
+ */
+static gcry_error_t otrl_sm_proof_know_log(gcry_mpi_t *c, gcry_mpi_t *d, const gcry_mpi_t g, const gcry_mpi_t x, int version)
+{
+ gcry_mpi_t r = randomExponent();
+ gcry_mpi_t temp = gcry_mpi_new(SM_MOD_LEN_BITS);
+ gcry_mpi_powm(temp, g, r, SM_MODULUS);
+ otrl_sm_hash(c, version, temp, NULL);
+ gcry_mpi_mulm(temp, x, *c, SM_ORDER);
+ gcry_mpi_subm(*d, r, temp, SM_ORDER);
+ gcry_mpi_release(temp);
+ gcry_mpi_release(r);
+
+ return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+/*
+ * Verify a proof of knowledge of a discrete logarithm. Checks that c = h(g^d x^c)
+ */
+static int otrl_sm_check_know_log(const gcry_mpi_t c, const gcry_mpi_t d, const gcry_mpi_t g, const gcry_mpi_t x, int version)
+{
+ gcry_mpi_t gd = gcry_mpi_new(SM_MOD_LEN_BITS); /* g^d */
+ gcry_mpi_t xc = gcry_mpi_new(SM_MOD_LEN_BITS); /* x^c */
+ gcry_mpi_t gdxc = gcry_mpi_new(SM_MOD_LEN_BITS); /* (g^d x^c) */
+ gcry_mpi_t hgdxc = NULL; /* h(g^d x^c) */
+
+ gcry_mpi_powm(gd, g, d, SM_MODULUS);
+ gcry_mpi_powm(xc, x, c, SM_MODULUS);
+ gcry_mpi_mulm(gdxc, gd, xc, SM_MODULUS);
+ otrl_sm_hash(&hgdxc, version, gdxc, NULL);
+
+ int comp = gcry_mpi_cmp(hgdxc, c);
+ gcry_mpi_release(gd);
+ gcry_mpi_release(xc);
+ gcry_mpi_release(gdxc);
+ gcry_mpi_release(hgdxc);
+
+ return comp;
+}
+
+/*
+ * Proof of knowledge of coordinates with first components being equal
+ */
+static gcry_error_t otrl_sm_proof_equal_coords(gcry_mpi_t *c, gcry_mpi_t *d1, gcry_mpi_t *d2, const OtrlSMState *state, const gcry_mpi_t r, int version)
+{
+ gcry_mpi_t r1 = randomExponent();
+ gcry_mpi_t r2 = randomExponent();
+ gcry_mpi_t temp1 = gcry_mpi_new(SM_MOD_LEN_BITS);
+ gcry_mpi_t temp2 = gcry_mpi_new(SM_MOD_LEN_BITS);
+
+ /* Compute the value of c, as c = h(g3^r1, g1^r1 g2^r2) */
+ gcry_mpi_powm(temp1, state->g1, r1, SM_MODULUS);
+ gcry_mpi_powm(temp2, state->g2, r2, SM_MODULUS);
+ gcry_mpi_mulm(temp2, temp1, temp2, SM_MODULUS);
+ gcry_mpi_powm(temp1, state->g3, r1, SM_MODULUS);
+ otrl_sm_hash(c, version, temp1, temp2);
+
+ /* Compute the d values, as d1 = r1 - r c, d2 = r2 - secret c */
+ gcry_mpi_mulm(temp1, r, *c, SM_ORDER);
+ gcry_mpi_subm(*d1, r1, temp1, SM_ORDER);
+
+ gcry_mpi_mulm(temp1, state->secret, *c, SM_ORDER);
+ gcry_mpi_subm(*d2, r2, temp1, SM_ORDER);
+
+ /* All clear */
+ gcry_mpi_release(r1);
+ gcry_mpi_release(r2);
+ gcry_mpi_release(temp1);
+ gcry_mpi_release(temp2);
+ return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+/*
+ * Verify a proof of knowledge of coordinates with first components being equal
+ */
+static gcry_error_t otrl_sm_check_equal_coords(const gcry_mpi_t c, const gcry_mpi_t d1, const gcry_mpi_t d2, const gcry_mpi_t p, const gcry_mpi_t q, const OtrlSMState *state, int version)
+{
+ gcry_mpi_t temp1 = gcry_mpi_new(SM_MOD_LEN_BITS);
+ gcry_mpi_t temp2 = gcry_mpi_new(SM_MOD_LEN_BITS);
+ gcry_mpi_t temp3 = gcry_mpi_new(SM_MOD_LEN_BITS);
+ gcry_mpi_t cprime = NULL;
+
+ /* To verify, we test that hash(g3^d1 * p^c, g1^d1 * g2^d2 * q^c) = c
+ * If indeed c = hash(g3^r1, g1^r1 g2^r2), d1 = r1 - r*c,
+ * d2 = r2 - secret*c. And if indeed p = g3^r, q = g1^r * g2^secret
+ * Then we should have that:
+ * hash(g3^d1 * p^c, g1^d1 * g2^d2 * q^c)
+ * = hash(g3^(r1 - r*c + r*c), g1^(r1 - r*c + q*c) *
+ * g2^(r2 - secret*c + secret*c))
+ * = hash(g3^r1, g1^r1 g2^r2)
+ * = c
+ */
+ gcry_mpi_powm(temp2, state->g3, d1, SM_MODULUS);
+ gcry_mpi_powm(temp3, p, c, SM_MODULUS);
+ gcry_mpi_mulm(temp1, temp2, temp3, SM_MODULUS);
+
+ gcry_mpi_powm(temp2, state->g1, d1, SM_MODULUS);
+ gcry_mpi_powm(temp3, state->g2, d2, SM_MODULUS);
+ gcry_mpi_mulm(temp2, temp2, temp3, SM_MODULUS);
+ gcry_mpi_powm(temp3, q, c, SM_MODULUS);
+ gcry_mpi_mulm(temp2, temp3, temp2, SM_MODULUS);
+
+ otrl_sm_hash(&cprime, version, temp1, temp2);
+
+ int comp = gcry_mpi_cmp(c, cprime);
+ gcry_mpi_release(temp1);
+ gcry_mpi_release(temp2);
+ gcry_mpi_release(temp3);
+ gcry_mpi_release(cprime);
+
+ return comp;
+}
+
+/*
+ * Proof of knowledge of logs with exponents being equal
+ */
+static gcry_error_t otrl_sm_proof_equal_logs(gcry_mpi_t *c, gcry_mpi_t *d, OtrlSMState *state, int version)
+{
+ gcry_mpi_t r = randomExponent();
+ gcry_mpi_t temp1 = gcry_mpi_new(SM_MOD_LEN_BITS);
+ gcry_mpi_t temp2 = gcry_mpi_new(SM_MOD_LEN_BITS);
+
+ /* Compute the value of c, as c = h(g1^r, (Qa/Qb)^r) */
+ gcry_mpi_powm(temp1, state->g1, r, SM_MODULUS);
+ gcry_mpi_powm(temp2, state->qab, r, SM_MODULUS);
+ otrl_sm_hash(c, version, temp1, temp2);
+
+ /* Compute the d values, as d = r - x3 c */
+ gcry_mpi_mulm(temp1, state->x3, *c, SM_ORDER);
+ gcry_mpi_subm(*d, r, temp1, SM_ORDER);
+
+ /* All clear */
+ gcry_mpi_release(r);
+ gcry_mpi_release(temp1);
+ gcry_mpi_release(temp2);
+ return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+/*
+ * Verify a proof of knowledge of logs with exponents being equal
+ */
+static gcry_error_t otrl_sm_check_equal_logs(const gcry_mpi_t c, const gcry_mpi_t d, const gcry_mpi_t r, const OtrlSMState *state, int version)
+{
+ gcry_mpi_t temp1 = gcry_mpi_new(SM_MOD_LEN_BITS);
+ gcry_mpi_t temp2 = gcry_mpi_new(SM_MOD_LEN_BITS);
+ gcry_mpi_t temp3 = gcry_mpi_new(SM_MOD_LEN_BITS);
+ gcry_mpi_t cprime = NULL;
+
+ /* Here, we recall the exponents used to create g3.
+ * If we have previously seen g3o = g1^x where x is unknown
+ * during the DH exchange to produce g3, then we may proceed with:
+ *
+ * To verify, we test that hash(g1^d * g3o^c, qab^d * r^c) = c
+ * If indeed c = hash(g1^r1, qab^r1), d = r1- x * c
+ * And if indeed r = qab^x
+ * Then we should have that:
+ * hash(g1^d * g3o^c, qab^d r^c)
+ * = hash(g1^(r1 - x*c + x*c), qab^(r1 - x*c + x*c))
+ * = hash(g1^r1, qab^r1)
+ * = c
+ */
+ gcry_mpi_powm(temp2, state->g1, d, SM_MODULUS);
+ gcry_mpi_powm(temp3, state->g3o, c, SM_MODULUS);
+ gcry_mpi_mulm(temp1, temp2, temp3, SM_MODULUS);
+
+ gcry_mpi_powm(temp3, state->qab, d, SM_MODULUS);
+ gcry_mpi_powm(temp2, r, c, SM_MODULUS);
+ gcry_mpi_mulm(temp2, temp3, temp2, SM_MODULUS);
+
+ otrl_sm_hash(&cprime, version, temp1, temp2);
+
+ int comp = gcry_mpi_cmp(c, cprime);
+ gcry_mpi_release(temp1);
+ gcry_mpi_release(temp2);
+ gcry_mpi_release(temp3);
+ gcry_mpi_release(cprime);
+
+ return comp;
+}
+
+/* Create first message in SMP exchange. Input is Alice's secret value
+ * which this protocol aims to compare to Bob's. Output is a serialized
+ * mpi array whose elements correspond to the following:
+ * [0] = g2a, Alice's half of DH exchange to determine g2
+ * [1] = c2, [2] = d2, Alice's ZK proof of knowledge of g2a exponent
+ * [3] = g3a, Alice's half of DH exchange to determine g3
+ * [4] = c3, [5] = d3, Alice's ZK proof of knowledge of g3a exponent */
+gcry_error_t otrl_sm_step1(OtrlSMAliceState *astate,
+ const unsigned char* secret, int secretlen,
+ unsigned char** output, int* outputlen)
+{
+ /* Initialize the sm state or update the secret */
+ gcry_mpi_t secret_mpi = NULL;
+ gcry_mpi_scan(&secret_mpi, GCRYMPI_FMT_USG, secret, secretlen, NULL);
+
+ if (! astate->g1) {
+ otrl_sm_state_init(astate);
+ }
+ gcry_mpi_set(astate->secret, secret_mpi);
+ gcry_mpi_release(secret_mpi);
+
+ gcry_mpi_t *msg1;
+ otrl_sm_msg1_init(&msg1);
+
+ astate->x2 = randomExponent();
+ astate->x3 = randomExponent();
+
+ gcry_mpi_powm(msg1[0], astate->g1, astate->x2, SM_MODULUS);
+ otrl_sm_proof_know_log(&(msg1[1]), &(msg1[2]), astate->g1, astate->x2, 1);
+
+ gcry_mpi_powm(msg1[3], astate->g1, astate->x3, SM_MODULUS);
+ otrl_sm_proof_know_log(&(msg1[4]), &(msg1[5]), astate->g1, astate->x3, 2);
+
+ serialize_mpi_array(output, outputlen, SM_MSG1_LEN, msg1);
+ otrl_sm_msg_free(&msg1, SM_MSG1_LEN);
+ return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+/* Receive the first message in SMP exchange, which was generated by
+ * otrl_sm_step1. Input is saved until the user inputs their secret
+ * information. No output. */
+gcry_error_t otrl_sm_step2a(OtrlSMBobState *bstate, const unsigned char* input, const int inputlen)
+{
+ gcry_mpi_t *msg1;
+ gcry_error_t err;
+
+ /* Initialize the sm state if needed */
+ if (! bstate->g1) {
+ otrl_sm_state_init(bstate);
+ }
+
+ /* Read from input to find the mpis */
+ err = unserialize_mpi_array(&msg1, SM_MSG1_LEN, input, inputlen);
+
+ if (err != gcry_error(GPG_ERR_NO_ERROR)) return err;
+
+ if (check_group_elem(msg1[0]) || check_expon(msg1[2]) ||
+ check_group_elem(msg1[3]) || check_expon(msg1[5])) {
+ return gcry_error(GPG_ERR_INV_VALUE);
+ }
+
+ /* Store Alice's g3a value for later in the protocol */
+ gcry_mpi_set(bstate->g3o, msg1[3]);
+
+ /* Verify Alice's proofs */
+ if (otrl_sm_check_know_log(msg1[1], msg1[2], bstate->g1, msg1[0], 1) ||
+ otrl_sm_check_know_log(msg1[4], msg1[5], bstate->g1, msg1[3], 2)) {
+ return gcry_error(GPG_ERR_INV_VALUE);
+ }
+
+ /* Create Bob's half of the generators g2 and g3 */
+ bstate->x2 = randomExponent();
+ bstate->x3 = randomExponent();
+
+ /* Combine the two halves from Bob and Alice and determine g2 and g3 */
+ gcry_mpi_powm(bstate->g2, msg1[0], bstate->x2, SM_MODULUS);
+ gcry_mpi_powm(bstate->g3, msg1[3], bstate->x3, SM_MODULUS);
+
+ return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+/* Create second message in SMP exchange. Input is Bob's secret value.
+ * Information from earlier steps in the exchange is taken from Bob's
+ * state. Output is a serialized mpi array whose elements correspond
+ * to the following:
+ * [0] = g2b, Bob's half of DH exchange to determine g2
+ * [1] = c2, [2] = d2, Bob's ZK proof of knowledge of g2b exponent
+ * [3] = g3b, Bob's half of DH exchange to determine g3
+ * [4] = c3, [5] = d3, Bob's ZK proof of knowledge of g3b exponent
+ * [6] = pb, [7] = qb, Bob's halves of the (Pa/Pb) and (Qa/Qb) values
+ * [8] = cp, [9] = d5, [10] = d6, Bob's ZK proof that pb, qb formed correctly */
+gcry_error_t otrl_sm_step2b(OtrlSMBobState *bstate, const unsigned char* secret, int secretlen, unsigned char **output, int* outputlen)
+{
+ /* Convert the given secret to the proper form and store it */
+ gcry_mpi_t *msg2;
+ gcry_mpi_t secret_mpi = NULL;
+ gcry_mpi_scan(&secret_mpi, GCRYMPI_FMT_USG, secret, secretlen, NULL);
+ gcry_mpi_set(bstate->secret, secret_mpi);
+ gcry_mpi_release(secret_mpi);
+
+ otrl_sm_msg2_init(&msg2);
+
+ gcry_mpi_powm(msg2[0], bstate->g1, bstate->x2, SM_MODULUS);
+ otrl_sm_proof_know_log(&(msg2[1]), &(msg2[2]), bstate->g1, bstate->x2, 3);
+
+ gcry_mpi_powm(msg2[3], bstate->g1, bstate->x3, SM_MODULUS);
+ otrl_sm_proof_know_log(&(msg2[4]), &(msg2[5]), bstate->g1, bstate->x3, 4);
+
+ /* Calculate P and Q values for Bob */
+ gcry_mpi_t r = randomExponent();
+ gcry_mpi_t qb1 = gcry_mpi_new(SM_MOD_LEN_BITS);
+ gcry_mpi_t qb2 = gcry_mpi_new(SM_MOD_LEN_BITS);
+ gcry_mpi_powm(bstate->p, bstate->g3, r, SM_MODULUS);
+ gcry_mpi_set(msg2[6], bstate->p);
+ gcry_mpi_powm(qb1, bstate->g1, r, SM_MODULUS);
+ gcry_mpi_powm(qb2, bstate->g2, bstate->secret, SM_MODULUS);
+ gcry_mpi_mulm(bstate->q, qb1, qb2, SM_MODULUS);
+ gcry_mpi_set(msg2[7], bstate->q);
+
+ otrl_sm_proof_equal_coords(&(msg2[8]), &(msg2[9]), &(msg2[10]), bstate, r, 5);
+
+ /* Convert to serialized form */
+ serialize_mpi_array(output, outputlen, SM_MSG2_LEN, msg2);
+
+ /* Free up memory for unserialized and intermediate values */
+ gcry_mpi_release(r);
+ gcry_mpi_release(qb1);
+ gcry_mpi_release(qb2);
+ otrl_sm_msg_free(&msg2, SM_MSG2_LEN);
+
+ return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+/* Create third message in SMP exchange. Input is a message generated
+ * by otrl_sm_step2b. Output is a serialized mpi array whose elements
+ * correspond to the following:
+ * [0] = pa, [1] = qa, Alice's halves of the (Pa/Pb) and (Qa/Qb) values
+ * [2] = cp, [3] = d5, [4] = d6, Alice's ZK proof that pa, qa formed correctly
+ * [5] = ra, calculated as (Qa/Qb)^x3 where x3 is the exponent used in g3a
+ * [6] = cr, [7] = d7, Alice's ZK proof that ra is formed correctly */
+gcry_error_t otrl_sm_step3(OtrlSMAliceState *astate, const unsigned char* input, const int inputlen, unsigned char **output, int* outputlen)
+{
+ /* Read from input to find the mpis */
+ gcry_mpi_t *msg2;
+ gcry_mpi_t *msg3;
+ gcry_error_t err;
+ err = unserialize_mpi_array(&msg2, SM_MSG2_LEN, input, inputlen);
+
+ if (err != gcry_error(GPG_ERR_NO_ERROR)) return err;
+
+ if (check_group_elem(msg2[0]) || check_group_elem(msg2[3]) ||
+ check_group_elem(msg2[6]) || check_group_elem(msg2[7]) ||
+ check_expon(msg2[2]) || check_expon(msg2[5]) ||
+ check_expon(msg2[9]) || check_expon(msg2[10])) {
+ return gcry_error(GPG_ERR_INV_VALUE);
+ }
+
+ otrl_sm_msg3_init(&msg3);
+
+ /* Store Bob's g3a value for later in the protocol */
+ gcry_mpi_set(astate->g3o, msg2[3]);
+
+ /* Verify Bob's knowledge of discreet log proofs */
+ if (otrl_sm_check_know_log(msg2[1], msg2[2], astate->g1, msg2[0], 3) ||
+ otrl_sm_check_know_log(msg2[4], msg2[5], astate->g1, msg2[3], 4)) {
+ return gcry_error(GPG_ERR_INV_VALUE);
+ }
+
+ /* Combine the two halves from Bob and Alice and determine g2 and g3 */
+ gcry_mpi_powm(astate->g2, msg2[0], astate->x2, SM_MODULUS);
+ gcry_mpi_powm(astate->g3, msg2[3], astate->x3, SM_MODULUS);
+
+ /* Verify Bob's coordinate equality proof */
+ if (otrl_sm_check_equal_coords(msg2[8], msg2[9], msg2[10], msg2[6], msg2[7], astate, 5))
+ return gcry_error(GPG_ERR_INV_VALUE);
+
+ /* Calculate P and Q values for Alice */
+ gcry_mpi_t r = randomExponent();
+ gcry_mpi_t qa1 = gcry_mpi_new(SM_MOD_LEN_BITS);
+ gcry_mpi_t qa2 = gcry_mpi_new(SM_MOD_LEN_BITS);
+ gcry_mpi_powm(astate->p, astate->g3, r, SM_MODULUS);
+ gcry_mpi_set(msg3[0], astate->p);
+ gcry_mpi_powm(qa1, astate->g1, r, SM_MODULUS);
+ gcry_mpi_powm(qa2, astate->g2, astate->secret, SM_MODULUS);
+ gcry_mpi_mulm(astate->q, qa1, qa2, SM_MODULUS);
+ gcry_mpi_set(msg3[1], astate->q);
+
+ otrl_sm_proof_equal_coords(&(msg3[2]), &(msg3[3]), &(msg3[4]), astate, r, 6);
+
+ /* Calculate Ra and proof */
+ gcry_mpi_t inv = gcry_mpi_new(SM_MOD_LEN_BITS);
+ gcry_mpi_invm(inv, msg2[6], SM_MODULUS);
+ gcry_mpi_mulm(astate->pab, astate->p, inv, SM_MODULUS);
+ gcry_mpi_invm(inv, msg2[7], SM_MODULUS);
+ gcry_mpi_mulm(astate->qab, astate->q, inv, SM_MODULUS);
+ gcry_mpi_powm(msg3[5], astate->qab, astate->x3, SM_MODULUS);
+ otrl_sm_proof_equal_logs(&(msg3[6]), &(msg3[7]), astate, 7);
+
+ serialize_mpi_array(output, outputlen, SM_MSG3_LEN, msg3);
+ otrl_sm_msg_free(&msg2, SM_MSG2_LEN);
+ otrl_sm_msg_free(&msg3, SM_MSG3_LEN);
+
+ gcry_mpi_release(r);
+ gcry_mpi_release(qa1);
+ gcry_mpi_release(qa2);
+ gcry_mpi_release(inv);
+
+ return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+/* Create final message in SMP exchange. Input is a message generated
+ * by otrl_sm_step3. Output is a serialized mpi array whose elements
+ * correspond to the following:
+ * [0] = rb, calculated as (Qa/Qb)^x3 where x3 is the exponent used in g3b
+ * [1] = cr, [2] = d7, Bob's ZK proof that rb is formed correctly
+ * This method also checks if Alice and Bob's secrets were the same. If
+ * so, it returns NO_ERROR. If the secrets differ, an INV_VALUE error is
+ * returned instead. */
+gcry_error_t otrl_sm_step4(OtrlSMBobState *bstate, const unsigned char* input, const int inputlen, unsigned char **output, int* outputlen)
+{
+ /* Read from input to find the mpis */
+ gcry_mpi_t *msg3;
+ gcry_mpi_t *msg4;
+ gcry_error_t err;
+ err = unserialize_mpi_array(&msg3, SM_MSG3_LEN, input, inputlen);
+
+ if (err != gcry_error(GPG_ERR_NO_ERROR)) return err;
+
+ otrl_sm_msg4_init(&msg4);
+
+ if (check_group_elem(msg3[0]) || check_group_elem(msg3[1]) ||
+ check_group_elem(msg3[5]) || check_expon(msg3[3]) ||
+ check_expon(msg3[4]) || check_expon(msg3[7])) {
+ return gcry_error(GPG_ERR_INV_VALUE);
+ }
+
+ /* Verify Alice's coordinate equality proof */
+ if (otrl_sm_check_equal_coords(msg3[2], msg3[3], msg3[4], msg3[0], msg3[1], bstate, 6))
+ return gcry_error(GPG_ERR_INV_VALUE);
+
+ /* Find Pa/Pb and Qa/Qb */
+ gcry_mpi_t inv = gcry_mpi_new(SM_MOD_LEN_BITS);
+ gcry_mpi_invm(inv, bstate->p, SM_MODULUS);
+ gcry_mpi_mulm(bstate->pab, msg3[0], inv, SM_MODULUS);
+ gcry_mpi_invm(inv, bstate->q, SM_MODULUS);
+ gcry_mpi_mulm(bstate->qab, msg3[1], inv, SM_MODULUS);
+
+ /* Verify Alice's log equality proof */
+ if (otrl_sm_check_equal_logs(msg3[6], msg3[7], msg3[5], bstate, 7))
+ return gcry_error(GPG_ERR_INV_VALUE);
+
+ /* Calculate Rb and proof */
+ gcry_mpi_powm(msg4[0], bstate->qab, bstate->x3, SM_MODULUS);
+ otrl_sm_proof_equal_logs(&(msg4[1]), &(msg4[2]), bstate, 8);
+
+ serialize_mpi_array(output, outputlen, SM_MSG4_LEN, msg4);
+
+ /* Calculate Rab and verify that secrets match */
+ gcry_mpi_t rab = gcry_mpi_new(SM_MOD_LEN_BITS);
+ gcry_mpi_powm(rab, msg3[5], bstate->x3, SM_MODULUS);
+ int comp = gcry_mpi_cmp(rab, bstate->pab);
+
+ /* Clean up everything allocated in this step */
+ otrl_sm_msg_free(&msg3, SM_MSG3_LEN);
+ otrl_sm_msg_free(&msg4, SM_MSG4_LEN);
+ gcry_mpi_release(rab);
+ gcry_mpi_release(inv);
+
+ if (comp)
+ return gcry_error(GPG_ERR_INV_VALUE);
+ else
+ return gcry_error(GPG_ERR_NO_ERROR);
+}
+
+/* Receives the final SMP message, which was generated in otrl_sm_step.
+ * This method checks if Alice and Bob's secrets were the same. If
+ * so, it returns NO_ERROR. If the secrets differ, an INV_VALUE error is
+ * returned instead. */
+gcry_error_t otrl_sm_step5(OtrlSMAliceState *astate, const unsigned char* input, const int inputlen)
+{
+ /* Read from input to find the mpis */
+ gcry_mpi_t *msg4;
+ gcry_error_t err;
+ err = unserialize_mpi_array(&msg4, SM_MSG4_LEN, input, inputlen);
+
+ if (err != gcry_error(GPG_ERR_NO_ERROR)) return err;
+
+ if (check_group_elem(msg4[0]) || check_expon(msg4[2])) {
+ return gcry_error(GPG_ERR_INV_VALUE);
+ }
+
+ /* Verify Bob's log equality proof */
+ if (otrl_sm_check_equal_logs(msg4[1], msg4[2], msg4[0], astate, 8))
+ return gcry_error(GPG_ERR_INV_VALUE);
+
+ /* Calculate Rab and verify that secrets match */
+ gcry_mpi_t rab = gcry_mpi_new(SM_MOD_LEN_BITS);
+ gcry_mpi_powm(rab, msg4[0], astate->x3, SM_MODULUS);
+
+ int comp = gcry_mpi_cmp(rab, astate->pab);
+ gcry_mpi_release(rab);
+ otrl_sm_msg_free(&msg4, SM_MSG4_LEN);
+
+ if (comp)
+ return gcry_error(GPG_ERR_INV_VALUE);
+ else
+ return gcry_error(GPG_ERR_NO_ERROR);
+}
diff --git a/src/sm.h b/src/sm.h
new file mode 100644
index 0000000..10737c6
--- /dev/null
+++ b/src/sm.h
@@ -0,0 +1,74 @@
+/*
+ * Off-the-Record Messaging library
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
+ * <otr at cypherpunks.ca>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of version 2.1 of the GNU Lesser General
+ * Public License as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __SM_H__
+#define __SM_H__
+
+#include <gcrypt.h>
+
+#define SM_HASH_ALGORITHM GCRY_MD_SHA256
+#define SM_DIGEST_SIZE 32
+
+typedef enum {
+ OTRL_SMP_EXPECT1,
+ OTRL_SMP_EXPECT2,
+ OTRL_SMP_EXPECT3,
+ OTRL_SMP_EXPECT4,
+ OTRL_SMP_EXPECT5
+} NextExpectedSMP;
+
+typedef struct {
+ gcry_mpi_t secret, x2, x3, g1, g2, g3, g3o, p, q, pab, qab;
+ NextExpectedSMP nextExpected;
+} OtrlSMState;
+
+typedef OtrlSMState OtrlSMAliceState;
+typedef OtrlSMState OtrlSMBobState;
+
+/*
+ * Call this once, at plugin load time. It sets up the modulus and
+ * generator MPIs.
+ */
+void otrl_sm_init(void);
+
+/*
+ * Initialize the fields of a SM state.
+ */
+void otrl_sm_state_new(OtrlSMState *smst);
+
+/*
+ * Initialize the fields of a SM state. Called the first time that
+ * a user begins an SMP session.
+ */
+void otrl_sm_state_init(OtrlSMState *smst);
+
+/*
+ * Deallocate the contents of a OtrlSMState (but not the OtrlSMState
+ * itself)
+ */
+void otrl_sm_state_free(OtrlSMState *smst);
+
+gcry_error_t otrl_sm_step1(OtrlSMAliceState *astate, const unsigned char* secret, int secretlen, unsigned char** output, int* outputlen);
+gcry_error_t otrl_sm_step2a(OtrlSMBobState *bstate, const unsigned char* input, const int inputlen);
+gcry_error_t otrl_sm_step2b(OtrlSMBobState *bstate, const unsigned char* secret, int secretlen, unsigned char **output, int* outputlen);
+gcry_error_t otrl_sm_step3(OtrlSMAliceState *astate, const unsigned char* input, const int inputlen, unsigned char **output, int* outputlen);
+gcry_error_t otrl_sm_step4(OtrlSMBobState *bstate, const unsigned char* input, const int inputlen, unsigned char **output, int* outputlen);
+gcry_error_t otrl_sm_step5(OtrlSMAliceState *astate, const unsigned char* input, const int inputlen);
+
+#endif
diff --git a/src/tlv.c b/src/tlv.c
index d840ad1..efa280e 100644
--- a/src/tlv.c
+++ b/src/tlv.c
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging library
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This library is free software; you can redistribute it and/or
diff --git a/src/tlv.h b/src/tlv.h
index ee30370..a378b9d 100644
--- a/src/tlv.h
+++ b/src/tlv.h
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging library
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This library is free software; you can redistribute it and/or
@@ -35,6 +35,12 @@ typedef struct s_OtrlTLV {
/* The sender has thrown away his OTR session keys with you */
#define OTRL_TLV_DISCONNECTED 0x0001
+/* The message contains a step in the Socialist Millionaires' Protocol. */
+#define OTRL_TLV_SMP1 0x0002
+#define OTRL_TLV_SMP2 0x0003
+#define OTRL_TLV_SMP3 0x0004
+#define OTRL_TLV_SMP4 0x0005
+#define OTRL_TLV_SMP_ABORT 0x0006
/* Make a single TLV, copying the supplied data */
OtrlTLV *otrl_tlv_new(unsigned short type, unsigned short len,
diff --git a/src/userstate.c b/src/userstate.c
index c6f6cf3..df9e191 100644
--- a/src/userstate.c
+++ b/src/userstate.c
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging library
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This library is free software; you can redistribute it and/or
diff --git a/src/userstate.h b/src/userstate.h
index 2a69376..157005d 100644
--- a/src/userstate.h
+++ b/src/userstate.h
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging library
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This library is free software; you can redistribute it and/or
diff --git a/src/version.h b/src/version.h
index 77187c1..01b4f38 100644
--- a/src/version.h
+++ b/src/version.h
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging library
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This library is free software; you can redistribute it and/or
@@ -20,10 +20,10 @@
#ifndef __VERSION_H__
#define __VERSION_H__
-#define OTRL_VERSION "3.0.0"
+#define OTRL_VERSION "3.1.0"
#define OTRL_VERSION_MAJOR 3
-#define OTRL_VERSION_MINOR 0
+#define OTRL_VERSION_MINOR 1
#define OTRL_VERSION_SUB 0
#endif
diff --git a/toolkit/ctrmode.c b/toolkit/ctrmode.c
index f2fa1a2..9c79e04 100644
--- a/toolkit/ctrmode.c
+++ b/toolkit/ctrmode.c
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging Toolkit
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This program is free software; you can redistribute it and/or modify
@@ -27,7 +27,7 @@
/* Encrypt or decrypt data in AES-CTR mode. (The operations are the
* same.) We roll our own here just to double-check that the calls
* libotr makes to libgcrypt are doing the right thing. */
-void aes_ctr_crypt(unsigned char *out, unsigned char *in, size_t len,
+void aes_ctr_crypt(unsigned char *out, const unsigned char *in, size_t len,
unsigned char key[16], unsigned char ctrtop[8])
{
unsigned char ctr[16], encctr[16];
diff --git a/toolkit/ctrmode.h b/toolkit/ctrmode.h
index b74f98b..a7a8303 100644
--- a/toolkit/ctrmode.h
+++ b/toolkit/ctrmode.h
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging Toolkit
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This program is free software; you can redistribute it and/or modify
@@ -23,7 +23,7 @@
/* Encrypt or decrypt data in AES-CTR mode. (The operations are the
* same.) We roll our own here just to double-check that the calls
* libotr makes to libgcrypt are doing the right thing. */
-void aes_ctr_crypt(unsigned char *out, unsigned char *in, size_t len,
+void aes_ctr_crypt(unsigned char *out, const unsigned char *in, size_t len,
unsigned char key[16], unsigned char ctrtop[8]);
#endif
diff --git a/toolkit/otr_mackey.c b/toolkit/otr_mackey.c
index e73c94d..bb79e30 100644
--- a/toolkit/otr_mackey.c
+++ b/toolkit/otr_mackey.c
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging Toolkit
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This program is free software; you can redistribute it and/or modify
diff --git a/toolkit/otr_modify.c b/toolkit/otr_modify.c
index 776889e..2ac225c 100644
--- a/toolkit/otr_modify.c
+++ b/toolkit/otr_modify.c
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging Toolkit
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This program is free software; you can redistribute it and/or modify
@@ -75,8 +75,8 @@ int main(int argc, char **argv)
"length.\n");
usage(argv[0]);
}
- old_text = argv[2];
- new_text = argv[3];
+ old_text = (const unsigned char *)argv[2];
+ new_text = (const unsigned char *)argv[3];
if (sscanf(argv[4], "%u", &offset) != 1) {
fprintf(stderr, "Unparseable offset given.\n");
diff --git a/toolkit/otr_parse.c b/toolkit/otr_parse.c
index afdac72..348282f 100644
--- a/toolkit/otr_parse.c
+++ b/toolkit/otr_parse.c
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging Toolkit
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This program is free software; you can redistribute it and/or modify
diff --git a/toolkit/otr_readforge.c b/toolkit/otr_readforge.c
index edf4b07..1eae299 100644
--- a/toolkit/otr_readforge.c
+++ b/toolkit/otr_readforge.c
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging Toolkit
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This program is free software; you can redistribute it and/or modify
@@ -114,7 +114,8 @@ int main(int argc, char **argv)
fprintf(stderr, "Out of memory!\n");
exit(1);
}
- aes_ctr_crypt(ciphertext, argv[2], newlen, aeskey, datamsg->ctr);
+ aes_ctr_crypt(ciphertext, (const unsigned char *)argv[2], newlen,
+ aeskey, datamsg->ctr);
free(datamsg->encmsg);
datamsg->encmsg = ciphertext;
datamsg->encmsglen = newlen;
diff --git a/toolkit/otr_remac.c b/toolkit/otr_remac.c
index 0ffe90b..0d4c457 100644
--- a/toolkit/otr_remac.c
+++ b/toolkit/otr_remac.c
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging Toolkit
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This program is free software; you can redistribute it and/or modify
diff --git a/toolkit/otr_sesskeys.c b/toolkit/otr_sesskeys.c
index f28fd91..656e791 100644
--- a/toolkit/otr_sesskeys.c
+++ b/toolkit/otr_sesskeys.c
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging Toolkit
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This program is free software; you can redistribute it and/or modify
diff --git a/toolkit/parse.c b/toolkit/parse.c
index e07c86a..f048530 100644
--- a/toolkit/parse.c
+++ b/toolkit/parse.c
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging Toolkit
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This program is free software; you can redistribute it and/or modify
@@ -38,7 +38,7 @@ void dump_int(FILE *stream, const char *title, unsigned int val)
void dump_mpi(FILE *stream, const char *title, gcry_mpi_t val)
{
size_t plen;
- char *d;
+ unsigned char *d;
gcry_mpi_print(GCRYMPI_FMT_USG, NULL, 0, &plen, val);
d = malloc(plen);
diff --git a/toolkit/parse.h b/toolkit/parse.h
index 1db65bc..171888e 100644
--- a/toolkit/parse.h
+++ b/toolkit/parse.h
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging Toolkit
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This program is free software; you can redistribute it and/or modify
diff --git a/toolkit/readotr.c b/toolkit/readotr.c
index 03927f3..f6ff00b 100644
--- a/toolkit/readotr.c
+++ b/toolkit/readotr.c
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging Toolkit
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This program is free software; you can redistribute it and/or modify
diff --git a/toolkit/readotr.h b/toolkit/readotr.h
index a0c5763..90144b8 100644
--- a/toolkit/readotr.h
+++ b/toolkit/readotr.h
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging Toolkit
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This program is free software; you can redistribute it and/or modify
diff --git a/toolkit/sesskeys.c b/toolkit/sesskeys.c
index 17acaa3..d41b77a 100644
--- a/toolkit/sesskeys.c
+++ b/toolkit/sesskeys.c
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging Toolkit
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This program is free software; you can redistribute it and/or modify
diff --git a/toolkit/sesskeys.h b/toolkit/sesskeys.h
index 7a16061..0a09e45 100644
--- a/toolkit/sesskeys.h
+++ b/toolkit/sesskeys.h
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging Toolkit
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This program is free software; you can redistribute it and/or modify
diff --git a/toolkit/sha1hmac.c b/toolkit/sha1hmac.c
index 871337e..ec54b3e 100644
--- a/toolkit/sha1hmac.c
+++ b/toolkit/sha1hmac.c
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging Toolkit
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This program is free software; you can redistribute it and/or modify
diff --git a/toolkit/sha1hmac.h b/toolkit/sha1hmac.h
index 47e57b3..ce44487 100644
--- a/toolkit/sha1hmac.h
+++ b/toolkit/sha1hmac.h
@@ -1,6 +1,6 @@
/*
* Off-the-Record Messaging Toolkit
- * Copyright (C) 2004-2005 Nikita Borisov and Ian Goldberg
+ * Copyright (C) 2004-2007 Ian Goldberg, Chris Alexander, Nikita Borisov
* <otr at cypherpunks.ca>
*
* This program is free software; you can redistribute it and/or modify
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-privacy/packages/libotr.git
More information about the Pkg-privacy-commits
mailing list