chiark / gitweb /
EAX: provide an implementation of EAX
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Thu, 25 Jul 2013 17:30:48 +0000 (18:30 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Thu, 25 Jul 2013 17:30:48 +0000 (18:30 +0100)
EAX is a reasonably well-regarded Authenticated Encryption block
cipher mode.  We intend to replace the existing CBC and CBC-MAC
transform with EAX.  EAX can be used with any block cipher, but we
will use it with Serpent.

In this patch we provide an implementation of EAX itself.

This primary consists of eax.c, the actual implementation of the EAX
mode.

To test that our implementation is correct, we use aes.[ch], which we
copied from qemu in the previous commit, to run the EAX-AES test
vectors.  These are cut-and-pasted out of the EAX paper.

(To do this we need to make aes.[ch] compile in our environment - but
the changes are minimal.  We also improve the copyright notices.)

Then for completeness we also provide EAX-Serpent and EAX-Serpent-BE
test vectors and the corresponding test code.  The EAX-Serpent test
vectors are from Mark Wooding.  The EAX-SerpentBE test vectors were
generated by this very code, so aren't independently verified.

(The implementation of what is now consttime_curious_multiply, and the
comment preeding it, was provided by Mark.  I have lightly edited it
to conform to the coding style etc. of the rest of the file.  Mark
also contributed improvements to alg_omac_t_k.)

Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
Signed-off-by: Mark Wooding <mdw@distorted.org.uk>
13 files changed:
.gitignore
Makefile.in
aes.c
aes.h
eax-aes-test.c [new file with mode: 0644]
eax-aes-test.vectors [new file with mode: 0644]
eax-serpent-test.c [new file with mode: 0644]
eax-serpent-test.vectors [new file with mode: 0644]
eax-serpentbe-test.c [new file with mode: 0644]
eax-serpentbe-test.vectors [new file with mode: 0644]
eax-test.c [new file with mode: 0644]
eax-test.h [new file with mode: 0644]
eax.c [new file with mode: 0644]

index b7f6187..a445369 100644 (file)
@@ -5,6 +5,8 @@ conffile.tab.[ch]
 conffile.yy.[ch]
 /version.c
 /secnet
+/eax-*-test
+/eax-*-test.confirm
 
 /config.log
 /config.h
index d4d3815..3f15f01 100644 (file)
@@ -58,6 +58,9 @@ OBJECTS:=secnet.o util.o conffile.yy.o conffile.tab.o conffile.o modules.o \
        process.o @LIBOBJS@ \
        hackypar.o
 
+TEST_OBJECTS:=eax-aes-test.o eax-serpent-test.o eax-serpentbe-test.o \
+               eax-test.o aes.o
+
 %.c:   %.y
 
 %.yy.c:        %.fl
@@ -69,7 +72,7 @@ OBJECTS:=secnet.o util.o conffile.yy.o conffile.tab.o conffile.o modules.o \
 %.o: %.c
        $(CC) $(CPPFLAGS) $(ALL_CFLAGS) -c $< -o $@
 
-all:   $(TARGETS)
+all:   $(TARGETS) check
 
 # Automatic remaking of configuration files, from autoconf documentation
 ${srcdir}/configure: configure.in
@@ -93,8 +96,8 @@ config.status: configure
 # End of config file remaking rules
 
 # C and header file dependency rules
-SOURCES:=$(OBJECTS:.o=.c)
-DEPENDS:=$(OBJECTS:.o=.d)
+SOURCES:=$(OBJECTS:.o=.c) $(TEST_OBJECTS:.o=.c)
+DEPENDS:=$(OBJECTS:.o=.d) $(TEST_OBJECTS:.o=.d)
 
 $(DEPENDS): ${srcdir}/depend.sh
 
@@ -112,11 +115,23 @@ conffile.tab.c:   conffile.y
 secnet:        $(OBJECTS)
        $(CC) $(LDFLAGS) $(ALL_CFLAGS) -o $@ $(OBJECTS) $(LDLIBS)
 
+check: eax-aes-test.confirm eax-serpent-test.confirm \
+       eax-serpentbe-test.confirm
+
 version.c: Makefile
        echo "#include \"secnet.h\"" >$@.new
        echo "char version[]=\"secnet $(VERSION)\";" >>$@.new
        mv -f $@.new $@
 
+eax-%-test: eax-%-test.o eax-test.o %.o
+       $(CC) $(LDFLAGS) $(ALL_CFLAGS) -o $@ $^
+
+eax-%-test.confirm: eax-%-test eax-%-test.vectors
+       ./$< <$(srcdir)/eax-$*-test.vectors >$@.new
+       mv -f $@.new $@
+
+.PRECIOUS: eax-%-test
+
 installdirs:
        $(INSTALL) -d $(prefix)/share/secnet $(sbindir)
        $(INSTALL) -d $(mandir)/man8
@@ -129,7 +144,7 @@ install: installdirs
 
 clean:
        $(RM) -f *.o *.yy.c *.tab.[ch] $(TARGETS) core version.c
-       $(RM) -f *.d *~
+       $(RM) -f *.d *~ eax-*-test.confirm eax-*-test
 
 realclean:     clean
        $(RM) -f *~ Makefile config.h  *.d \
diff --git a/aes.c b/aes.c
index eb37adb..4e155ab 100644 (file)
--- a/aes.c
+++ b/aes.c
@@ -1,6 +1,10 @@
 /**
  *
  * aes.c - integrated in QEMU by Fabrice Bellard from the OpenSSL project.
+ *
+ * Copied to the secnet tree by Ian Jackson from the upstream qemu git
+ * tree revision 55616505876d6683130076b810a27c7889321560
+ * and modified only to remove the include of qemu-common.h.
  */
 /*
  * rijndael-alg-fst.c
@@ -27,7 +31,6 @@
  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
-#include "qemu-common.h"
 #include "aes.h"
 
 #ifndef NDEBUG
diff --git a/aes.h b/aes.h
index a0167eb..fc69356 100644 (file)
--- a/aes.h
+++ b/aes.h
@@ -1,5 +1,58 @@
-#ifndef QEMU_AES_H
-#define QEMU_AES_H
+/*
+  * aes.h
+  *
+  * Header file declaring AES functions.
+  *
+  * Copied from the upstream qemu git tree revision
+  *   55616505876d6683130076b810a27c7889321560
+  * but was introduced there by Fabrice Bellard in
+  *   e4d4fe3c34cdd6e26f9b9975efec7d1e81ad00b6
+  *   AES crypto support
+  *   git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1036 \
+  *     c046a42c-6fe2-441c-8c8c-71466251a162
+  *
+  * Modified by Ian Jackson to change the guard #define from
+  * QEMU_AES_H to AES_H and to add some needed system #include's.
+  *
+  * The header file doesn't appear to have a separate copyright notice
+  * but is clearly a lightly edited (by Bellard) version of code from
+  * Rijmen, Bosselaers and Barreto.
+  *
+  * The original is from rijndael-alg-fst.c, with this copyright
+  * notice:
+  *
+  *   rijndael-alg-fst.c
+  *   
+  *   @version 3.0 (December 2000)
+  *   
+  *   Optimised ANSI C code for the Rijndael cipher (now AES)
+  *   
+  *   @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
+  *   @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
+  *   @author Paulo Barreto <paulo.barreto@terra.com.br>
+  *   
+  *   This code is hereby placed in the public domain.
+  *   
+  *   THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
+  *   OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+  *   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+  *   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+  *   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+  *   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+  *   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+  *   BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+  *   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+  *   OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+  *   EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+  *
+  */
+
+#ifndef AES_H
+#define AES_H
+
+#include <stdint.h>
+#include <assert.h>
+#include <string.h>
 
 #define AES_MAXNR 14
 #define AES_BLOCK_SIZE 16
@@ -23,4 +76,4 @@ void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
                     const unsigned long length, const AES_KEY *key,
                     unsigned char *ivec, const int enc);
 
-#endif
+#endif /* AES_H */
diff --git a/eax-aes-test.c b/eax-aes-test.c
new file mode 100644 (file)
index 0000000..d8ad027
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * eax-aes-test.c: test harness glue for EAX-AES (EAX-Rijndael)
+ */
+/*
+ * This file is Free Software.  It was originally written for secnet.
+ *
+ * You may redistribute it and/or modify it under the terms of the GNU
+ * General Public License as published by the Free Software
+ * Foundation; either version 2, or (at your option) any later
+ * version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "eax-test.h"
+#include "aes.h"
+
+#define BLOCK_SIZE AES_BLOCK_SIZE
+static AES_KEY key;
+
+EAX_SOME_TEST;
+
+void eaxtest_blockcipher_key_setup(const uint8_t *keydata, uint8_t bytes)
+{
+    AES_set_encrypt_key(keydata, bytes*8, &key);
+}
+
+static void BLOCK_ENCRYPT(uint8_t dst[BLOCK_SIZE],
+                         const uint8_t src[BLOCK_SIZE])
+{
+    AES_encrypt((const void*)src, (void*)dst, &key);
+}
+
+#include "eax.c"
diff --git a/eax-aes-test.vectors b/eax-aes-test.vectors
new file mode 100644 (file)
index 0000000..f6bf3f4
--- /dev/null
@@ -0,0 +1,59 @@
+MSG:
+KEY:    233952DEE4D5ED5F9B9C6D6FF80FF478
+NONCE:  62EC67F9C3A4A407FCB2A8C49031A8B3
+HEADER: 6BFB914FD07EAE6B
+CIPHER: E037830E8389F27B025A2D6527E79D01
+
+MSG:    F7FB
+KEY:    91945D3F4DCBEE0BF45EF52255F095A4
+NONCE:  BECAF043B0A23D843194BA972C66DEBD
+HEADER: FA3BFD4806EB53FA
+CIPHER: 19DD5C4C9331049D0BDAB0277408F67967E5
+
+MSG:    1A47CB4933
+KEY:    01F74AD64077F2E704C0F60ADA3DD523
+NONCE:  70C3DB4F0D26368400A10ED05D2BFF5E
+HEADER: 234A3463C1264AC6
+CIPHER: D851D5BAE03A59F238A23E39199DC9266626C40F80
+
+MSG:    481C9E39B1
+KEY:    D07CF6CBB7F313BDDE66B727AFD3C5E8
+NONCE:  8408DFFF3C1A2B1292DC199E46B7D617
+HEADER: 33CCE2EABFF5A79D
+CIPHER: 632A9D131AD4C168A4225D8E1FF755939974A7BEDE
+
+MSG:    40D0C07DA5E4
+KEY:    35B6D0580005BBC12B0587124557D2C2
+NONCE:  FDB6B06676EEDC5C61D74276E1F8E816
+HEADER: AEB96EAEBE2970E9
+CIPHER: 071DFE16C675CB0677E536F73AFE6A14B74EE49844DD
+
+MSG:    4DE3B35C3FC039245BD1FB7D
+KEY:    BD8E6E11475E60B268784C38C62FEB22
+NONCE:  6EAC5C93072D8E8513F750935E46DA1B
+HEADER: D4482D1CA78DCE0F
+CIPHER: 835BB4F15D743E350E728414ABB8644FD6CCB86947C5E10590210A4F
+
+MSG:    8B0A79306C9CE7ED99DAE4F87F8DD61636
+KEY:    7C77D6E813BED5AC98BAA417477A2E7D
+NONCE:  1A8C98DCD73D38393B2BF1569DEEFC19
+HEADER: 65D2017990D62528
+CIPHER: 02083E3979DA014812F59F11D52630DA30137327D10649B0AA6E1C181DB617D7F2
+
+MSG:    1BDA122BCE8A8DBAF1877D962B8592DD2D56
+KEY:    5FFF20CAFAB119CA2FC73549E20F5B0D
+NONCE:  DDE59B97D722156D4D9AFF2BC7559826
+HEADER: 54B9F04E6A09189A
+CIPHER: 2EC47B2C4954A489AFC7BA4897EDCDAE8CC33B60450599BD02C96382902AEF7F832A
+
+MSG:    6CF36720872B8513F6EAB1A8A44438D5EF11
+KEY:    A4A4782BCFFD3EC5E7EF6D8C34A56123
+NONCE:  B781FCF2F75FA5A8DE97A9CA48E522EC
+HEADER: 899A175897561D7E
+CIPHER: 0DE18FD0FDD91E7AF19F1D8EE8733938B1E8E7F6D2231618102FDB7FE55FF1991700
+
+MSG:    CA40D7446E545FFAED3BD12A740A659FFBBB3CEAB7
+KEY:    8395FCF1E95BEBD697BD010BC766AAC3
+NONCE:  22E7ADD93CFC6393C57EC0B3C17D6B44
+HEADER: 126735FCC320D25A
+CIPHER: CB8920F87A6C75CFF39627B56E3ED197C552D295A7CFC46AFC253B4652B1AF3795B124AB6E
diff --git a/eax-serpent-test.c b/eax-serpent-test.c
new file mode 100644 (file)
index 0000000..9e8d951
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * eax-serpent-test.c: test harness glue for EAX-Serpent
+ */
+/*
+ * This file is Free Software.  It was originally written for secnet.
+ *
+ * You may redistribute it and/or modify it under the terms of the GNU
+ * General Public License as published by the Free Software
+ * Foundation; either version 2, or (at your option) any later
+ * version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "eax-test.h"
+#include "serpent.h"
+
+#define BLOCK_SIZE 16
+static struct keyInstance key;
+
+EAX_SOME_TEST;
+
+void eaxtest_blockcipher_key_setup(const uint8_t *keydata, uint8_t bytes)
+{
+    serpent_makekey(&key, bytes*8, keydata);
+}
+
+static void BLOCK_ENCRYPT(uint8_t dst[BLOCK_SIZE],
+                         const uint8_t src[BLOCK_SIZE])
+{
+    serpent_encrypt(&key, src, dst);
+}
+
+#include "eax.c"
diff --git a/eax-serpent-test.vectors b/eax-serpent-test.vectors
new file mode 100644 (file)
index 0000000..e016783
--- /dev/null
@@ -0,0 +1,59 @@
+MSG: 
+KEY: 233952DEE4D5ED5F9B9C6D6FF80FF478
+NONCE: 62EC67F9C3A4A407FCB2A8C49031A8B3
+HEADER: 6BFB914FD07EAE6B
+CIPHER: 1271EC1E68330EB461A96D3A3A7A2707
+
+MSG: F7FB
+KEY: 91945D3F4DCBEE0BF45EF52255F095A4
+NONCE: BECAF043B0A23D843194BA972C66DEBD
+HEADER: FA3BFD4806EB53FA
+CIPHER: 1C7367D3DB493A1F7B054ECECA2A2CF37EE6
+
+MSG: 1A47CB4933
+KEY: 01F74AD64077F2E704C0F60ADA3DD523
+NONCE: 70C3DB4F0D26368400A10ED05D2BFF5E
+HEADER: 234A3463C1264AC6
+CIPHER: 2439712B59B13982351BA05B25BB2BD3B95DF62D73
+
+MSG: 481C9E39B1
+KEY: D07CF6CBB7F313BDDE66B727AFD3C5E8
+NONCE: 8408DFFF3C1A2B1292DC199E46B7D617
+HEADER: 33CCE2EABFF5A79D
+CIPHER: F1D718884BE94B29E143A264B54E283CA9E439C90D
+
+MSG: 40D0C07DA5E4
+KEY: 35B6D0580005BBC12B0587124557D2C2
+NONCE: FDB6B06676EEDC5C61D74276E1F8E816
+HEADER: AEB96EAEBE2970E9
+CIPHER: 5936DB85DF31199BA3556A5D5EFF1964A6BEFEA0D950
+
+MSG: 4DE3B35C3FC039245BD1FB7D
+KEY: BD8E6E11475E60B268784C38C62FEB22
+NONCE: 6EAC5C93072D8E8513F750935E46DA1B
+HEADER: D4482D1CA78DCE0F
+CIPHER: 7A3A7997EE349B57152CC43F723903A85B09D86456315AC0D9180724
+
+MSG: 8B0A79306C9CE7ED99DAE4F87F8DD61636
+KEY: 7C77D6E813BED5AC98BAA417477A2E7D
+NONCE: 1A8C98DCD73D38393B2BF1569DEEFC19
+HEADER: 65D2017990D62528
+CIPHER: 73548FFAF45D2617EB25AD1DFFA18420836D48394D5EF2CD2E0E30CDD2F4C52D96
+
+MSG: 1BDA122BCE8A8DBAF1877D962B8592DD2D56
+KEY: 5FFF20CAFAB119CA2FC73549E20F5B0D
+NONCE: DDE59B97D722156D4D9AFF2BC7559826
+HEADER: 54B9F04E6A09189A
+CIPHER: E8BD1C6FE47DF149A141CE813B0C1239542EC4CBF7B3968388D631E6F4FFE86E14E7
+
+MSG: 6CF36720872B8513F6EAB1A8A44438D5EF11
+KEY: A4A4782BCFFD3EC5E7EF6D8C34A56123
+NONCE: B781FCF2F75FA5A8DE97A9CA48E522EC
+HEADER: 899A175897561D7E
+CIPHER: E4A9D72847D437B85F10B7DAA46F1E00E3509AF0B97961C39DFBB70170B6C4CADBC1
+
+MSG: CA40D7446E545FFAED3BD12A740A659FFBBB3CEAB7
+KEY: 8395FCF1E95BEBD697BD010BC766AAC3
+NONCE: 22E7ADD93CFC6393C57EC0B3C17D6B44
+HEADER: 126735FCC320D25A
+CIPHER: 83D69403EAE9386B679DAEAAD2951465F8DDF9BE1AFFAD1C5FEF072F8B48BD58C07FEE3D83
diff --git a/eax-serpentbe-test.c b/eax-serpentbe-test.c
new file mode 100644 (file)
index 0000000..ce5b3dc
--- /dev/null
@@ -0,0 +1,9 @@
+#include "eax-test.h"
+#include "serpent.h"
+/* multiple-inclusion protection means that serpent.h's inclusion
+ * by eax-serpent-test.c is suppressed, so we don't get useless
+ * duplicate declarations of serpentbe_makekey and serpentbe_encrypt
+ */
+#define serpent_makekey serpentbe_makekey
+#define serpent_encrypt serpentbe_encrypt
+#include "eax-serpent-test.c"
diff --git a/eax-serpentbe-test.vectors b/eax-serpentbe-test.vectors
new file mode 100644 (file)
index 0000000..d7e4e6e
--- /dev/null
@@ -0,0 +1,59 @@
+MSG:
+KEY:    233952DEE4D5ED5F9B9C6D6FF80FF478
+NONCE:  62EC67F9C3A4A407FCB2A8C49031A8B3
+HEADER: 6BFB914FD07EAE6B
+CIPHER: E667316E3FC40DF234575E203EA06EA0
+
+MSG:    F7FB
+KEY:    91945D3F4DCBEE0BF45EF52255F095A4
+NONCE:  BECAF043B0A23D843194BA972C66DEBD
+HEADER: FA3BFD4806EB53FA
+CIPHER: D6D0A45C2A76EEB6AD20C3DB5CE100A2AEC4
+
+MSG:    1A47CB4933
+KEY:    01F74AD64077F2E704C0F60ADA3DD523
+NONCE:  70C3DB4F0D26368400A10ED05D2BFF5E
+HEADER: 234A3463C1264AC6
+CIPHER: FD8218F8987B7CCEBE4D521F4374D40B2F85794B31
+
+MSG:    481C9E39B1
+KEY:    D07CF6CBB7F313BDDE66B727AFD3C5E8
+NONCE:  8408DFFF3C1A2B1292DC199E46B7D617
+HEADER: 33CCE2EABFF5A79D
+CIPHER: 529951EDB28B9557667E88ED360EB51256DEC0F056
+
+MSG:    40D0C07DA5E4
+KEY:    35B6D0580005BBC12B0587124557D2C2
+NONCE:  FDB6B06676EEDC5C61D74276E1F8E816
+HEADER: AEB96EAEBE2970E9
+CIPHER: F46A8BFED3B22A6E4388659FF1C39B3D49AAD8ADEA74
+
+MSG:    4DE3B35C3FC039245BD1FB7D
+KEY:    BD8E6E11475E60B268784C38C62FEB22
+NONCE:  6EAC5C93072D8E8513F750935E46DA1B
+HEADER: D4482D1CA78DCE0F
+CIPHER: C3C7281CE5790F14D4CD666E8494D4911D528548F200014C32B86719
+
+MSG:    8B0A79306C9CE7ED99DAE4F87F8DD61636
+KEY:    7C77D6E813BED5AC98BAA417477A2E7D
+NONCE:  1A8C98DCD73D38393B2BF1569DEEFC19
+HEADER: 65D2017990D62528
+CIPHER: 1DD9A93ACD19F0C3FB7A3B431DFCFB96D2B899FA2285AEC7DCA504AF75B97A58A3
+
+MSG:    1BDA122BCE8A8DBAF1877D962B8592DD2D56
+KEY:    5FFF20CAFAB119CA2FC73549E20F5B0D
+NONCE:  DDE59B97D722156D4D9AFF2BC7559826
+HEADER: 54B9F04E6A09189A
+CIPHER: 2BA4C477F2927210ADCA26DF72E2BEF81BF3D6B03160E7BFE7FD3EB57D255D66713F
+
+MSG:    6CF36720872B8513F6EAB1A8A44438D5EF11
+KEY:    A4A4782BCFFD3EC5E7EF6D8C34A56123
+NONCE:  B781FCF2F75FA5A8DE97A9CA48E522EC
+HEADER: 899A175897561D7E
+CIPHER: A17D854BA33FDBDF0BA86ADC9152D40B4EA01E1A8FAB1E0A80B19E73784219B29446
+
+MSG:    CA40D7446E545FFAED3BD12A740A659FFBBB3CEAB7
+KEY:    8395FCF1E95BEBD697BD010BC766AAC3
+NONCE:  22E7ADD93CFC6393C57EC0B3C17D6B44
+HEADER: 126735FCC320D25A
+CIPHER: 9F30626B590A0A6E2F6CE0ED8835031654B3FCCF311BD7A6C6089AF1C7373D22CB80D4AFEE
diff --git a/eax-test.c b/eax-test.c
new file mode 100644 (file)
index 0000000..c29a51f
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * eax-test.c: test harness for EAX, implementation
+ */
+/*
+ * This file is Free Software.  It was originally written for secnet.
+ *
+ * You may redistribute it and/or modify it under the terms of the GNU
+ * General Public License as published by the Free Software
+ * Foundation; either version 2, or (at your option) any later
+ * version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * usages:
+ *   ./eax-foo-test <eax-foo-test.vectors
+ *      runs the test vectors, regenerates the file on stdout
+ *   grep -v CIPHER <eax-foo-test.vectors | ./eax-foo-test
+ *      generates output with CIPHER lines reinserted
+ * All errors result in calls to abort().
+ */
+
+#include "eax-test.h"
+
+struct valbuf {
+    _Bool got;
+    uint8_t v[1024];
+    size_t len;
+};
+#define V(vb) ((vb).v), ((vb).len)
+
+static struct valbuf msg, key, nonce, header, cipher, ourcipher, returnplain;
+static size_t tau;
+
+static void trydecrypt(_Bool expected)
+{
+    _Bool actual = eax_decrypt(-1, V(nonce), V(header), V(ourcipher), tau,
+                              returnplain.v);
+    assert(actual == expected);
+    if (actual) {
+       returnplain.len = ourcipher.len - tau;
+       assert(returnplain.len == msg.len);
+       assert(!memcmp(returnplain.v, msg.v, msg.len));
+    }
+}
+
+static void negtest(struct valbuf *perturb)
+{
+    unsigned delta = 0x04;
+    size_t i;
+    for (i=0; i<perturb->len; i++) {
+       perturb->v[i] ^= delta;
+       trydecrypt(0);
+       perturb->v[i] ^= delta;
+    }
+}
+
+static void something(void)
+{
+    if (!msg.got) return;
+    assert(key.got);
+    assert(nonce.got);
+    assert(header.got);
+    eaxtest_blockcipher_key_setup(V(key));
+    eax_setup(-1);
+    if (cipher.got) {
+       assert(cipher.len > msg.len);
+       tau = cipher.len - msg.len;
+       assert(tau <= blocksize);
+    } else {
+       assert(msg.len + blocksize < sizeof(ourcipher.v));
+       tau = blocksize;
+    }
+    ourcipher.len = msg.len + tau;
+    eax_encrypt(-1, V(nonce), V(header), V(msg), tau, ourcipher.v);
+    if (cipher.got) {
+       assert(ourcipher.len == cipher.len);
+       assert(!memcmp(ourcipher.v, cipher.v, cipher.len));
+       trydecrypt(1);
+       negtest(&ourcipher);
+       negtest(&header);
+    } else {
+       size_t i;
+       printf("CIPHER: ");
+       for (i=0; i<ourcipher.len; i++)
+           printf("%02X", ourcipher.v[i]);
+       putchar('\n');
+    }
+    msg.got=key.got=nonce.got=header.got=0;
+}
+
+static int getputchar(void)
+{
+    int c = getchar();
+    assert(c != EOF);
+    putchar(c);
+    return c;
+}
+
+int main(int argc, const char *const *argv)
+{
+    struct valbuf *cv;
+
+    assert(argc==1);
+
+    for (;;) {
+       int c = getchar();
+       switch (c) {
+       case 'M':  something();  cv = &msg;     putchar(c);  break;
+       case 'K':                cv = &key;     putchar(c);  break;
+       case 'N':                cv = &nonce;   putchar(c);  break;
+       case 'H':                cv = &header;  putchar(c);  break;
+       case 'C':                cv = &cipher;  putchar(c);  break;
+       case '\n':                              putchar(c);  continue;
+       case EOF:  something();  exit(0);
+       default:   assert(!"unexpected input");
+       }
+       cv->got = 1;
+       cv->len = 0;
+       for (;;) {
+           c = getputchar();
+           if (c == ':') break;
+           assert(isalpha(c));
+       }
+       for (;;) {
+           char hbuf[3], *ep;
+           c = getputchar();
+           if (c == '\n') break;
+           if (isspace(c)) continue;
+           assert(isprint(c));
+           hbuf[0] = c;
+           c = getputchar();
+           assert(isprint(c));
+           hbuf[1] = c;
+           hbuf[2] = 0;
+           assert(cv->len < sizeof(cv->v));
+           cv->v[cv->len++] = strtoul(hbuf,&ep,16);
+           assert(!*ep);
+       }
+    }
+    assert(!ferror(stdin));
+    assert(feof(stdin));
+    assert(!ferror(stdout));
+    assert(!fflush(stdout));
+    return 0;
+}
diff --git a/eax-test.h b/eax-test.h
new file mode 100644 (file)
index 0000000..2fe5d96
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * eax-test.c: test harness for EAX, common declarations
+ */
+/*
+ * This file is Free Software.  It was originally written for secnet.
+ *
+ * You may redistribute it and/or modify it under the terms of the GNU
+ * General Public License as published by the Free Software
+ * Foundation; either version 2, or (at your option) any later
+ * version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#ifndef EAX_TEST_H
+#define EAX_TEST_H
+
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <sys/types.h>
+
+#define INFO                int dummy_info
+#define I                   dummy_info
+#define EAX_ENTRYPOINT_DECL /* empty */
+
+#define EAX_DECLARATIONS_ONLY
+#include "eax.c"
+#undef EAX_DECLARATIONS_ONLY
+
+void eaxtest_blockcipher_key_setup(const uint8_t *keydata, uint8_t bytes);
+
+#define consttime_memeq(s1,s2,sz) (!memcmp((s1),(s2),(sz)))
+    /* fine for running test vectors */
+
+extern const size_t blocksize;
+
+#define EAX_SOME_TEST                                          \
+    const size_t blocksize = BLOCK_SIZE;                       \
+    static uint8_t INFO_B[BLOCK_SIZE], INFO_P[BLOCK_SIZE]
+
+#endif /* EAX_TEST_H */
diff --git a/eax.c b/eax.c
new file mode 100644 (file)
index 0000000..af5ccae
--- /dev/null
+++ b/eax.c
@@ -0,0 +1,341 @@
+/*
+ * eax.c: implementation of the EAX authenticated encryption block cipher mode
+ */
+/*
+ * Copyright 2013 Ian Jackson
+ * Copyright 2013 Mark Wooding
+ *
+ * This file is Free Software.  It was originally written for secnet.
+ *
+ * You may redistribute it and/or modify it under the terms of the GNU
+ * General Public License as published by the Free Software
+ * Foundation; either version 2, or (at your option) any later
+ * version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/*
+ * This file is designed to be #included into another .c file which
+ * sets up the environment.  It will declare or define three
+ * functions, eax_setup, eax_encrypt and eax_decrypt.
+ *
+ * Manifest constants which are expected to be defined:
+ *
+ *  INFO       One or more formal parameter definitions.
+ *             Used in all relevant function declarations.  Typically
+ *             the application will use this for its context pointer,
+ *             key schedule structure, etc.
+ *
+ *  I          Corresponding actual parameters for chaining onto
+ *             sub-functions declared to take INFO parameters
+ *
+ *  EAX_ENTRYPOINT_DECL
+ *             Declarator decoration for the three entry points.
+ *             Typically either "static" or the empty string;
+ *
+ *  EAX_DECLARATIONS_ONLY
+ *             Tested with #ifdef, so should be #defined to 1, or left
+ *             undefined.  If defined, #including eax.c will produces
+ *             only the function prototypes for the three entrypoints.
+ *             Otherwise it will produce the implementation.
+ *
+ *  BLOCK_SIZE
+ *             Constant expresion of integer type.
+ *
+ *  void BLOCK_ENCRYPT(uint8_t dst[n], const uint8_t src[n]);
+ *
+ *             Function to encrypt with the selected key.  The block
+ *             cipher's key schedule (ie, the key) to be used is
+ *             implicit; uses of BLOCK_ENCRYPT always occur in a
+ *             context where the parameters defined by INFO are
+ *             available.
+ *
+ *             So in a real application which wants to use more than
+ *             one key at a time, BLOCK_ENCRYPT must be a macro which
+ *             accesses the block cipher's key schedule via one of the
+ *             INFO parameters.
+ *
+ *             BLOCK_ENCRYPT must tolerate dst==src.
+ *
+ *             EAX does not need to use the block cipher's decryption
+ *             function.
+ *
+ *  uint8_t INFO_B[n], INFO_P[n];
+ *
+ *             Buffers used by the algorithm; they are written by
+ *             eax_setup and used by eax_encrypt and eax_decrypt.
+ *
+ *             That is, effectively they are the part of the key
+ *             schedule specific to EAX.
+ *
+ *             An application which wants to use more than one key at
+ *             a time must define these as macros which refer to
+ *             key-specific variables via one of the INFO parameters.
+ *
+ *  int consttime_memeq(const void *s1, const void *s2, size_t n);
+ *
+ *             Like !memcmp(s1,s2,n) but takes the same amount of time
+ *             no matter where the discrepancy is.  Result must be
+ *             a canonicalised boolean.
+ *
+ * The entrypoints which are then defined are:
+ *
+ *  void eax_setup(INFO)
+ *
+ *      Does the EAX-specific part of the key setup.  The block
+ *      cipher key schedule must already have been done, as
+ *      eax_setup uses BLOCK_ENCRYPT.
+ *
+ *  void eax_encrypt(INFO, const uint8_t nonce[nonce_len], size_t nonce_len,
+ *                         const uint8_t h[h_len], size_t h_len,
+ *                         const uint8_t m[m_len], size_t m_len,
+ *                         uint8_t tau,
+ *                         uint8_t ct[m_len+tau])
+ *
+ *      Does a single EAX authenticated encryption, providing
+ *      confidentiality and integrity to the message m[0..m_len-1].
+ *
+ *      The output message is longer than m by tau bytes and is stored
+ *      in the array ct which must be big enough.
+ *
+ *      nonce must never be repeated with the same key or the security
+ *      of the system is destroyed, but it does not need to be secret.
+ *      It is OK to transmit the nonce with the message along with the
+ *      ciphertext and have the receiver recover it.
+ *
+ *      h is the "header" - it is some extra data which should be
+ *      covered by the authentication, but not the encryption.  The
+ *      output message does not contain a representation of h: it is
+ *      expected to be transmitted separately (perhaps even in a
+ *      different format).  (If h_len==0, h may be a NULL pointer.)
+ *
+ *      tau is the tag length - that is, the length of the message
+ *      authentication code.  It should be chosen for the right
+ *      tradeoff between message expansion and security (resistence to
+ *      forgery).  It must be no longer than the block cipher block
+ *      size.
+ *
+ *      For any particular key.  the tag length should be fixed.  (The
+ *      tag length should NOT be encoded into the packet along with
+ *      the ciphertext and extracted by the receiver!  Rather, the
+ *      receiver must know what tag length to expect.)
+ *
+ *      It is permissible for ct==m, or for the arrays to be disjoint.
+ *      They must not overlap more subtly.
+ *
+ *  _Bool eax_decrypt(INFO, const uint8_t nonce[nonce_len], size_t nonce_len,
+ *                          const uint8_t h[h_len], size_t h_len,
+ *                          const uint8_t ct[ct_len], size_t ct_len,
+ *                          uint8_t tau,
+ *                          uint8_t m[ct_len-tau])
+ *
+ *      Does a single EAX authenticated decryption.
+ *
+ *      On successful return, the plaintext message is written to m
+ *      and eax_decrypt returns true.  The length of the plaintext
+ *      message is always ct_len-tau.
+ *
+ *      If the message did not decrypt correctly, returns false.
+ *      (There is no further indication of the nature of the error.)
+ *      In this case the buffer m may contain arbitrary contents which
+ *      should not be revealed to attackers.
+ *
+ *      nonce, h, tau are as above.
+ *
+ *      It is permissible to call eax_decrypt with an input message
+ *      which is too short (i.e. shorter than tau) (notwithstanding
+ *      the notation m[ct_len-tau] in the faux prototype above).
+ *      In this case it will return false without touching m.
+ *
+ *      As with eax_decrypt, ct==m is permissible.
+ */
+
+/***** IMPLEMENTATION *****/
+
+/*
+ * We use the notation from the EAX paper, mostly.
+ * (We write xscr for "x in fancy mathsy curly script".)
+ *
+ * See:
+ *  Mihir Bellare, Phillip Rogaway, and David Wagner
+ *
+ *  _The EAX Mode of Operation
+ *   (A Two-Pass Authenticated Encryption Scheme
+ *   Optimized for Simplicity and Efficiency)_
+ *
+ * Preliminary version in:
+ *   Fast Software Encryption (FSE) 2004. Lecture Notes in Computer Science,
+ *   vol. ??, pp. ??--??.
+ *
+ * Full version at:
+ *  http://www.cs.ucdavis.edu/~rogaway/papers/eax.html
+ */
+/*
+ * In general, all functions tolerate their destination arrays being
+ * the same pointer to their source arrays, or totally distinct.
+ * (Just like BLOCK_ENCRYPT and the public eax entrypoints.)
+ * They must not overlap in more subtle ways.
+ */
+
+#define n ((size_t)BLOCK_SIZE)
+
+#ifndef EAX_DECLARATIONS_ONLY
+
+static void xor_block(uint8_t *dst, const uint8_t *a, const uint8_t *b,
+                      size_t l)
+    /* simple block xor */
+{
+    while (l--)
+        *dst++ = *a++ ^ *b++;
+}
+
+static void increment(uint8_t *value)
+    /* value is a single block; incremented (BE) mod 256^n */
+{
+    uint8_t *p;
+    for (p=value+n; p>value; )
+        if ((*--p)++) break;
+}
+
+static void alg_ctr(INFO, uint8_t *c, const uint8_t *nscr,
+                    const uint8_t *m, size_t m_len)
+{
+    uint8_t blocknonce[n], cipher[n];
+    size_t in;
+
+    memcpy(blocknonce, nscr, n);
+    for (in=0; in<m_len; in+=n) {
+        BLOCK_ENCRYPT(cipher,blocknonce);
+        increment(blocknonce);
+        size_t now = m_len-in < n ? m_len-in : n;
+        xor_block(c+in, m+in, cipher, now);
+    }
+}
+
+static void alg_omac_t_k(INFO, uint8_t *mac_out, uint8_t t,
+                         const uint8_t *m, size_t m_len)
+{
+    /* Initial tweak. */
+    memset(mac_out, 0, n-1);
+    mac_out[n-1] = t;
+
+    /* All of the whole blocks. */
+    size_t in=0;
+    for (; in+n <= m_len; in+=n) {
+        BLOCK_ENCRYPT(mac_out, mac_out);
+        xor_block(mac_out, mac_out, m+in, n);
+    }
+
+    /* The last partial block, if there is one. */
+    assert(in <= m_len);
+    size_t remain = m_len - in;
+    if (!remain)
+        xor_block(mac_out, mac_out, INFO_B, n);
+    else {
+        BLOCK_ENCRYPT(mac_out, mac_out);
+        xor_block(mac_out, mac_out, m+in, remain);
+        mac_out[remain] ^= 0x80;
+        xor_block(mac_out, mac_out, INFO_P, n);
+    }
+
+    /* Final block-cipher application. */
+    BLOCK_ENCRYPT(mac_out, mac_out);
+}
+
+/*
+ * Constant-time multiply-by-x in F = GF(2^128), using the EAX representation
+ * F = GF(2)[x]/(x^128 + x^7 + x^2 + x + 1).
+ *
+ * The input vector V consists of the input polynomial L = a_127 x^127 +
+ * ... + a_1 x + a_0; specifically, the byte v[15 - i] contains a_{8i+7}
+ * x^{8i+7} + ... + a_{8i} x^{8i}.  The output vector O will contain L x on
+ * exit, using the same encoding.
+ *
+ * It is fine if O = V, or the two vectors are disjoint; Bad Things will
+ * happen if they overlap in some more complicated way.
+ */
+static void consttime_curious_multiply(INFO, uint8_t *o, const uint8_t *v)
+{
+#define POLY 0x87u
+
+  unsigned m = ~((v[0] >> 7) - 1u) & POLY;
+  unsigned i, mm;
+
+  for (i = n - 1; i < n; i--) {
+    mm = (v[i] >> 7) & 1u;
+    o[i] = (v[i] << 1) ^ m;
+    m = mm;
+  }
+
+#undef POLY
+}
+
+#endif /* not EAX_DECLARATIONS_ONLY */
+
+EAX_ENTRYPOINT_DECL
+void eax_setup(INFO)
+#ifndef EAX_DECLARATIONS_ONLY
+{
+    uint8_t work[n];
+    memset(work,0,n);
+    BLOCK_ENCRYPT(work,work);
+    consttime_curious_multiply(I, INFO_B, work);
+    consttime_curious_multiply(I, INFO_P, INFO_B);
+}
+#endif /* not EAX_DECLARATIONS_ONLY */
+;
+
+EAX_ENTRYPOINT_DECL
+void eax_encrypt(INFO,
+                 const uint8_t *nonce, size_t nonce_len,
+                 const uint8_t *h, size_t h_len,
+                 const uint8_t *m, size_t m_len, uint8_t tau, uint8_t *ct)
+#ifndef EAX_DECLARATIONS_ONLY
+{
+    assert(tau <= n);
+    uint8_t nscr[n], hscr[n], cscr[n];
+    alg_omac_t_k(I, nscr, 0, nonce,nonce_len);
+    alg_omac_t_k(I, hscr, 1, h,h_len);
+    alg_ctr(I, ct, nscr, m, m_len);
+    alg_omac_t_k(I, cscr, 2, ct, m_len);
+    uint8_t *t = ct + m_len;
+    xor_block(t, nscr, cscr, tau);
+    xor_block(t, t, hscr, tau);
+}
+#endif /* not EAX_DECLARATIONS_ONLY */
+;
+
+EAX_ENTRYPOINT_DECL
+_Bool eax_decrypt(INFO,
+                  const uint8_t *nonce, size_t nonce_len,
+                  const uint8_t *h, size_t h_len,
+                  const uint8_t *ct, size_t ct_len, uint8_t tau, uint8_t *m)
+#ifndef EAX_DECLARATIONS_ONLY
+{
+    assert(tau <= n);
+    const uint8_t *t;
+    uint8_t nscr[n], hscr[n], cscr[n], tprime[tau];
+    if (ct_len < tau) return 0;
+    size_t m_len = ct_len - tau;
+    t = ct + m_len;
+    alg_omac_t_k(I, nscr, 0, nonce,nonce_len);
+    alg_omac_t_k(I, hscr, 1, h,h_len);
+    alg_omac_t_k(I, cscr, 2, ct,m_len);
+    xor_block(tprime, nscr, cscr, tau);
+    xor_block(tprime, tprime, hscr, tau);
+    if (!consttime_memeq(tprime, t, tau)) return 0;
+    alg_ctr(I, m, nscr, ct, m_len);
+    return 1;
+}
+#endif /* not EAX_DECLARATIONS_ONLY */
+;
+
+#undef n