--- /dev/null
+Makefile.am
+Makefile.in
+_mpdiv.c
+aclocal.m4
+blowfish-cbc.c
+blowfish-cbc.h
+blowfish-cfb.c
+blowfish-cfb.h
+blowfish-ecb.c
+blowfish-ecb.h
+blowfish-ofb.c
+blowfish-ofb.h
+build
+config.h.in
+configure
+des-cbc.c
+des-cbc.h
+des-cfb.c
+des-cfb.h
+des-ecb.c
+des-ecb.h
+des-ofb.c
+des-ofb.h
+des3-cbc.c
+des3-cbc.h
+des3-cfb.c
+des3-cfb.h
+des3-ecb.c
+des3-ecb.h
+des3-ofb.c
+des3-ofb.h
+des_sp.h
+idea-cbc.c
+idea-cbc.h
+idea-cfb.c
+idea-cfb.h
+idea-ecb.c
+idea-ecb.h
+idea-ofb.c
+idea-ofb.h
+md4-hmac.c
+md4-hmac.h
+md5-hmac.c
+md5-hmac.h
+rc5-cbc.c
+rc5-cbc.h
+rc5-cfb.c
+rc5-cfb.h
+rc5-ecb.c
+rc5-ecb.h
+rc5-ofb.c
+rc5-ofb.h
+rmd160-hmac.c
+rmd160-hmac.h
+sha-hmac.c
+sha-hmac.h
+stamp-h.in
--- /dev/null
+COPYING.LIB
+install-sh
+missing
+mkinstalldirs
+getdate.y
+getdate.h
--- /dev/null
+;;; -*-emacs-lisp-*-
+
+(setq skel-alist
+ (append
+ '((author . "Straylight/Edgeware")
+ (licence-text . "[[lgpl]]")
+ (full-title . "Catacomb")
+ (library . "Catacomb"))
+ skel-alist))
--- /dev/null
+## -*-makefile-*-
+##
+## $Id: Makefile.m4,v 1.1 1999/09/03 08:41:11 mdw Exp $
+##
+## Makefile for Catacomb
+##
+## (c) 1999 Straylight/Edgeware
+##
+
+##----- Licensing notice ----------------------------------------------------
+##
+## This file is part of Catacomb.
+##
+## Catacomb is free software; you can redistribute it and/or modify
+## it under the terms of the GNU Library General Public License as
+## published by the Free Software Foundation; either version 2 of the
+## License, or (at your option) any later version.
+##
+## Catacomb 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 Library General Public License for more details.
+##
+## You should have received a copy of the GNU Library General Public
+## License along with Catacomb; if not, write to the Free
+## Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+## MA 02111-1307, USA.
+
+##----- Revision history ----------------------------------------------------
+##
+## $Log: Makefile.m4,v $
+## Revision 1.1 1999/09/03 08:41:11 mdw
+## Initial import.
+##
+## The `CVS' directory can't be hardlinked. Don't worry about this
+## overmuch.
+##
+##
+
+AUTOMAKE_OPTIONS = foreign
+
+archincludedir = $(libdir)/catacomb/include
+
+## --- List handling macros ---
+##
+## List handling is nice, usually. Unfortunately, I based this design on
+## TeX list macros rather than anything sensible...
+
+define(`_', `define(`_item', $1)define(`_item_2', $2)emit`'')
+define(`adorn', `pushdef(`emit', `$1`'_item`'$3')$2`'popdef(`emit')')
+define(`join',
+`pushdef(`emit', `adorn(``_(''_item`$2', `$3', ``)'')`'')$1`'popdef(`emit')')
+define(`addsuffix', `adorn(`', `$1', `$2')')
+define(`lit', `adorn(`', `$1', `')')
+define(`nl', `
+')
+
+define(`allwithsuffix',
+`addsuffix(`$1', `$3') addsuffix(`$2', `$3') dnl
+addsuffix(join(`$1', `-', `$2'), `$3')')
+
+## --- Autogenerated source files ---
+
+define(`ciphers', `_(des) _(des3) _(blowfish) _(idea) _(rc5)')
+define(`cipher_modes', `_(ecb) _(cbc) _(cfb) _(ofb)')
+
+define(`hashes', `_(md5) _(md4) _(rmd160) _(sha)')
+define(`hash_modes', `_(hmac)')
+
+MODES = \
+ adorn(`$(srcdir)/', join(`ciphers', `-', `cipher_modes'), `.c') \
+ adorn(`$(srcdir)/', join(`ciphers', `-', `cipher_modes'), `.h') \
+ adorn(`$(srcdir)/', join(`hashes', `-', `hash_modes'), `.c') \
+ adorn(`$(srcdir)/', join(`hashes', `-', `hash_modes'), `.h')
+
+$(MODES): $(srcdir)/genmodes
+
+archinclude_HEADERS = mptypes.h
+
+mptypes.h: mptypes
+ des_sp.h \
+ ./mptypes >mptypes.h
+
+BUILT_SOURCES = \
+ getdate.c \
+ addsuffix(join(`ciphers', `-', `cipher_modes'), `.c') \
+ addsuffix(join(`ciphers', `-', `cipher_modes'), `.h') \
+INCLUDES = -I$(srcdir)/..
+ addsuffix(join(`hashes', `-', `hash_modes'), `.c') \
+ addsuffix(join(`hashes', `-', `hash_modes'), `.h')
+include_HEADERS = \
+libcatacomb_la_LDFLAGS = -version-info 0:4:0
+## Middle number is the patchlevel. Final number is the minor version. The
+## difference between the first and last numbers is major version.
+
+define(`emit', `$1.h ')
+pkginclude_HEADERS = \
+ paranoia.h \
+ blkc.h hash.h \
+ mpx.h mpw.h mpscan.h mparena.h mp.h mptext.h mpmont.h \
+ ptab.h pgen.h rabin.h \
+ dsa.h dh.h \
+ allwithsuffix(`ciphers', `cipher_modes', `.h') \
+libcatacomb_a_SOURCES = \
+
+define(`emit', `$1.c ')
+libcatacomb_la_SOURCES = \
+ des-base.c des-base.h des_sp.h bf_ikey.h daftstory.h \
+ ptab.c pgen.c rabin.c \
+ dsa-sign.c dsa-verify.c dsa-gen.c \
+ dh-prime.c \
+ addsuffix(join(`ciphers', `-', `cipher_modes'), `.c') \
+noinst_PROGRAMS = des-mktab
+LDADD = libcatacomb.a ../mLib/libmLib.a
+## --- Utility programs ---
+noinst_PROGRAMS = des-mktab mptypes
+LDADD = libcatacomb.a
+bin_SCRIPTS = catacomb-config
+noinst_PROGRAMS = des-mktab genprimes mptypes
+LDADD = libcatacomb.la
+genprimes_SOURCES = genprimes.c
+genprimes_LDADD =
+
+mptypes_SOURCES = mptypes.c
+mptypes_LDADD =
+
+## --- Documentation ---
+
+man_MANS = key.1 keyring.5
+
+## --- Other handy definitions ---
+ @ln $(srcdir)/tests/* $(distdir)/tests
+EXTRA_DIST = Makefile.m4 genmodes $(man_MANS)
+
+dist-hook:
+ @ln getdate.c $(distdir) || ln $(srcdir)/getdate.c $(distdir) || true
+ @mkdir $(distdir)/tests
+ @ln $(srcdir)/tests/* $(distdir)/tests || true
+ @rm -f $(distdir)/tests/*~
+TESTS = \
+ rc4.t \
+ addsuffix(join(`ciphers', `-', `cipher_modes'), `.t') \
+ addsuffix(join(`hashes', `-', `hash_modes'), `.t') \
+ addsuffix(`ciphers', `.t') addsuffix(`hashes', `.t')
+ $(COMPILE) -DTEST_RIG -DSRCDIR=\"$(srcdir)\" \
+ $(srcdir)/$1.c libcatacomb.a ../mLib/libmLib.a -o $1.t')
+
+`$1.t: $1.c libcatacomb.a
+ $(COMPILE) -DTEST_RIG -DSRCDIR=\"$(srcdir)\" $(srcdir)/$1.c libcatacomb.a $(LIBS) -o $1.t')
+ $1.t)dnl
+$1.t: $1.c libcatacomb.la
+
+adorn(`nl`'CTESTRIG(', `ciphers', `)')
+adorn(`nl`'CTESTRIG(', `hashes', `)')
+CLEANFILES = *.t
+adorn(`nl`'CTESTRIG(', join(`hashes', `-', `hash_modes'), `)')
+CTESTRIG(dsa-verify)
+CLEANFILES = *.t mptypes.h
+TESTS = testprogs
+
+CLEANFILES = *.t mptypes.h des_sp.h ptab.c ptab.h
+
+## --- Makefile building (haha!) ---
+
+$(srcdir)/Makefile.am: $(srcdir)/Makefile.m4
+ m4 $(srcdir)/Makefile.m4 >$(srcdir)/Makefile.am
+ $(MODES) $(srcdir)/des_sp.h \
+ $(srcdir)/getdate.c getdate.c
+ $(srcdir)/Makefile.am \
+ $(srcdir)/getdate.c getdate.c \
+ $(MODES)
+
+##----- That's all, folks ---------------------------------------------------
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: acconfig.h,v 1.1 1999/09/03 08:41:11 mdw Exp $
+ *
+ * Configuration header for Catacomb
+ *
+ * (c) 1999 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: acconfig.h,v $
+ * Revision 1.1 1999/09/03 08:41:11 mdw
+ * Initial import.
+ *
+ */
+
+#ifndef ACCONFIG_H
+#define ACCONFIG_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*----- Autoconfiguration data --------------------------------------------*/
+@TOP@
+
+/* Package and version number. */
+#define PACKAGE "catacomb"
+#define VERSION "1.0.0"
+
+/* If it's not provided already, define to be a signed integer type capable
+ * of representing any object size. (If in doubt, make it an `int'.) */
+#undef ssize_t
+
+/* If not provided already, define to be whatever your system uses for
+ * representing time. (Probably `long'.) */
+#undef time_t
+
+@BOTTOM@
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: bf_ikey.h,v 1.1 1999/09/03 08:41:11 mdw Exp $
+ *
+ * Blowfish initial key data
+ *
+ * (c) 1998 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: bf_ikey.h,v $
+ * Revision 1.1 1999/09/03 08:41:11 mdw
+ * Initial import.
+ *
+ */
+
+#ifndef BF_IKEY_H
+#define BF_IKEY_H
+
+/*----- Macros ------------------------------------------------------------*/
+
+#define BLOWFISH_IKEY { \
+ \
+ /* --- P-array of round-specific subkeys --- */ \
+ \
+ { 0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, \
+ 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89, \
+ 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, \
+ 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, \
+ 0x9216d5d9, 0x8979fb1b }, \
+ \
+ /* --- First S-box --- */ \
+ \
+ { 0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, \
+ 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99, \
+ 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, \
+ 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, \
+ 0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, \
+ 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013, \
+ 0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, \
+ 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e, \
+ 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, \
+ 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, \
+ 0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, \
+ 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a, \
+ 0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, \
+ 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677, \
+ 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, \
+ 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, \
+ 0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, \
+ 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239, \
+ 0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, \
+ 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0, \
+ 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, \
+ 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, \
+ 0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, \
+ 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe, \
+ 0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, \
+ 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d, \
+ 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, \
+ 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, \
+ 0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, \
+ 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463, \
+ 0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, \
+ 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09, \
+ 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, \
+ 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, \
+ 0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, \
+ 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8, \
+ 0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, \
+ 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82, \
+ 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, \
+ 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, \
+ 0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, \
+ 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b, \
+ 0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, \
+ 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8, \
+ 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, \
+ 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, \
+ 0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, \
+ 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c, \
+ 0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, \
+ 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1, \
+ 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, \
+ 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, \
+ 0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, \
+ 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf, \
+ 0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, \
+ 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af, \
+ 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, \
+ 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, \
+ 0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, \
+ 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915, \
+ 0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, \
+ 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915, \
+ 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, \
+ 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a }, \
+ \
+ /* --- Second S-box --- */ \
+ \
+ { 0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, \
+ 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266, \
+ 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, \
+ 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, \
+ 0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, \
+ 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1, \
+ 0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, \
+ 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1, \
+ 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, \
+ 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, \
+ 0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, \
+ 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd, \
+ 0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, \
+ 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7, \
+ 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, \
+ 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, \
+ 0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, \
+ 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af, \
+ 0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, \
+ 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87, \
+ 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, \
+ 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, \
+ 0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, \
+ 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd, \
+ 0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, \
+ 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509, \
+ 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, \
+ 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, \
+ 0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, \
+ 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a, \
+ 0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, \
+ 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960, \
+ 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, \
+ 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, \
+ 0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, \
+ 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84, \
+ 0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, \
+ 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf, \
+ 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, \
+ 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, \
+ 0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, \
+ 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7, \
+ 0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, \
+ 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281, \
+ 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, \
+ 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, \
+ 0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, \
+ 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73, \
+ 0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, \
+ 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0, \
+ 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, \
+ 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, \
+ 0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, \
+ 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285, \
+ 0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, \
+ 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061, \
+ 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, \
+ 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, \
+ 0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, \
+ 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc, \
+ 0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, \
+ 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340, \
+ 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, \
+ 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7 }, \
+ \
+ /* --- Third S-box --- */ \
+ \
+ { 0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, \
+ 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068, \
+ 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, \
+ 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, \
+ 0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, \
+ 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504, \
+ 0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, \
+ 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb, \
+ 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, \
+ 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, \
+ 0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, \
+ 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b, \
+ 0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, \
+ 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb, \
+ 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, \
+ 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, \
+ 0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, \
+ 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c, \
+ 0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, \
+ 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc, \
+ 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, \
+ 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, \
+ 0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, \
+ 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115, \
+ 0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, \
+ 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728, \
+ 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, \
+ 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, \
+ 0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, \
+ 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d, \
+ 0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, \
+ 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b, \
+ 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, \
+ 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, \
+ 0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, \
+ 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c, \
+ 0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, \
+ 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9, \
+ 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, \
+ 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, \
+ 0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, \
+ 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc, \
+ 0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, \
+ 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61, \
+ 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, \
+ 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, \
+ 0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, \
+ 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c, \
+ 0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, \
+ 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633, \
+ 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, \
+ 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, \
+ 0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, \
+ 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027, \
+ 0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, \
+ 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62, \
+ 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, \
+ 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, \
+ 0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, \
+ 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc, \
+ 0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, \
+ 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c, \
+ 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, \
+ 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0 }, \
+ \
+ /* --- Fourth and final S-box --- */ \
+ \
+ { 0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, \
+ 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe, \
+ 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, \
+ 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, \
+ 0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, \
+ 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6, \
+ 0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, \
+ 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22, \
+ 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, \
+ 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, \
+ 0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, \
+ 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59, \
+ 0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, \
+ 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51, \
+ 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, \
+ 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, \
+ 0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, \
+ 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28, \
+ 0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, \
+ 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd, \
+ 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, \
+ 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, \
+ 0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, \
+ 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f, \
+ 0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, \
+ 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32, \
+ 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, \
+ 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, \
+ 0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, \
+ 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb, \
+ 0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, \
+ 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47, \
+ 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, \
+ 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, \
+ 0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, \
+ 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048, \
+ 0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, \
+ 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd, \
+ 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, \
+ 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, \
+ 0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, \
+ 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f, \
+ 0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, \
+ 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525, \
+ 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, \
+ 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, \
+ 0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, \
+ 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e, \
+ 0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, \
+ 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d, \
+ 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, \
+ 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, \
+ 0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, \
+ 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc, \
+ 0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, \
+ 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a, \
+ 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, \
+ 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, \
+ 0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, \
+ 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060, \
+ 0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, \
+ 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9, \
+ 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, \
+ 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6 } \
+}
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: blkc.h,v 1.1 1999/09/03 08:41:11 mdw Exp $
+ *
+ * Common definitions for block ciphers
+ *
+ * (c) 1999 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: blkc.h,v $
+ * Revision 1.1 1999/09/03 08:41:11 mdw
+ * Initial import.
+ *
+ */
+
+#ifndef BLKC_H
+#define BLKC_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <mLib/bits.h>
+
+/*----- Theory of operation -----------------------------------------------*
+ *
+ * A block cipher has associated with it a triple, called PRE_CLASS, of the
+ * form `(TYPE, ENDIAN, BITS)', where TYPE is either `N' (representing an
+ * implemented bit size) or `X' (representing an unimplemented bit size,
+ * causing loops to be compiled rather than unrolled code), ENDIAN is `B'
+ * (big) or `L' (little), and BITS is the block size of the cipher in bits.
+ */
+
+/*----- Data movement macros ----------------------------------------------*/
+
+/*
+ * `The C preprocessor. You will never find a more wretched hive of bogus
+ * hackery. We must be cautious.'
+ */
+
+/* --- General dispatch macros --- */
+
+#define BLKC_DOGLUE(x, y) x ## y
+#define BLKC_GLUE(x, y) BLKC_DOGLUE(x, y)
+#define BLKC_APPLY(f, x) f x
+#define BLKC_FIRST(x, y, z) x
+#define BLKC_SECOND(x, y, z) y
+#define BLKC_THIRD(x, y, z) z
+#define BLKC_TYPE(PRE) BLKC_APPLY(BLKC_FIRST, PRE ## _CLASS)
+#define BLKC_ENDIAN(PRE) BLKC_APPLY(BLKC_SECOND, PRE ## _CLASS)
+#define BLKC_BITS(PRE) BLKC_APPLY(BLKC_THIRD, PRE ## _CLASS)
+
+#define BLKC_STORE_E(PRE) BLKC_GLUE(STORE32_, BLKC_ENDIAN(PRE))
+#define BLKC_LOAD_E(PRE) BLKC_GLUE(LOAD32_, BLKC_ENDIAN(PRE))
+
+/* --- Interface macros --- */
+
+#define BLKC_STORE(PRE, b, w) \
+ BLKC_GLUE(BLKC_STORE_, BLKC_TYPE(PRE)) \
+ (PRE, b, w, BLKC_STORE_E(PRE), BLKC_BITS(PRE))
+
+#define BLKC_XSTORE(PRE, b, w, wx) \
+ BLKC_GLUE(BLKC_XSTORE_, BLKC_TYPE(PRE)) \
+ (PRE, b, w, wx, BLKC_STORE_E(PRE), BLKC_BITS(PRE))
+
+#define BLKC_LOAD(PRE, w, b) \
+ BLKC_GLUE(BLKC_LOAD_, BLKC_TYPE(PRE)) \
+ (PRE, w, b, BLKC_LOAD_E(PRE), BLKC_BITS(PRE))
+
+#define BLKC_XLOAD(PRE, w, b) \
+ BLKC_GLUE(BLKC_XLOAD_, BLKC_TYPE(PRE)) \
+ (PRE, w, b, BLKC_LOAD_E(PRE), BLKC_BITS(PRE))
+
+#define BLKC_MOVE(PRE, w, wx) \
+ BLKC_GLUE(BLKC_MOVE_, BLKC_TYPE(PRE)) \
+ (PRE, w, wx, BLKC_BITS(PRE))
+
+#define BLKC_XMOVE(PRE, w, wx) \
+ BLKC_GLUE(BLKC_XMOVE_, BLKC_TYPE(PRE)) \
+ (PRE, w, wx, BLKC_BITS(PRE))
+
+/* --- General implementation skeleton --- */
+
+#define BLKC_SKEL(PRE, decl, guts) do { \
+ decl \
+ guts \
+} while (0)
+
+#define BLKC_P(p) register octet *_p = (octet *)(p)
+#define BLKC_W(w) register uint32 *_w = (w)
+#define BLKC_WX(wx) register uint32 *_wx = (wx);
+
+/* --- Implementation for unusual block sizes --- */
+
+#define BLKC_SKEL_X(PRE, decl, guts) \
+ BLKC_SKEL(PRE, int _i; decl, \
+ for (_i = 0; _i < PRE ## _BLKSZ / 4; _i++) { \
+ guts \
+ })
+
+#define BLKC_STORE_X(PRE, b, w, op, n) \
+ BLKC_SKEL_X(PRE, BLKC_P(b); const BLKC_W(w);, \
+ op(_p, *_w); _p += 4; _w++; )
+
+#define BLKC_XSTORE_X(PRE, b, w, wx, op, n) \
+ BLKC_SKEL_X(PRE, BLKC_P(b); const BLKC_W(w); const BLKC_WX(wx);, \
+ op(_p, *_w ^ *_wx); _p += 4; _w++; _wx++; )
+
+#define BLKC_LOAD_X(PRE, w, b, op, n) \
+ BLKC_SKEL_X(PRE, const BLKC_P(b); BLKC_W(w);, \
+ *_w = op(_p); _p += 4; _w++; )
+
+#define BLKC_XLOAD_X(PRE, w, b, op, n) \
+ BLKC_SKEL_X(PRE, const BLKC_P(b); BLKC_W(w);, \
+ *_w ^= op(_p); _p += 4; _w++; )
+
+#define BLKC_MOVE_X(PRE, w, wx, n) \
+ BLKC_SKEL_X(PRE, BLKC_W(w); const BLKC_WX(wx);, \
+ *_w = *_wx; _w++; _wx++; ) \
+
+#define BLKC_XMOVE_X(PRE, w, wx, n) \
+ BLKC_SKEL_X(PRE, BLKC_W(w); const BLKC_WX(wx);, \
+ *_w ^= *_wx; _w++; _wx++; ) \
+
+/* --- Implementation for known block sizes --- */
+
+#define BLKC_SKEL_64(PRE, decl, op, guts) \
+ BLKC_SKEL(PRE, decl, guts(op, 0); guts(op, 1);)
+
+#define BLKC_SKEL_128(PRE, decl, op, guts) \
+ BLKC_SKEL(PRE, decl, guts(op, 0); guts(op, 1); guts(op, 2); guts(op, 3);)
+
+#define BLKC_STORE_GUTS(op, i) op(_p + 4 * i, _w[i])
+#define BLKC_XSTORE_GUTS(op, i) op(_p + 4 * i, _w[i] ^ _wx[i])
+#define BLKC_LOAD_GUTS(op, i) _w[i] = op(_p + 4 * i)
+#define BLKC_XLOAD_GUTS(op, i) _w[i] ^= op(_p + 4 * i)
+#define BLKC_MOVE_GUTS(op, i) _w[i] = _wx[i]
+#define BLKC_XMOVE_GUTS(op, i) _w[i] ^= _wx[i]
+
+#define BLKC_STORE_N(PRE, b, w, op, n) \
+ BLKC_GLUE(BLKC_SKEL_, n) \
+ (PRE, BLKC_P(b); const BLKC_W(w);, op, BLKC_STORE_GUTS)
+
+#define BLKC_XSTORE_N(PRE, b, w, wx, op, n) \
+ BLKC_GLUE(BLKC_SKEL_, n) \
+ (PRE, BLKC_P(b); const BLKC_W(w); const BLKC_WX(wx);, \
+ op, BLKC_XSTORE_GUTS)
+
+#define BLKC_LOAD_N(PRE, w, b, op, n) \
+ BLKC_GLUE(BLKC_SKEL_, n) \
+ (PRE, const BLKC_P(b); BLKC_W(w);, op, BLKC_LOAD_GUTS)
+
+#define BLKC_XLOAD_N(PRE, w, b, op, n) \
+ BLKC_GLUE(BLKC_SKEL_, n) \
+ (PRE, const BLKC_P(b); BLKC_W(w);, op, BLKC_XLOAD_GUTS)
+
+#define BLKC_MOVE_N(PRE, w, wx, n) \
+ BLKC_GLUE(BLKC_SKEL_, n) \
+ (PRE, BLKC_W(w); const BLKC_WX(wx);, op, BLKC_MOVE_GUTS)
+
+#define BLKC_XMOVE_N(PRE, w, wx, n) \
+ BLKC_GLUE(BLKC_SKEL_, n) \
+ (PRE, BLKC_W(w); const BLKC_WX(wx);, op, BLKC_XMOVE_GUTS)
+
+/*----- Test rig for block ciphers ----------------------------------------*/
+
+/* --- @BLKC_TEST@ --- *
+ *
+ * Arguments: @PRE@, @pre@ = prefixes for cipher-specific definitions
+ *
+ * Use: Standard test rig for block ciphers.
+ */
+
+#ifdef TEST_RIG
+
+#include <mLib/quis.h>
+#include <mLib/testrig.h>
+
+#define BLKC_TEST(PRE, pre) \
+ \
+static int verify(dstr *v) \
+{ \
+ pre ## _ctx k; \
+ uint32 p[PRE ## _BLKSZ / 4]; \
+ uint32 c[PRE ## _BLKSZ / 4]; \
+ uint32 d[PRE ## _BLKSZ / 4]; \
+ dstr b = DSTR_INIT; \
+ int ok = 1; \
+ \
+ /* --- Initialize the key buffer --- */ \
+ \
+ dstr_ensure(&b, PRE ## _BLKSZ); \
+ b.len = PRE ## _BLKSZ; \
+ pre ## _init(&k, v[0].buf, v[0].len); \
+ BLKC_LOAD(PRE, p, v[1].buf); \
+ BLKC_LOAD(PRE, c, v[2].buf); \
+ \
+ /* --- Test encryption --- */ \
+ \
+ BLKC_MOVE(PRE, d, p); \
+ pre ## _eblk(&k, d, d); \
+ BLKC_STORE(PRE, b.buf, d); \
+ if (memcmp(b.buf, v[2].buf, PRE ## _BLKSZ)) { \
+ ok = 0; \
+ printf("\nfail encryption:" \
+ "\n\tkey = "); \
+ type_hex.dump(&v[0], stdout); \
+ printf("\n\tplaintext = "); type_hex.dump(&v[1], stdout); \
+ printf("\n\texpected = "); type_hex.dump(&v[2], stdout); \
+ printf("\n\tcalculated = "); type_hex.dump(&b, stdout); \
+ putchar('\n'); \
+ } \
+ \
+ /* --- Test decryption --- */ \
+ \
+ BLKC_MOVE(PRE, d, c); \
+ pre ## _dblk(&k, d, d); \
+ BLKC_STORE(PRE, b.buf, d); \
+ if (memcmp(b.buf, v[1].buf, PRE ## _BLKSZ)) { \
+ ok = 0; \
+ printf("\nfail decryption:" \
+ "\n\tkey = "); \
+ type_hex.dump(&v[0], stdout); \
+ printf("\n\tciphertext = "); type_hex.dump(&v[2], stdout); \
+ printf("\n\texpected = "); type_hex.dump(&v[1], stdout); \
+ printf("\n\tcalculated = "); type_hex.dump(&b, stdout); \
+ putchar('\n'); \
+ } \
+ \
+ /* --- Return --- */ \
+ \
+ return (ok); \
+} \
+ \
+static test_chunk defs[] = { \
+ { #pre, verify, { &type_hex, &type_hex, &type_hex, 0 } }, \
+ { #pre "-sched", verify, { &type_hex, &type_hex, &type_hex, 0 } }, \
+ { 0, 0, { 0 } } \
+}; \
+ \
+int main(int argc, char *argv[]) \
+{ \
+ test_run(argc, argv, defs, SRCDIR"/tests/" #pre); \
+ return (0); \
+}
+
+#else
+# define BLKC_TEST(PRE, pre)
+#endif
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: blowfish.c,v 1.1 1999/09/03 08:41:11 mdw Exp $
+ *
+ * The Blowfish block cipher
+ *
+ * (c) 1998 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: blowfish.c,v $
+ * Revision 1.1 1999/09/03 08:41:11 mdw
+ * Initial import.
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <mLib/bits.h>
+
+#include "blowfish.h"
+#include "bf_ikey.h"
+#include "blkc.h"
+#include "paranoia.h"
+
+/*----- Global variables --------------------------------------------------*/
+
+static blowfish_ctx ikey = BLOWFISH_IKEY;
+
+/*----- Macros ------------------------------------------------------------*/
+
+#define ROUND(k, x, y, r) \
+ ((x) ^= (k)->p[(r)], \
+ (y) ^= (((((k)->s0[((x) >> 24) & MASK8]) + \
+ ((k)->s1[((x) >> 16) & MASK8])) ^ \
+ ((k)->s2[((x) >> 8) & MASK8])) + \
+ ((k)->s3[((x) >> 0) & MASK8])))
+
+#define EBLK(k, a, b, c, d) do { \
+ uint32 _x = (a); \
+ uint32 _y = (b); \
+ ROUND((k), _x, _y, 0); \
+ ROUND((k), _y, _x, 1); \
+ ROUND((k), _x, _y, 2); \
+ ROUND((k), _y, _x, 3); \
+ ROUND((k), _x, _y, 4); \
+ ROUND((k), _y, _x, 5); \
+ ROUND((k), _x, _y, 6); \
+ ROUND((k), _y, _x, 7); \
+ ROUND((k), _x, _y, 8); \
+ ROUND((k), _y, _x, 9); \
+ ROUND((k), _x, _y, 10); \
+ ROUND((k), _y, _x, 11); \
+ ROUND((k), _x, _y, 12); \
+ ROUND((k), _y, _x, 13); \
+ ROUND((k), _x, _y, 14); \
+ ROUND((k), _y, _x, 15); \
+ (c) = _y ^ (k)->p[17]; \
+ (d) = _x ^ (k)->p[16]; \
+} while (0)
+
+#define DBLK(k, a, b, c, d) do { \
+ uint32 _x = (a); \
+ uint32 _y = (b); \
+ ROUND((k), _x, _y, 17); \
+ ROUND((k), _y, _x, 16); \
+ ROUND((k), _x, _y, 15); \
+ ROUND((k), _y, _x, 14); \
+ ROUND((k), _x, _y, 13); \
+ ROUND((k), _y, _x, 12); \
+ ROUND((k), _x, _y, 11); \
+ ROUND((k), _y, _x, 10); \
+ ROUND((k), _x, _y, 9); \
+ ROUND((k), _y, _x, 8); \
+ ROUND((k), _x, _y, 7); \
+ ROUND((k), _y, _x, 6); \
+ ROUND((k), _x, _y, 5); \
+ ROUND((k), _y, _x, 4); \
+ ROUND((k), _x, _y, 3); \
+ ROUND((k), _y, _x, 2); \
+ (c) = _y ^ (k)->p[0]; \
+ (d) = _x ^ (k)->p[1]; \
+} while (0)
+
+/*----- Low-level encryption interface ------------------------------------*/
+
+/* --- @blowfish_init@ --- *
+ *
+ * Arguments: @blowfish_ctx *k@ = pointer to key block to fill in
+ * @const void *buf@ = pointer to buffer of key material
+ * @size_t sz@ = size of key material
+ *
+ * Returns: ---
+ *
+ * Use: Initializes a Blowfish key buffer. Blowfish accepts
+ * a more-or-less arbitrary size key.
+ */
+
+void blowfish_init(blowfish_ctx *k, const void *buf, size_t sz)
+{
+ /* --- Copy the initial value over --- */
+
+ memcpy(k, &ikey, sizeof(ikey));
+
+ /* --- Initialize the %$P$% array --- */
+
+ {
+ const octet *p = buf;
+ const octet *q = p + sz;
+ int i = 0, j = 0;
+ uint32 x = 0;
+
+ while (i < 18) {
+ x = (x << 8) | U8(*p++);
+ if (p >= q)
+ p = buf;
+ if (++j >= 4) {
+ k->p[i++] ^= x;
+ x = 0;
+ j = 0;
+ }
+ }
+
+ x = 0;
+ }
+
+ /* --- Now mangle the complete array of keys --- */
+
+ {
+ uint32 b[2];
+ int i;
+
+ b[0] = b[1] = 0;
+
+ for (i = 0; i < 18; i += 2) {
+ blowfish_eblk(k, b, b);
+ k->p[i] = b[0]; k->p[i + 1] = b[1];
+ }
+
+ for (i = 0; i < 256; i += 2) {
+ blowfish_eblk(k, b, b);
+ k->s0[i] = b[0]; k->s0[i + 1] = b[1];
+ }
+
+ for (i = 0; i < 256; i += 2) {
+ blowfish_eblk(k, b, b);
+ k->s1[i] = b[0]; k->s1[i + 1] = b[1];
+ }
+
+ for (i = 0; i < 256; i += 2) {
+ blowfish_eblk(k, b, b);
+ k->s2[i] = b[0]; k->s2[i + 1] = b[1];
+ }
+
+ for (i = 0; i < 256; i += 2) {
+ blowfish_eblk(k, b, b);
+ k->s3[i] = b[0]; k->s3[i + 1] = b[1];
+ }
+
+ BURN(b);
+ }
+}
+
+/* --- @blowfish_eblk@, @blowfish_dblk@ --- *
+ *
+ * Arguments: @const blowfish_ctx *k@ = pointer to key block
+ * @const uint32 s[2]@ = pointer to source block
+ * @uint32 d[2]@ = pointer to destination block
+ *
+ * Returns: ---
+ *
+ * Use: Low-level block encryption and decryption.
+ */
+
+void blowfish_eblk(const blowfish_ctx *k, const uint32 *s, uint32 *d)
+{
+ EBLK(k, s[0], s[1], d[0], d[1]);
+}
+
+void blowfish_dblk(const blowfish_ctx *k, const uint32 *s, uint32 *d)
+{
+ DBLK(k, s[0], s[1], d[0], d[1]);
+}
+
+BLKC_TEST(BLOWFISH, blowfish)
+
+/*----- That's all, folks -------------------------------------------------*/
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: blowfish.h,v 1.1 1999/09/03 08:41:11 mdw Exp $
+ *
+ * The Blowfish block cipher
+ *
+ * (c) 1998 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: blowfish.h,v $
+ * Revision 1.1 1999/09/03 08:41:11 mdw
+ * Initial import.
+ *
+ */
+
+/*----- Notes on the Blowfish block cipher --------------------------------*
+ *
+ * Blowfish was invented by Bruce Schneier. The algorithm is unpatented and
+ * free for anyone to use. It's fast, simple, offers a big key, and is
+ * looking relatively bulletproof. It's also this author's block cipher of
+ * choice, for what little that's worth. The disadvantage is that Blowfish
+ * has a particularly heavyweight key schedule.
+ */
+
+#ifndef BLOWFISH_H
+#define BLOWFISH_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stddef.h>
+
+#include <mLib/bits.h>
+
+/*----- Magical numbers ---------------------------------------------------*/
+
+#define BLOWFISH_BLKSZ 8
+#define BLOWFISH_KEYSZ 0
+#define BLOWFISH_CLASS (N, B, 64)
+
+/*----- Data structures ---------------------------------------------------*/
+
+typedef struct blowfish_ctx {
+ uint32 p[18];
+ uint32 s0[256], s1[256], s2[256], s3[256];
+} blowfish_ctx;
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @blowfish_init@ --- *
+ *
+ * Arguments: @blowfish_ctx *k@ = pointer to key block to fill in
+ * @const void *buf@ = pointer to buffer of key material
+ * @size_t sz@ = size of key material
+ *
+ * Returns: ---
+ *
+ * Use: Initializes a Blowfish key buffer. Blowfish accepts
+ * a more-or-less arbitrary size key.
+ */
+
+extern void blowfish_init(blowfish_ctx */*k*/,
+ const void */*buf*/, size_t /*sz*/);
+
+/* --- @blowfish_eblk@, @blowfish_dblk@ --- *
+ *
+ * Arguments: @const blowfish_ctx *k@ = pointer to key block
+ * @const uint32 s[2]@ = pointer to source block
+ * @uint32 d[2]@ = pointer to destination block
+ *
+ * Returns: ---
+ *
+ * Use: Low-level block encryption and decryption.
+ */
+
+extern void blowfish_eblk(const blowfish_ctx */*k*/,
+ const uint32 */*s*/, uint32 */*d*/);
+
+extern void blowfish_dblk(const blowfish_ctx */*k*/,
+ const uint32 */*s*/, uint32 */*d*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: cbc.h,v 1.1 1999/09/03 08:41:11 mdw Exp $
+ *
+ * Ciphertext block chaining for block ciphers
+ *
+ * (c) 1999 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: cbc.h,v $
+ * Revision 1.1 1999/09/03 08:41:11 mdw
+ * Initial import.
+ *
+ */
+
+#ifndef CBC_H
+#define CBC_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <string.h>
+
+#include <mLib/bits.h>
+
+#ifndef BLKC_H
+# include "blkc.h"
+#endif
+
+/*----- Macros ------------------------------------------------------------*/
+
+/* --- @CBC_DECL@ --- *
+ *
+ * Arguments: @PRE@, @pre@ = prefixes for the underlying block cipher
+ *
+ * Use: Creates declarations for CBC stealing mode.
+ */
+
+#define CBC_DECL(PRE, pre) \
+ \
+typedef struct pre ## _cbcctx { \
+ pre ## _ctx ctx; /* Underlying cipher context */ \
+ uint32 iv[PRE ## _BLKSZ / 4]; /* Previous ciphertext or IV */ \
+} pre ## _cbcctx; \
+ \
+extern void pre ## _cbcgetiv(const pre ## _cbcctx */*ctx*/, \
+ void */*iv*/); \
+ \
+extern void pre ## _cbcsetiv(pre ## _cbcctx */*ctx*/, \
+ const void */*iv*/); \
+ \
+extern void pre ## _cbcsetkey(pre ## _cbcctx */*ctx*/, \
+ const pre ## _ctx */*k*/); \
+ \
+extern void pre ## _cbcinit(pre ## _cbcctx */*ctx*/, \
+ const void */*key*/, size_t /*sz*/, \
+ const void */*iv*/); \
+ \
+extern void pre ## _cbcencrypt(pre ## _cbcctx */*ctx*/, \
+ const void */*src*/, void */*dest*/, \
+ size_t /*sz*/); \
+ \
+extern void pre ## _cbcdecrypt(pre ## _cbcctx */*ctx*/, \
+ const void */*src*/, void */*dest*/, \
+ size_t /*sz*/); \
+
+/* --- @CBC_DEF@ --- *
+ *
+ * Arguments: @PRE@, @pre@ = prefixes for the underlying block cipher
+ *
+ * Use: Creates an implementation for CBC stealing mode.
+ */
+
+#define CBC_DEF(PRE, pre) \
+ \
+/* --- @pre_cbcgetiv@ --- * \
+ * \
+ * Arguments: @const pre_cbcctx *ctx@ = pointer to CBC context block \
+ * @void *iv#@ = pointer to output data block \
+ * \
+ * Returns: --- \
+ * \
+ * Use: Reads the currently set IV. Reading and setting an IV \
+ * is transparent to the CBC encryption or decryption \
+ * process. \
+ */ \
+ \
+void pre ## _cbcgetiv(const pre ## _cbcctx *ctx, void *iv) \
+{ \
+ BLKC_STORE(PRE, iv, ctx->iv); \
+} \
+ \
+/* --- @pre_cbcsetiv@ --- * \
+ * \
+ * Arguments: @pre_cbcctx *ctx@ = pointer to CBC context block \
+ * @cnost void *iv@ = pointer to IV to set \
+ * \
+ * Returns: --- \
+ * \
+ * Use: Sets the IV to use for subsequent encryption. \
+ */ \
+ \
+void pre ## _cbcsetiv(pre ## _cbcctx *ctx, const void *iv) \
+{ \
+ BLKC_LOAD(PRE, ctx->iv, iv); \
+} \
+ \
+/* --- @pre_cbcsetkey@ --- * \
+ * \
+ * Arguments: @pre_cbcctx *ctx@ = pointer to CBC context block \
+ * @const pre_ctx *k@ = pointer to cipher context \
+ * \
+ * Returns: --- \
+ * \
+ * Use: Sets the CBC context to use a different cipher key. \
+ */ \
+ \
+void pre ## _cbcsetkey(pre ## _cbcctx *ctx, const pre ## _ctx *k) \
+{ \
+ ctx->ctx = *k; \
+} \
+ \
+/* --- @pre_cbcinit@ --- * \
+ * \
+ * Arguments: @pre_cbcctx *ctx@ = pointer to cipher context \
+ * @const void *key@ = pointer to the key buffer \
+ * @size_t sz@ = size of the key \
+ * @const void *iv@ = pointer to initialization vector \
+ * \
+ * Returns: --- \
+ * \
+ * Use: Initializes a CBC context ready for use. The @iv@ \
+ * argument may be passed as a null pointer to set a zero \
+ * IV. Apart from that, this call is equivalent to calls \
+ * to @pre_init@, @pre_cbcsetkey@ and @pre_cbcsetiv@. \
+ */ \
+ \
+void pre ## _cbcinit(pre ## _cbcctx *ctx, \
+ const void *key, size_t sz, \
+ const void *iv) \
+{ \
+ static octet zero[PRE ## _BLKSZ] = { 0 }; \
+ pre ## _init(&ctx->ctx, key, sz); \
+ BLKC_LOAD(PRE, ctx->iv, iv ? iv : zero); \
+} \
+ \
+/* --- @pre_cbcencrypt@ --- * \
+ * \
+ * Arguments: @pre_cbcctx *ctx@ = pointer to CBC context block \
+ * @const void *src@ = pointer to source data \
+ * @void *dest@ = pointer to destination data \
+ * @size_t sz@ = size of block to be encrypted \
+ * \
+ * Returns: --- \
+ * \
+ * Use: Encrypts a block with a block cipher in CBC mode, with \
+ * ciphertext stealing and other clever tricks. \
+ * Essentially, data can be encrypted in arbitrary sized \
+ * chunks, although decryption must use the same chunks. \
+ */ \
+ \
+void pre ## _cbcencrypt(pre ## _cbcctx *ctx, \
+ const void *src, void *dest, \
+ size_t sz) \
+{ \
+ const octet *s = src; \
+ octet *d = dest; \
+ \
+ /* --- Empty blocks are trivial --- */ \
+ \
+ if (!sz) \
+ return; \
+ \
+ /* --- Extra magical case for a short block --- * \
+ * \
+ * Encrypt the IV, then exclusive-or the plaintext with the octets \
+ * of the encrypted IV, shifting ciphertext octets in instead. This \
+ * basically switches over to CFB. \
+ */ \
+ \
+ if (sz < PRE ## _BLKSZ) { \
+ octet b[PRE ## _BLKSZ]; \
+ unsigned i; \
+ \
+ pre ## _eblk(&ctx->ctx, ctx->iv, ctx->iv); \
+ BLKC_STORE(PRE, b, ctx->iv); \
+ for (i = 0; i < sz; i++) \
+ d[i] = b[i] ^ s[i]; \
+ memmove(b, b + sz, PRE ## _BLKSZ - sz); \
+ memcpy(b + PRE ## _BLKSZ - sz, d, sz); \
+ BLKC_LOAD(PRE, ctx->iv, b); \
+ return; \
+ } \
+ \
+ /* --- Do the main chunk of encryption --- * \
+ * \
+ * This will do the whole lot if it's a whole number of blocks. For \
+ * each block, XOR it with the previous ciphertext in @iv@, encrypt, \
+ * and keep a copy of the ciphertext for the next block. \
+ */ \
+ \
+ while (sz >= 2 * PRE ## _BLKSZ || sz == PRE ## _BLKSZ) { \
+ BLKC_XLOAD(PRE, ctx->iv, s); \
+ pre ## _eblk(&ctx->ctx, ctx->iv, ctx->iv); \
+ BLKC_STORE(PRE, d, ctx->iv); \
+ s += PRE ## _BLKSZ; \
+ d += PRE ## _BLKSZ; \
+ sz -= PRE ## _BLKSZ; \
+ } \
+ \
+ /* --- Do the tail-end block and bit-left-over --- * \
+ * \
+ * This isn't very efficient. That shouldn't matter much. \
+ */ \
+ \
+ if (sz) { \
+ octet b[PRE ## _BLKSZ]; \
+ unsigned i; \
+ \
+ /* --- Let @sz@ be the size of the partial block --- */ \
+ \
+ sz -= PRE ## _BLKSZ; \
+ \
+ /* --- First stage --- * \
+ * \
+ * XOR the complete block with the current IV, and encrypt it. The \
+ * first part of the result is the partial ciphertext block. Don't \
+ * write that out yet, because I've not read the partial plaintext \
+ * block. \
+ */ \
+ \
+ BLKC_XLOAD(PRE, ctx->iv, s); \
+ pre ## _eblk(&ctx->ctx, ctx->iv, ctx->iv); \
+ BLKC_STORE(PRE, b, ctx->iv); \
+ \
+ /* --- Second stage --- * \
+ * \
+ * Now XOR in the partial plaintext block, writing out the \
+ * ciphertext as I go. Then encrypt, and write the complete \
+ * ciphertext block. \
+ */ \
+ \
+ s += PRE ## _BLKSZ; \
+ d += PRE ## _BLKSZ; \
+ for (i = 0; i < sz; i++) { \
+ register octet x = b[i]; \
+ b[i] ^= s[i]; \
+ d[i] = x; \
+ } \
+ BLKC_LOAD(PRE, ctx->iv, b); \
+ pre ## _eblk(&ctx->ctx, ctx->iv, ctx->iv); \
+ BLKC_STORE(PRE, d - PRE ## _BLKSZ, ctx->iv); \
+ } \
+ \
+ /* --- Done --- */ \
+ \
+ return; \
+} \
+ \
+/* --- @pre_cbcdecrypt@ --- * \
+ * \
+ * Arguments: @pre_cbcctx *ctx@ = pointer to CBC context block \
+ * @const void *src@ = pointer to source data \
+ * @void *dest@ = pointer to destination data \
+ * @size_t sz@ = size of block to be encrypted \
+ * \
+ * Returns: --- \
+ * \
+ * Use: Encrypts a block with a block cipher in CBC mode, with \
+ * ciphertext stealing and other clever tricks. \
+ * Essentially, data can be encrypted in arbitrary sized \
+ * chunks, although decryption must use the same chunks. \
+ */ \
+ \
+void pre ## _cbcdecrypt(pre ## _cbcctx *ctx, \
+ const void *src, void *dest, \
+ size_t sz) \
+{ \
+ const octet *s = src; \
+ octet *d = dest; \
+ \
+ /* --- Empty blocks are trivial --- */ \
+ \
+ if (!sz) \
+ return; \
+ \
+ /* --- Extra magical case for a short block --- * \
+ * \
+ * Encrypt the IV, then exclusive-or the ciphertext with the octets \
+ * of the encrypted IV, shifting ciphertext octets in instead. This \
+ * basically switches over to CFB. \
+ */ \
+ \
+ if (sz < PRE ## _BLKSZ) { \
+ octet b[PRE ## _BLKSZ], c[PRE ## _BLKSZ]; \
+ unsigned i; \
+ \
+ pre ## _eblk(&ctx->ctx, ctx->iv, ctx->iv); \
+ BLKC_STORE(PRE, b, ctx->iv); \
+ for (i = 0; i < sz; i++) { \
+ register octet x = s[i]; \
+ d[i] = b[i] ^ x; \
+ c[i] = x; \
+ } \
+ memmove(b, b + sz, PRE ## _BLKSZ - sz); \
+ memcpy(b + PRE ## _BLKSZ - sz, c, sz); \
+ BLKC_LOAD(PRE, ctx->iv, b); \
+ return; \
+ } \
+ \
+ /* --- Do the main chunk of decryption --- * \
+ * \
+ * This will do the whole lot if it's a whole number of blocks. For \
+ * each block, decrypt, XOR it with the previous ciphertext in @iv@, \
+ * and keep a copy of the ciphertext for the next block. \
+ */ \
+ \
+ while (sz >= 2 * PRE ## _BLKSZ || sz == PRE ## _BLKSZ) { \
+ uint32 b[PRE ## _BLKSZ / 4], niv[PRE ## _BLKSZ / 4]; \
+ BLKC_LOAD(PRE, niv, s); \
+ pre ## _dblk(&ctx->ctx, niv, b); \
+ BLKC_XSTORE(PRE, d, b, ctx->iv); \
+ BLKC_MOVE(PRE, ctx->iv, niv); \
+ s += PRE ## _BLKSZ; \
+ d += PRE ## _BLKSZ; \
+ sz -= PRE ## _BLKSZ; \
+ } \
+ \
+ /* --- Do the tail-end block and bit-left-over --- * \
+ * \
+ * This isn't very efficient. That shouldn't matter much. \
+ */ \
+ \
+ if (sz) { \
+ octet b[PRE ## _BLKSZ]; \
+ uint32 bk[PRE ## _BLKSZ / 4], niv[PRE ## _BLKSZ / 4]; \
+ unsigned i; \
+ \
+ /* --- Let @sz@ be the size of the partial block --- */ \
+ \
+ sz -= PRE ## _BLKSZ; \
+ \
+ /* --- First stage --- * \
+ * \
+ * Take the complete ciphertext block, and decrypt it. This block \
+ * is carried over for the next encryption operation. \
+ */ \
+ \
+ BLKC_LOAD(PRE, niv, s); \
+ pre ## _dblk(&ctx->ctx, niv, bk); \
+ \
+ /* --- Second stage --- * \
+ * \
+ * XORing the first few bytes of this with the partial ciphertext \
+ * block recovers the partial plaintext block. At the same time, \
+ * write the partial ciphertext block's contents in ready for stage \
+ * three. \
+ */ \
+ \
+ BLKC_STORE(PRE, b, bk); \
+ s += PRE ## _BLKSZ; \
+ d += PRE ## _BLKSZ; \
+ for (i = 0; i < sz; i++) { \
+ register octet x = s[i]; \
+ d[i] = b[i] ^ x; \
+ b[i] = x; \
+ } \
+ \
+ /* --- Third stage --- * \
+ * \
+ * Decrypt the block we've got left, and XOR with the initial IV to \
+ * recover the complete plaintext block. \
+ */ \
+ \
+ BLKC_LOAD(PRE, bk, b); \
+ pre ## _dblk(&ctx->ctx, bk, bk); \
+ BLKC_XSTORE(PRE, d - PRE ## _BLKSZ, bk, ctx->iv); \
+ BLKC_MOVE(PRE, ctx->iv, niv); \
+ } \
+ \
+ /* --- Done --- */ \
+ \
+ return; \
+} \
+ \
+CBC_TEST(PRE, pre)
+
+/*----- Test rig ----------------------------------------------------------*/
+
+#ifdef TEST_RIG
+
+#include <stdio.h>
+
+#include "daftstory.h"
+
+/* --- @CBC_TEST@ --- *
+ *
+ * Arguments: @PRE@, @pre@ = prefixes for block cipher definitions
+ *
+ * Use: Standard test rig for CBC functions.
+ */
+
+#define CBC_TEST(PRE, pre) \
+ \
+/* --- Initial plaintext for the test --- */ \
+ \
+static const octet text[] = TEXT; \
+ \
+/* --- Key and IV to use --- */ \
+ \
+static const octet key[] = KEY; \
+static const octet iv[] = IV; \
+ \
+/* --- Buffers for encryption and decryption output --- */ \
+ \
+static octet ct[sizeof(text)]; \
+static octet pt[sizeof(text)]; \
+ \
+static void hexdump(const octet *p, size_t sz) \
+{ \
+ const octet *q = p + sz; \
+ for (sz = 0; p < q; p++, sz++) { \
+ printf("%02x", *p); \
+ if ((sz + 1) % PRE ## _BLKSZ == 0) \
+ putchar(':'); \
+ } \
+} \
+ \
+int main(void) \
+{ \
+ size_t sz = 0, rest; \
+ pre ## _cbcctx ctx; \
+ pre ## _ctx k; \
+ int status = 0; \
+ int done = 0; \
+ \
+ size_t keysz = PRE ## _KEYSZ ? \
+ PRE ## _KEYSZ : strlen((const char *)key); \
+ \
+ fputs(#pre "-cbc: ", stdout); \
+ \
+ pre ## _init(&k, key, keysz); \
+ pre ## _cbcsetkey(&ctx, &k); \
+ \
+ while (sz <= sizeof(text)) { \
+ rest = sizeof(text) - sz; \
+ memcpy(ct, text, sizeof(text)); \
+ pre ## _cbcsetiv(&ctx, iv); \
+ pre ## _cbcencrypt(&ctx, ct, ct, sz); \
+ pre ## _cbcencrypt(&ctx, ct + sz, ct + sz, rest); \
+ memcpy(pt, ct, sizeof(text)); \
+ pre ## _cbcsetiv(&ctx, iv); \
+ pre ## _cbcdecrypt(&ctx, pt, pt, sz); \
+ pre ## _cbcdecrypt(&ctx, pt + sz, pt + sz, rest); \
+ if (memcmp(pt, text, sizeof(text)) == 0) { \
+ done++; \
+ if (sizeof(text) < 40 || done % 8 == 0) \
+ fputc('.', stdout); \
+ if (done % 480 == 0) \
+ fputs("\n\t", stdout); \
+ fflush(stdout); \
+ } else { \
+ printf("\nError (sz = %lu)\n", (unsigned long)sz); \
+ status = 1; \
+ printf("\tplaintext = "); hexdump(text, sz); \
+ printf(", "); hexdump(text + sz, rest); \
+ fputc('\n', stdout); \
+ printf("\tciphertext = "); hexdump(ct, sz); \
+ printf(", "); hexdump(ct + sz, rest); \
+ fputc('\n', stdout); \
+ printf("\trecovered text = "); hexdump(pt, sz); \
+ printf(", "); hexdump(pt + sz, rest); \
+ fputc('\n', stdout); \
+ fputc('\n', stdout); \
+ } \
+ if (sz < 63) \
+ sz++; \
+ else \
+ sz += 9; \
+ } \
+ \
+ fputs(status ? " failed\n" : " ok\n", stdout); \
+ return (status); \
+}
+
+#else
+# define CBC_TEST(PRE, pre)
+#endif
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: cfb.h,v 1.1 1999/09/03 08:41:11 mdw Exp $
+ *
+ * Ciphertext feedback for block ciphers
+ *
+ * (c) 1999 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: cfb.h,v $
+ * Revision 1.1 1999/09/03 08:41:11 mdw
+ * Initial import.
+ *
+ */
+
+#ifndef CFB_H
+#define CFB_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <string.h>
+
+#include <mLib/bits.h>
+
+#ifndef BLKC_H
+# include "blkc.h"
+#endif
+
+#ifndef PARANOIA_H
+# include "paranoia.h"
+#endif
+
+/*----- Data structures ---------------------------------------------------*/
+
+/* --- @CFB_DECL@ --- *
+ *
+ * Arguments: @PRE@, @pre@ = prefixes for the underlying block cipher
+ *
+ * Use: Creates declarations for CFB mode.
+ */
+
+#define CFB_DECL(PRE, pre) \
+ \
+typedef struct pre ## _cfbctx { \
+ pre ## _ctx ctx; /* Underlying cipher context */ \
+ int off; /* Offset into @iv@ buffer */ \
+ octet iv[PRE ## _BLKSZ]; /* Previous ciphertext or IV */ \
+} pre ## _cfbctx; \
+ \
+extern void pre ## _cfbgetiv(const pre ## _cfbctx */*ctx*/, \
+ void */*iv*/); \
+ \
+extern void pre ## _cfbsetiv(pre ## _cfbctx */*ctx*/, \
+ const void */*iv*/); \
+ \
+extern void pre ## _cfbbdry(pre ## _cfbctx */*ctx*/); \
+ \
+extern void pre ## _cfbsetkey(pre ## _cfbctx */*ctx*/, \
+ const pre ## _ctx */*k*/); \
+ \
+extern void pre ## _cfbinit(pre ## _cfbctx */*ctx*/, \
+ const void */*key*/, size_t /*sz*/, \
+ const void */*iv*/); \
+ \
+extern void pre ## _cfbencrypt(pre ## _cfbctx */*ctx*/, \
+ const void */*src*/, void */*dest*/, \
+ size_t /*sz*/); \
+ \
+extern void pre ## _cfbdecrypt(pre ## _cfbctx */*ctx*/, \
+ const void */*src*/, void */*dest*/, \
+ size_t /*sz*/); \
+
+
+/* --- @CFB_DEF@ --- *
+ *
+ * Arguments: @PRE@, @pre@ = prefixes for the underlying block cipher
+ *
+ * Use: Creates an implementation for CFB mode.
+ */
+
+#define CFB_DEF(PRE, pre) \
+ \
+/* --- @pre_cfbgetiv@ --- * \
+ * \
+ * Arguments: @const pre_cfbctx *ctx@ = pointer to CFB context block \
+ * @void *iv#@ = pointer to output data block \
+ * \
+ * Returns: --- \
+ * \
+ * Use: Reads the currently set IV. Reading and setting an IV \
+ * is not transparent to the cipher. It will add a `step' \
+ * which must be matched by a similar operation during \
+ * decryption. \
+ */ \
+ \
+void pre ## _cfbgetiv(const pre ## _cfbctx *ctx, void *iv) \
+{ \
+ octet *p = iv; \
+ int off = ctx->off; \
+ int rest = PRE ## _BLKSZ - off; \
+ memcpy(p, ctx->iv + off, rest); \
+ memcpy(p + rest, ctx->iv, off); \
+} \
+ \
+/* --- @pre_cfbsetiv@ --- * \
+ * \
+ * Arguments: @pre_cfbctx *ctx@ = pointer to CFB context block \
+ * @cnost void *iv@ = pointer to IV to set \
+ * \
+ * Returns: --- \
+ * \
+ * Use: Sets the IV to use for subsequent encryption. \
+ */ \
+ \
+void pre ## _cfbsetiv(pre ## _cfbctx *ctx, const void *iv) \
+{ \
+ uint32 niv[PRE ## _BLKSZ / 4]; \
+ BLKC_LOAD(PRE, niv, iv); \
+ pre ## _eblk(&ctx->ctx, niv, niv); \
+ BLKC_STORE(PRE, ctx->iv, niv); \
+ ctx->off = 0; \
+} \
+ \
+/* --- @pre_cfbbdry@ --- * \
+ * \
+ * Arguments: @pre_cfbctx *ctx@ = pointer to CFB context block \
+ * \
+ * Returns: --- \
+ * \
+ * Use: Inserts a boundary during encryption. Successful \
+ * decryption must place a similar boundary. \
+ */ \
+ \
+void pre ## _cfbbdry(pre ## _cfbctx *ctx) \
+{ \
+ octet iv[PRE ## _BLKSZ]; \
+ pre ## _cfbgetiv(ctx, iv); \
+ pre ## _cfbsetiv(ctx, iv); \
+ BURN(iv); \
+} \
+ \
+/* --- @pre_cfbsetkey@ --- * \
+ * \
+ * Arguments: @pre_cfbctx *ctx@ = pointer to CFB context block \
+ * @const pre_ctx *k@ = pointer to cipher context \
+ * \
+ * Returns: --- \
+ * \
+ * Use: Sets the CFB context to use a different cipher key. \
+ */ \
+ \
+void pre ## _cfbsetkey(pre ## _cfbctx *ctx, const pre ## _ctx *k) \
+{ \
+ ctx->ctx = *k; \
+} \
+ \
+/* --- @pre_cfbinit@ --- * \
+ * \
+ * Arguments: @pre_cfbctx *ctx@ = pointer to cipher context \
+ * @const void *key@ = pointer to the key buffer \
+ * @size_t sz@ = size of the key \
+ * @const void *iv@ = pointer to initialization vector \
+ * \
+ * Returns: --- \
+ * \
+ * Use: Initializes a CFB context ready for use. You should \
+ * ensure that the IV chosen is unique: reusing an IV will \
+ * compromise the security of at least the first block \
+ * encrypted. This is equivalent to calls to @pre_init@, \
+ * @pre_cfbsetkey@ and @pre_cfbsetiv@. \
+ */ \
+ \
+void pre ## _cfbinit(pre ## _cfbctx *ctx, \
+ const void *key, size_t sz, \
+ const void *iv) \
+{ \
+ static octet zero[PRE ## _BLKSZ] = { 0 }; \
+ pre ## _init(&ctx->ctx, key, sz); \
+ pre ## _cfbsetiv(ctx, iv ? iv : zero); \
+} \
+ \
+/* --- @pre_cfbencrypt@ --- * \
+ * \
+ * Arguments: @pre_cfbctx *ctx@ = pointer to CFB context block \
+ * @const void *src@ = pointer to source data \
+ * @void *dest@ = pointer to destination data \
+ * @size_t sz@ = size of block to be encrypted \
+ * \
+ * Returns: --- \
+ * \
+ * Use: Encrypts a block with a block cipher in CFB mode. The \
+ * input block may be arbitrary in size. CFB mode is not \
+ * sensitive to block boundaries. \
+ */ \
+ \
+void pre ## _cfbencrypt(pre ## _cfbctx *ctx, \
+ const void *src, void *dest, \
+ size_t sz) \
+{ \
+ const octet *s = src; \
+ octet *d = dest; \
+ int off = ctx->off; \
+ \
+ /* --- Empty blocks are trivial --- */ \
+ \
+ if (!sz) \
+ return; \
+ \
+ /* --- If I can deal with the block from my buffer, do that --- */ \
+ \
+ if (sz < PRE ## _BLKSZ - off) \
+ goto small; \
+ \
+ /* --- Finish off what's left in my buffer --- */ \
+ \
+ while (off < PRE ## _BLKSZ) { \
+ register octet x = *s++; \
+ *d++ = ctx->iv[off++] ^= x; \
+ sz--; \
+ } \
+ \
+ /* --- Main encryption loop --- */ \
+ \
+ { \
+ uint32 iv[PRE ## _BLKSZ / 4]; \
+ BLKC_LOAD(PRE, iv, ctx->iv); \
+ \
+ for (;;) { \
+ pre ## _eblk(&ctx->ctx, iv, iv); \
+ if (sz < PRE ## _BLKSZ) \
+ break; \
+ BLKC_XLOAD(PRE, iv, s); \
+ BLKC_STORE(PRE, d, iv); \
+ s += PRE ## _BLKSZ; \
+ d += PRE ## _BLKSZ; \
+ sz -= PRE ## _BLKSZ; \
+ } \
+ off = 0; \
+ BLKC_STORE(PRE, ctx->iv, iv); \
+ } \
+ \
+ /* --- Tidying up the tail end --- */ \
+ \
+ if (sz) { \
+ small: \
+ do { \
+ register octet x = *s++; \
+ *d++ = ctx->iv[off++] ^= x; \
+ sz--; \
+ } while (sz); \
+ } \
+ \
+ /* --- Done --- */ \
+ \
+ ctx->off = off; \
+ return; \
+} \
+ \
+/* --- @pre_cfbdecrypt@ --- * \
+ * \
+ * Arguments: @pre_cfbctx *ctx@ = pointer to CFB context block \
+ * @const void *src@ = pointer to source data \
+ * @void *dest@ = pointer to destination data \
+ * @size_t sz@ = size of block to be encrypted \
+ * \
+ * Returns: --- \
+ * \
+ * Use: Encrypts a block with a block cipher in CFB mode, with \
+ * ciphertext stealing and other clever tricks. \
+ * Essentially, data can be encrypted in arbitrary sized \
+ * chunks, although decryption must use the same chunks. \
+ */ \
+ \
+void pre ## _cfbdecrypt(pre ## _cfbctx *ctx, \
+ const void *src, void *dest, \
+ size_t sz) \
+{ \
+ const octet *s = src; \
+ octet *d = dest; \
+ int off = ctx->off; \
+ \
+ /* --- Empty blocks are trivial --- */ \
+ \
+ if (!sz) \
+ return; \
+ \
+ /* --- If I can deal with the block from my buffer, do that --- */ \
+ \
+ if (sz < PRE ## _BLKSZ - off) \
+ goto small; \
+ \
+ /* --- Finish off what's left in my buffer --- */ \
+ \
+ while (off < PRE ## _BLKSZ) { \
+ register octet x = *s++; \
+ *d++ = ctx->iv[off] ^ x; \
+ ctx->iv[off++] = x; \
+ sz--; \
+ } \
+ \
+ /* --- Main encryption loop --- */ \
+ \
+ { \
+ uint32 iv[PRE ## _BLKSZ / 4]; \
+ BLKC_LOAD(PRE, iv, ctx->iv); \
+ \
+ for (;;) { \
+ uint32 x[PRE ## _BLKSZ / 4]; \
+ pre ## _eblk(&ctx->ctx, iv, iv); \
+ if (sz < PRE ## _BLKSZ) \
+ break; \
+ BLKC_LOAD(PRE, x, s); \
+ BLKC_XSTORE(PRE, d, iv, x); \
+ BLKC_MOVE(PRE, iv, x); \
+ s += PRE ## _BLKSZ; \
+ d += PRE ## _BLKSZ; \
+ sz -= PRE ## _BLKSZ; \
+ } \
+ off = 0; \
+ BLKC_STORE(PRE, ctx->iv, iv); \
+ } \
+ \
+ /* --- Tidying up the tail end --- */ \
+ \
+ if (sz) { \
+ small: \
+ do { \
+ register octet x = *s++; \
+ *d++ = ctx->iv[off] ^ x; \
+ ctx->iv[off++] = x; \
+ sz--; \
+ } while (sz); \
+ } \
+ \
+ /* --- Done --- */ \
+ \
+ ctx->off = off; \
+ return; \
+} \
+ \
+CFB_TEST(PRE, pre)
+
+/*----- Test rig ----------------------------------------------------------*/
+
+#ifdef TEST_RIG
+
+#include <stdio.h>
+
+#include "daftstory.h"
+
+/* --- @CFB_TEST@ --- *
+ *
+ * Arguments: @PRE@, @pre@ = prefixes for block cipher definitions
+ *
+ * Use: Standard test rig for CFB functions.
+ */
+
+#define CFB_TEST(PRE, pre) \
+ \
+/* --- Initial plaintext for the test --- */ \
+ \
+static const octet text[] = TEXT; \
+ \
+/* --- Key and IV to use --- */ \
+ \
+static const octet key[] = KEY; \
+static const octet iv[] = IV; \
+ \
+/* --- Buffers for encryption and decryption output --- */ \
+ \
+static octet ct[sizeof(text)]; \
+static octet pt[sizeof(text)]; \
+ \
+static void hexdump(const octet *p, size_t sz) \
+{ \
+ const octet *q = p + sz; \
+ for (sz = 0; p < q; p++, sz++) { \
+ printf("%02x", *p); \
+ if ((sz + 1) % PRE ## _BLKSZ == 0) \
+ putchar(':'); \
+ } \
+} \
+ \
+int main(void) \
+{ \
+ size_t sz = 0, rest; \
+ pre ## _cfbctx ctx; \
+ int status = 0; \
+ int done = 0; \
+ pre ## _ctx k; \
+ \
+ size_t keysz = PRE ## _KEYSZ ? \
+ PRE ## _KEYSZ : strlen((const char *)key); \
+ \
+ fputs(#pre "-cfb: ", stdout); \
+ \
+ pre ## _init(&k, key, keysz); \
+ pre ## _cfbsetkey(&ctx, &k); \
+ \
+ while (sz <= sizeof(text)) { \
+ rest = sizeof(text) - sz; \
+ memcpy(ct, text, sizeof(text)); \
+ pre ## _cfbsetiv(&ctx, iv); \
+ pre ## _cfbencrypt(&ctx, ct, ct, sz); \
+ pre ## _cfbencrypt(&ctx, ct + sz, ct + sz, rest); \
+ memcpy(pt, ct, sizeof(text)); \
+ pre ## _cfbsetiv(&ctx, iv); \
+ pre ## _cfbdecrypt(&ctx, pt, pt, rest); \
+ pre ## _cfbdecrypt(&ctx, pt + rest, pt + rest, sz); \
+ if (memcmp(pt, text, sizeof(text)) == 0) { \
+ done++; \
+ if (sizeof(text) < 40 || done % 8 == 0) \
+ fputc('.', stdout); \
+ if (done % 480 == 0) \
+ fputs("\n\t", stdout); \
+ fflush(stdout); \
+ } else { \
+ printf("\nError (sz = %lu)\n", (unsigned long)sz); \
+ status = 1; \
+ printf("\tplaintext = "); hexdump(text, sz); \
+ printf(", "); hexdump(text + sz, rest); \
+ fputc('\n', stdout); \
+ printf("\tciphertext = "); hexdump(ct, sz); \
+ printf(", "); hexdump(ct + sz, rest); \
+ fputc('\n', stdout); \
+ printf("\trecovered text = "); hexdump(pt, sz); \
+ printf(", "); hexdump(pt + sz, rest); \
+ fputc('\n', stdout); \
+ fputc('\n', stdout); \
+ } \
+ if (sz < 63) \
+ sz++; \
+ else \
+ sz += 9; \
+ } \
+ \
+ fputs(status ? " failed\n" : " ok\n", stdout); \
+ return (status); \
+}
+
+#else
+# define CFB_TEST(PRE, pre)
+#endif
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
--- /dev/null
+dnl -*-fundamental-*-
+dnl
+dnl $Id: configure.in,v 1.1 1999/09/03 08:41:11 mdw Exp $
+dnl
+dnl Autoconfiguration for Catacomb
+dnl
+dnl (c) 1999 Straylight/Edgeware
+dnl
+
+dnl ----- Licensing notice --------------------------------------------------
+dnl
+dnl This file is part of Catacomb.
+dnl
+dnl Catacomb is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU Library General Public License as
+dnl published by the Free Software Foundation; either version 2 of the
+dnl License, or (at your option) any later version.
+dnl
+dnl Catacomb is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+dnl GNU Library General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU Library General Public
+dnl License along with Catacomb; if not, write to the Free
+dnl Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+dnl MA 02111-1307, USA.
+
+dnl ----- Revision history --------------------------------------------------
+dnl
+dnl $Log: configure.in,v $
+dnl Revision 1.1 1999/09/03 08:41:11 mdw
+dnl Initial import.
+dnl
+dnl Revision 1.1 1999/09/03 08:41:11 mdw
+dnl Initial import.
+dnl
+
+AM_INIT_AUTOMAKE(catacomb, 1.0.0pre1)
+
+AC_INIT(blkc.h)
+AM_INIT_AUTOMAKE(catacomb, 1.0.0pre2)
+AM_CONFIG_HEADER(config.h)
+
+dnl --- Make sure I can compile and build libraries ---
+
+AC_PROG_CC
+AC_CHECK_PROG(AR, ar, ar)
+AC_PROG_RANLIB
+mdw_MLIB
+
+AC_PROG_YACC
+
+dnl --- Actually, I assume these exist anyway ---
+
+AC_CHECK_HEADERS(unistd.h)
+AC_HEADER_STDC
+
+dnl --- Check for various important system types ---
+
+AC_TYPE_PID_T
+
+dnl --- Tedious check for ssize_t ---
+dnl
+dnl glibc-2 puts ssize_t in a strange place.
+
+AC_CACHE_CHECK(for ssize_t, cat_cv_type_ssize_t,
+[AC_EGREP_CPP(ssize_t,
+[#include <sys/types.h>
+#if HAVE_UNISTD_H
+#inlcude <unistd.h>
+#endif
+#if STDC_HEADERS
+#include <stddef.h>
+#include <stdlib.h>
+#endif],
+cat_cv_type_ssize_t=yes, cat_cv_type_ssize_t=no)])
+if test $cat_cv_type_ssize_t = no; then
+ AC_DEFINE(ssize_t, int)
+fi
+AC_TYPE_UID_T
+AC_CHECK_TYPE(time_t, long)
+mdw_TYPE_SSIZE_T
+
+dnl --- Can I call `initgroups'? ---
+dnl
+dnl This is used in noise-gathering.
+
+AC_CHECK_FUNCS(setgroups)
+AC_OUTPUT(Makefile)
+dnl --- Done ---
+
+AC_OUTPUT(Makefile catacomb-config)
+
+dnl ----- That's all, folks -------------------------------------------------
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: daftstory.h,v 1.1 1999/09/03 08:41:11 mdw Exp $
+ *
+ * Daft story for use in test encryptions
+ *
+ * (c) 1999 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: daftstory.h,v $
+ * Revision 1.1 1999/09/03 08:41:11 mdw
+ * Initial import.
+ *
+ */
+
+#ifndef DAFTSTORY_H
+#define DAFTSTORY_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*----- Macros ------------------------------------------------------------*/
+
+/* --- Don't ask --- */
+
+#ifdef SMALL_TEST
+# define TEXT "A small piece of text for testing encryption."
+#else
+# define STORY "\
+Once upon a time there were a beautiful princess, a slightly nutty wizard,\n\
+and a watermelon. Now, the watermelon had decided that it probably wasn't\n\
+going to get very far with the princess unless it did something pretty\n\
+drastic. So it asked the wizard to turn it into a handsome prince.\n\
+\n\
+At least, this is the way that the wizard viewed the situation. He might\n\
+have just hallucinated it all; those mushrooms had looked ever so nice.\n\
+\n\
+Back to the point. The watermelon had expressed its desire not to be a\n\
+watermelon any more. And the wizard was probably tripping something quite\n\
+powerful. He hunted around a bit for his staff, and mumbled something\n\
+that film directors would think of as sounding appropriately arcane and\n\
+mystical (but was, in fact, just the ingredients list for an ancient\n\
+remedy for athlete's foot) and *pop*. Cooked watermelon. Yuk.\n\
+\n\
+Later in the year, the princess tripped over the hem of her dress, fell\n\
+down a spiral staircase, and died. The king ordered dressmakers to attach\n\
+safety warnings to long dresses.\n\
+\n\
+And the wizard? Who cares?\n\
+"
+# define TEXT STORY STORY STORY
+#endif
+
+#define KEY "Penguins rule OK, rhubarb cauliflower"
+#define IV "EdgewareCatacomb, parsley, sage, rosemary and thyme"
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: des-base.c,v 1.1 1999/09/03 08:41:11 mdw Exp $
+ *
+ * Common features for DES implementation
+ *
+ * (c) 1999 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: des-base.c,v $
+ * Revision 1.1 1999/09/03 08:41:11 mdw
+ * Initial import.
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <mLib/bits.h>
+
+#include "des-base.h"
+#include "des_sp.h"
+
+/*----- Global variables --------------------------------------------------*/
+
+uint32 des_sp[8][64] = DES_SP;
+
+/*----- That's all, folks -------------------------------------------------*/
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: des-base.h,v 1.1 1999/09/03 08:41:11 mdw Exp $
+ *
+ * Common features for DES implementation
+ *
+ * (c) 1999 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: des-base.h,v $
+ * Revision 1.1 1999/09/03 08:41:11 mdw
+ * Initial import.
+ *
+ */
+
+#ifndef DES_BASE_H
+#define DES_BASE_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <mLib/bits.h>
+
+/*----- External data -----------------------------------------------------*/
+
+extern uint32 des_sp[8][64];
+
+/*----- Macros ------------------------------------------------------------*/
+
+/* --- @DES_ROUND@ --- *
+ *
+ * This is the basic DES round function. The inputs are the two subkey
+ * halves, and the left and right block halves. Note that the block halves
+ * are rotated left one place at this point. This wraps what's meant to be
+ * the top bit around to the bottom, so I get a clear run at the S-boxes.
+ */
+
+#define DES_ROUND(ka, kb, x, y) do { \
+ uint32 _t = (y) ^ (ka); \
+ (x) ^= des_sp[7][(_t >> 0) & 0x3f] ^ \
+ des_sp[5][(_t >> 8) & 0x3f] ^ \
+ des_sp[3][(_t >> 16) & 0x3f] ^ \
+ des_sp[1][(_t >> 24) & 0x3f]; \
+ _t = ROR32((y), 4) ^ (kb); \
+ (x) ^= des_sp[6][(_t >> 0) & 0x3f] ^ \
+ des_sp[4][(_t >> 8) & 0x3f] ^ \
+ des_sp[2][(_t >> 16) & 0x3f] ^ \
+ des_sp[0][(_t >> 24) & 0x3f]; \
+} while (0)
+
+/* --- @DES_IP@, @DES_IPINV@ --- *
+ *
+ * The cryptographically useless initial and final permutations. The initial
+ * permutation also rotates the two block halves left by one place. This is
+ * undone by the inverse permutation at the end.
+ */
+
+#define DES_IP(x, y) do { \
+ uint32 _t; \
+ _t = (y ^ (x >> 4)) & 0x0f0f0f0f; y ^= _t; x ^= _t << 4; \
+ _t = (x ^ (x >> 18)) & 0x00003333; x ^= _t; x ^= _t << 18; \
+ _t = (y ^ (y >> 18)) & 0x00003333; y ^= _t; y ^= _t << 18; \
+ _t = (x ^ (x >> 9)) & 0x00550055; x ^= _t; x ^= _t << 9; \
+ _t = (y ^ (y >> 9)) & 0x00550055; y ^= _t; y ^= _t << 9; \
+ _t = (x ^ (x >> 24)) & 0x000000ff; x ^= _t; x ^= _t << 24; \
+ _t = (y ^ (y >> 24)) & 0x000000ff; y ^= _t; y ^= _t << 24; \
+ _t = (y ^ (x >> 16)) & 0x0000ffff; y ^= _t; x ^= _t << 16; \
+ x = ROL32(x, 1); y = ROL32(y, 1); \
+} while (0)
+
+#define DES_IPINV(x, y) do { \
+ uint32 _t; \
+ x = ROR32(x, 1); y = ROR32(y, 1); \
+ _t = (y ^ (x >> 16)) & 0x0000ffff; y ^= _t; x ^= _t << 16; \
+ _t = (x ^ (x >> 24)) & 0x000000ff; x ^= _t; x ^= _t << 24; \
+ _t = (y ^ (y >> 24)) & 0x000000ff; y ^= _t; y ^= _t << 24; \
+ _t = (y ^ (x >> 4)) & 0x0f0f0f0f; y ^= _t; x ^= _t << 4; \
+ _t = (x ^ (x >> 18)) & 0x00003333; x ^= _t; x ^= _t << 18; \
+ _t = (y ^ (y >> 18)) & 0x00003333; y ^= _t; y ^= _t << 18; \
+ _t = (x ^ (x >> 9)) & 0x00550055; x ^= _t; x ^= _t << 9; \
+ _t = (y ^ (y >> 9)) & 0x00550055; y ^= _t; y ^= _t << 9; \
+} while (0)
+
+/* --- @DES_EBLK@, @DES_DBLK@ --- *
+ *
+ * Whole block encryption and decryption.
+ */
+
+#define DES_EBLK(k, a, b, c, d) do { \
+ const uint32 *_k = (k); \
+ uint32 _x = (a), _y = (b); \
+ DES_ROUND(_k[0], _k[1], _x, _y); _k += 2; \
+ DES_ROUND(_k[0], _k[1], _y, _x); _k += 2; \
+ DES_ROUND(_k[0], _k[1], _x, _y); _k += 2; \
+ DES_ROUND(_k[0], _k[1], _y, _x); _k += 2; \
+ DES_ROUND(_k[0], _k[1], _x, _y); _k += 2; \
+ DES_ROUND(_k[0], _k[1], _y, _x); _k += 2; \
+ DES_ROUND(_k[0], _k[1], _x, _y); _k += 2; \
+ DES_ROUND(_k[0], _k[1], _y, _x); _k += 2; \
+ DES_ROUND(_k[0], _k[1], _x, _y); _k += 2; \
+ DES_ROUND(_k[0], _k[1], _y, _x); _k += 2; \
+ DES_ROUND(_k[0], _k[1], _x, _y); _k += 2; \
+ DES_ROUND(_k[0], _k[1], _y, _x); _k += 2; \
+ DES_ROUND(_k[0], _k[1], _x, _y); _k += 2; \
+ DES_ROUND(_k[0], _k[1], _y, _x); _k += 2; \
+ DES_ROUND(_k[0], _k[1], _x, _y); _k += 2; \
+ DES_ROUND(_k[0], _k[1], _y, _x); _k += 2; \
+ (c) = _y; \
+ (d) = _x; \
+} while (0)
+
+#define DES_DBLK(k, a, b, c, d) do { \
+ const uint32 *_k = (k) + 32; \
+ uint32 _x = (a), _y = (b); \
+ _k -= 2; DES_ROUND(_k[0], _k[1], _x, _y); \
+ _k -= 2; DES_ROUND(_k[0], _k[1], _y, _x); \
+ _k -= 2; DES_ROUND(_k[0], _k[1], _x, _y); \
+ _k -= 2; DES_ROUND(_k[0], _k[1], _y, _x); \
+ _k -= 2; DES_ROUND(_k[0], _k[1], _x, _y); \
+ _k -= 2; DES_ROUND(_k[0], _k[1], _y, _x); \
+ _k -= 2; DES_ROUND(_k[0], _k[1], _x, _y); \
+ _k -= 2; DES_ROUND(_k[0], _k[1], _y, _x); \
+ _k -= 2; DES_ROUND(_k[0], _k[1], _x, _y); \
+ _k -= 2; DES_ROUND(_k[0], _k[1], _y, _x); \
+ _k -= 2; DES_ROUND(_k[0], _k[1], _x, _y); \
+ _k -= 2; DES_ROUND(_k[0], _k[1], _y, _x); \
+ _k -= 2; DES_ROUND(_k[0], _k[1], _x, _y); \
+ _k -= 2; DES_ROUND(_k[0], _k[1], _y, _x); \
+ _k -= 2; DES_ROUND(_k[0], _k[1], _x, _y); \
+ _k -= 2; DES_ROUND(_k[0], _k[1], _y, _x); \
+ (c) = _y; \
+ (d) = _x; \
+} while (0)
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: des-mktab.c,v 1.1 1999/09/03 08:41:11 mdw Exp $
+ *
+ * Build combined S-P tables for DES
+ *
+ * (c) 1999 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: des-mktab.c,v $
+ * Revision 1.1 1999/09/03 08:41:11 mdw
+ * Initial import.
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <mLib/bits.h>
+
+/*----- Static variables --------------------------------------------------*/
+
+/* --- S boxes --- */
+
+static char s[8][4][16] = {
+
+ /* --- S1 --- */
+
+ { { 14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7 },
+ { 0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8 },
+ { 4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0 },
+ { 15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13 } },
+
+ /* --- S2 --- */
+
+ { { 15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10 },
+ { 3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5 },
+ { 0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15 },
+ { 13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9 } },
+
+ /* --- S3 --- */
+
+ { { 10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8 },
+ { 13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1 },
+ { 13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7 },
+ { 1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12 } },
+
+ /* --- S4 --- */
+
+ { { 7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15 },
+ { 13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9 },
+ { 10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4 },
+ { 3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14 } },
+
+ /* --- S5 --- */
+
+ { { 2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9 },
+ { 14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6 },
+ { 4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14 },
+ { 11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3 } },
+
+ /* --- S6 --- */
+
+ { { 12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11 },
+ { 10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8 },
+ { 9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6 },
+ { 4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13 } },
+
+ /* --- S7 --- */
+
+ { { 4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1 },
+ { 13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6 },
+ { 1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2 },
+ { 6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12 } },
+
+ /* --- S8 --- */
+
+ { { 13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7 },
+ { 1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2 },
+ { 7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8 },
+ { 2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11 } }
+};
+
+/* --- P table --- */
+
+static char p[32] = {
+ 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10,
+ 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25
+};
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @unique@ --- *
+ *
+ * Arguments: @const char *t@ = pointer to table
+ * @int base@ = base of the data
+ * @int sz@ = number of elements
+ * @const char *name@ = name of this table
+ * @...@ = things to fill in
+ *
+ * Returns: Zero if it failed, nonzero if it didn't.
+ *
+ * Use: Validates a table. All the elements must be in range and
+ * unique.
+ */
+
+static int unique(char *t, int base, int sz, const char *name, ...)
+{
+ char u[32];
+ char nbuf[128];
+ int i;
+ int ok = 1;
+
+ {
+ va_list ap;
+ va_start(ap, name);
+ vsprintf(nbuf, name, ap);
+ va_end(ap);
+ }
+
+ if (sz > sizeof(u)) {
+ fprintf(stderr, "internal error: table `%s' too large\n", nbuf);
+ exit(EXIT_FAILURE);
+ }
+ memset(u, 0, sizeof(u));
+ for (i = 0; i < sz; i++) {
+ int x = t[i] - base;
+ if (x >= sz) {
+ fprintf(stderr, "validation error: %i too big (index %i) in %s\n",
+ x + base, i, nbuf);
+ ok = 0;
+ } else if (u[x]) {
+ fprintf(stderr, "validation error: duplicate %i (index %i) in %s\n",
+ x + base, i, nbuf);
+ ok = 0;
+ }
+ u[x] = 1;
+ }
+ for (i = 0; i < sz; i++) {
+ if (!u[i]) {
+ fprintf(stderr, "validation error: missing %i in %s\n",
+ i + base, nbuf);
+ ok = 0;
+ }
+ }
+
+ return (ok);
+}
+
+/* --- @validate@ --- *
+ *
+ * Arguments: ---
+ *
+ * Returns: Only if everything's OK.
+ *
+ * Use: Validates the tables. A bit. Not much at all...
+ */
+
+static void validate(void)
+{
+ int i, j;
+ int ok = 1;
+
+ for (i = 0; i < 8; i++) for (j = 0; j < 4; j++)
+ if (!unique(s[i][j], 0, 16, "sbox %i, row %i", i, j)) ok = 0;
+ if (!unique(p, 1, 32, "p")) ok = 0;
+ if (!ok)
+ exit(EXIT_FAILURE);
+}
+
+/* --- @permute@ --- *
+ *
+ * Arguments: @unsigned long x@ = value to permute
+ *
+ * Returns: Permuted version of @x@.
+ *
+ * Use: Permutes a number. The result is the input value after
+ * having been spewed through the @P@ permutation, and then
+ * (and this is important) rotated left one place.
+ */
+
+static unsigned long permute(unsigned long x)
+{
+ unsigned long y = 0;
+ unsigned i;
+
+ for (i = 0; i < 32; i++) {
+ if (x & (1 << (32 - p[i])))
+ y |= (1 << (31 - i));
+ }
+ return (ROL32(y, 1));
+}
+
+/* --- @mangle@ --- *
+ *
+ * Arguments: @const char s[4][16]@ = an s-box
+ * @unsigned long ss[64]@ = output buffer
+ * @int bitoff@ = bit offset to use
+ *
+ * Returns: ---
+ *
+ * Use: Mangles the s-box. Specifically, the bizarre indexing is
+ * transformed into something sensible, and the result is
+ * permuted according to the @p@ table.
+ */
+
+static void mangle(const char s[4][16], unsigned long *ss, int bitoff)
+{
+ unsigned i;
+ for (i = 0; i < 64; i++) {
+ unsigned row = ((i & 0x20) >> 4) | (i & 0x01);
+ unsigned col = (i & 0x1e) >> 1;
+ ss[i] = permute(s[row][col] << bitoff);
+ }
+}
+
+/* --- @main@ --- */
+
+int main(void)
+{
+ int i, j;
+ unsigned long ss[64];
+ const char *sep;
+
+ validate();
+
+ fputs("\
+/* DES SP table (generated) */\n\
+\n\
+#define DES_SP { \\\n\
+", stdout);
+ for (i = 0; i < 8; i++) {
+ mangle(s[i], ss, 28 - 4 * i);
+ printf("\
+ \\\n\
+ /* --- SP[%i] --- */ \\\n\
+ \\\n\
+", i);
+ sep = " { ";
+ for (j = 0; j < 64; j++) {
+ printf("%s0x%08lx", sep, ss[j]);
+ if (j % 4 == 3)
+ sep = ", \\\n ";
+ else
+ sep = ", ";
+ }
+ printf(" }%s \\\n", i == 7 ? "" : ",");
+ }
+ fputs("}\n", stdout);
+ return (0);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: des.c,v 1.1 1999/09/03 08:41:11 mdw Exp $
+ *
+ * The Data Encryption Standard
+ *
+ * (c) 1999 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: des.c,v $
+ * Revision 1.1 1999/09/03 08:41:11 mdw
+ * Initial import.
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <mLib/bits.h>
+
+#include "blkc.h"
+#include "des-base.h"
+#include "des.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @permute@ --- *
+ *
+ * Arguments: @const char *p@ = pointer to permutation table
+ * @uint32 a, b@ = source value to permute
+ * @uint32 *d@ = destination for value
+ *
+ * Returns: ---
+ *
+ * Use: Performs a 64-bit permutation. The table is given in the
+ * normal (but bizarre) DES bit numbering system. That's not to
+ * say that the tables in this source file are like the normal
+ * DES tables, because they're not.
+ */
+
+static void permute(const char *p, uint32 a, uint32 b, uint32 *d)
+{
+ uint32 x = 0, y = 0;
+ int i;
+
+ for (i = 0; i < 32; i++) {
+ int q = p[i];
+ uint32 t;
+ if (!q)
+ continue;
+ else if (q <= 32)
+ t = a;
+ else {
+ t = b;
+ q -= 32;
+ }
+ if (t & (1 << (32 - q)))
+ x |= (1 << (31 - i));
+ }
+
+ p += 32;
+
+ for (i = 0; i < 32; i++) {
+ int q = p[i];
+ uint32 t;
+ if (!q)
+ continue;
+ else if (q <= 32)
+ t = a;
+ else {
+ t = b;
+ q -= 32;
+ }
+ if (t & (1 << (32 - q)))
+ y |= (1 << (31 - i));
+ }
+
+ d[0] = x;
+ d[1] = y;
+}
+
+/* --- @des_init@ --- *
+ *
+ * Arguments: @des_ctx *k@ = pointer to key block
+ * @const void *buf@ = pointer to key buffer
+ * @size_t sz@ = size of key material
+ *
+ * Returns: ---
+ *
+ * Use: Initializes a DES key buffer. The key buffer may be either 7
+ * or 8 bytes long. If it's 8 bytes, the key is assumed to be
+ * padded with parity bits in the low order bit of each octet.
+ * These are stripped out without checking prior to the actual
+ * key scheduling.
+ */
+
+void des_init(des_ctx *k, const void *buf, size_t sz)
+{
+ uint32 x, y;
+ uint32 *kp = k->k;
+ int i;
+
+ /* --- @pc1@ --- *
+ *
+ * This cryptographically useless permutation is used to mangle the key
+ * before it's subjected to the key schedule proper. I've not actually
+ * messed it about much except for inserting padding at the beginning of
+ * the two halves of the key.
+ */
+
+ static const char pc1[] = {
+ 0, 0, 0, 0,
+ 57, 49, 41, 33, 25, 17, 9,
+ 1, 58, 50, 42, 34, 26, 18,
+ 10, 2, 59, 51, 43, 35, 27,
+ 19, 11, 3, 60, 52, 44, 36,
+ 0, 0, 0, 0,
+ 63, 55, 47, 39, 31, 23, 15,
+ 7, 62, 54, 46, 38, 30, 22,
+ 14, 6, 61, 53, 45, 37, 29,
+ 21, 13, 5, 28, 20, 12, 4
+ };
+
+ /* --- @pc2@ --- *
+ *
+ * This irritating but necessary permutation mangles the key between the
+ * simple rotation-based schedule and the actual XOR with which it modifies
+ * the behaviour of the cipher.
+ *
+ * This version of the table doesn't look much like the original. This is
+ * because some parts of the world have been permuted in order to make
+ * things simpler for the round function. In particular, everything is
+ * rotated left one place to avoid problems with the wraparound of the
+ * expansion permutation, and the key is split between odd and even S-boxes
+ * rather than high and low ones. That's without the complication of the
+ * padding bits in the representation of the 56-bit proto-key.
+ */
+
+ static const char pc2[] = {
+ 0, 0, 3 + 4, 28 + 4, 15 + 4, 6 + 4, 21 + 4, 10 + 4, /* S-box 2 */
+ 0, 0, 16 + 4, 7 + 4, 27 + 4, 20 + 4, 13 + 4, 2 + 4, /* S-box 4 */
+ 0, 0, 30 + 8, 40 + 8, 51 + 8, 45 + 8, 33 + 8, 48 + 8, /* S-box 6 */
+ 0, 0, 46 + 8, 42 + 8, 50 + 8, 36 + 8, 29 + 8, 32 + 8, /* S-box 8 */
+ 0, 0, 14 + 4, 17 + 4, 11 + 4, 24 + 4, 1 + 4, 5 + 4, /* S-box 1 */
+ 0, 0, 23 + 4, 19 + 4, 12 + 4, 4 + 4, 26 + 4, 8 + 4, /* S-box 3 */
+ 0, 0, 41 + 8, 52 + 8, 31 + 8, 37 + 8, 47 + 8, 55 + 8, /* S-box 5 */
+ 0, 0, 44 + 8, 49 + 8, 39 + 8, 56 + 8, 34 + 8, 53 + 8 /* S-box 7 */
+ };
+
+ /* --- @v@ --- *
+ *
+ * Contains the rotation amounts for the key halves.
+ */
+
+ static const char v[] = {
+ 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
+ };
+
+ /* --- Extract the key into my registers --- *
+ *
+ * The 7 byte case is rather horrible. It expands the key to the 8 byte
+ * case before going any further. It could probably do with its own @pc1@
+ * table.
+ */
+
+ assert(((void)"DES key must be 56 or 64 bits", sz == 7 || sz == 8));
+
+ if (sz == 8) {
+ const octet *p = buf;
+ x = LOAD32(p); y = LOAD32(p + 4);
+ } else {
+ const octet *p = buf;
+ x = LOAD32(p);
+ x = (x & 0xfe000000) | ((x & 0x01fffff0) >> 1);
+ x = (x & 0xfffe0000) | ((x & 0x0001fff8) >> 1);
+ x = (x & 0xfffffe00) | ((x & 0x000001fc) >> 1);
+ y = LOAD32(p + 3) << 1; /* Note: misaligned */
+ y = (y & 0x000000fe) | ((y & 0x1fffff00) << 1);
+ y = (y & 0x0000fefe) | ((y & 0x3fff0000) << 1);
+ y = (y & 0x00fefefe) | ((y & 0x7f000000) << 1);
+ }
+
+ /* --- Permute using the pointless PC1 --- */
+
+ {
+ uint32 ka[2];
+ permute(pc1, x, y, ka);
+ x = ka[0]; y = ka[1];
+ }
+
+ /* --- Now for the key schedule proper --- */
+
+ for (i = 0; i < 16; i++) {
+ if (v[i] == 1) {
+ x = ((x << 1) | (x >> 27)) & 0x0fffffff;
+ y = ((y << 1) | (y >> 27)) & 0x0fffffff;
+ } else {
+ x = ((x << 2) | (x >> 26)) & 0x0fffffff;
+ y = ((y << 2) | (y >> 26)) & 0x0fffffff;
+ }
+ permute(pc2, x, y, kp);
+ kp += 2;
+ }
+}
+
+/* --- @des_eblk@, @des_dblk@ --- *
+ *
+ * Arguments: @const des_ctx *k@ = pointer to key block
+ * @const uint32 s[2]@ = pointer to source block
+ * @uint32 d[2]@ = pointer to destination block
+ *
+ * Returns: ---
+ *
+ * Use: Low-level block encryption and decryption.
+ */
+
+void des_eblk(const des_ctx *k, const uint32 *s, uint32 *d)
+{
+ uint32 x = s[0], y = s[1];
+ DES_IP(x, y);
+ DES_EBLK(k->k, x, y, x, y);
+ DES_IPINV(x, y);
+ d[0] = x, d[1] = y;
+}
+
+void des_dblk(const des_ctx *k, const uint32 *s, uint32 *d)
+{
+ uint32 x = s[0], y = s[1];
+ DES_IP(x, y);
+ DES_DBLK(k->k, x, y, x, y);
+ DES_IPINV(x, y);
+ d[0] = x, d[1] = y;
+}
+
+BLKC_TEST(DES, des)
+
+/*----- That's all, folks -------------------------------------------------*/
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: des.h,v 1.1 1999/09/03 08:41:11 mdw Exp $
+ *
+ * The Data Encryption Standard
+ *
+ * (c) 1999 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: des.h,v $
+ * Revision 1.1 1999/09/03 08:41:11 mdw
+ * Initial import.
+ *
+ */
+
+/*----- Notes on the Data Encryption Standard -----------------------------*
+ *
+ * Almost twenty years after it was first accepted, DES is still the standard
+ * block cipher. It's showing its age in its small key size and poor
+ * optimiziation for software implementations, but it's not really been badly
+ * dented by the intensive analysis thrown at it.
+ *
+ * This interface is here for compatibility with existing protocols, and
+ * because it's a trivial veneer over the base DES code which is used by the
+ * @des3@ interface which implements proper strong triple-DES.
+ */
+
+#ifndef DES_H
+#define DES_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stddef.h>
+
+#include <mLib/bits.h>
+
+/*----- Magical numbers ---------------------------------------------------*/
+
+#define DES_BLKSZ 8
+#define DES_KEYSZ 7
+#define DES_CLASS (N, B, 64)
+
+/*----- Data structures ---------------------------------------------------*/
+
+typedef struct des_ctx {
+ uint32 k[32];
+} des_ctx;
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @des_init@ --- *
+ *
+ * Arguments: @des_ctx *k@ = pointer to key block
+ * @const void *buf@ = pointer to key buffer
+ * @size_t sz@ = size of key material
+ *
+ * Returns: ---
+ *
+ * Use: Initializes a DES key buffer. The key buffer may be either 7
+ * or 8 bytes long. If it's 8 bytes, the key is assumed to be
+ * padded with parity bits in the low order bit of each octet.
+ * These are stripped out without checking prior to the actual
+ * key scheduling.
+ */
+
+extern void des_init(des_ctx */*k*/, const void */*buf*/, size_t /*sz*/);
+
+/* --- @des_eblk@, @des_dblk@ --- *
+ *
+ * Arguments: @const des_ctx *k@ = pointer to key block
+ * @const uint32 s[2]@ = pointer to source block
+ * @uint32 d[2]@ = pointer to destination block
+ *
+ * Returns: ---
+ *
+ * Use: Low-level block encryption and decryption.
+ */
+
+extern void des_eblk(const des_ctx */*k*/,
+ const uint32 */*s*/, uint32 */*d*/);
+extern void des_dblk(const des_ctx */*k*/,
+ const uint32 */*s*/, uint32 */*d*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: des3.c,v 1.1 1999/09/03 08:41:11 mdw Exp $
+ *
+ * Implementation of double- and triple-DES
+ *
+ * (c) 1999 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: des3.c,v $
+ * Revision 1.1 1999/09/03 08:41:11 mdw
+ * Initial import.
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <mLib/bits.h>
+
+#include "blkc.h"
+#include "des-base.h"
+#include "des.h"
+#include "des3.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @des3_init@ --- *
+ *
+ * Arguments: @des3_ctx *k@ = pointer to key block
+ * @const void *buf@ = pointer to key buffer
+ * @size_t sz@ = size of key material
+ *
+ * Returns: ---
+ *
+ * Use: Initializes a DES key buffer. The key buffer may have length
+ * 7, 8, 14, 16, 21, or 24. These correspond to one, two or
+ * three DES keys, either packed or unpacked (i.e., still
+ * containing parity bits).
+ */
+
+void des3_init(des3_ctx *k, const void *buf, size_t sz)
+{
+ size_t step;
+ const octet *p = buf;
+
+ assert(((void)("des3 key length must be one of 7, 8, 14, 16, 21 or 24"),
+ (sz % 7 == 0 || sz % 8 == 0) && sz < 25));
+
+ if (sz % 7 == 0)
+ step = 7;
+ else
+ step = 8;
+
+ des_init(&k->a, p, step);
+ if (sz > 8) p += step;
+ des_init(&k->b, p, step);
+ if (sz > 16) p += step; else p = buf;
+ des_init(&k->c, p, step);
+}
+
+/* --- @des3_eblk@, @des3_dblk@ --- *
+ *
+ * Arguments: @const des3_ctx *k@ = pointer to key block
+ * @const uint32 s[2]@ = pointer to source block
+ * @uint32 d[2]@ = pointer to destination block
+ *
+ * Returns: ---
+ *
+ * Use: Low-level block encryption and decryption.
+ */
+
+void des3_eblk(const des3_ctx *k, const uint32 *s, uint32 *d)
+{
+ uint32 x = s[0], y = s[1];
+ DES_IP(x, y);
+ DES_EBLK(k->a.k, x, y, x, y);
+ DES_DBLK(k->b.k, x, y, x, y);
+ DES_EBLK(k->c.k, x, y, x, y);
+ DES_IPINV(x, y);
+ d[0] = x, d[1] = y;
+}
+
+void des3_dblk(const des3_ctx *k, const uint32 *s, uint32 *d)
+{
+ uint32 x = s[0], y = s[1];
+ DES_IP(x, y);
+ DES_DBLK(k->c.k, x, y, x, y);
+ DES_EBLK(k->b.k, x, y, x, y);
+ DES_DBLK(k->a.k, x, y, x, y);
+ DES_IPINV(x, y);
+ d[0] = x, d[1] = y;
+}
+
+BLKC_TEST(DES3, des3)
+
+/*----- That's all, folks -------------------------------------------------*/
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: des3.h,v 1.1 1999/09/03 08:41:11 mdw Exp $
+ *
+ * Implementation of double- and triple-DES
+ *
+ * (c) 1999 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: des3.h,v $
+ * Revision 1.1 1999/09/03 08:41:11 mdw
+ * Initial import.
+ *
+ */
+
+#ifndef DES3_H
+#define DES3_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*----- Notes on double- and triple-DES -----------------------------------*
+ *
+ * The normal recommendation for using DES now is `triple DES'.
+ * Conventionally, this involves an encrypt-decrypt-encrypt sequence,
+ * although whether the first and last operations use the same key is
+ * unfortunately not agreed upon. This interface handles both cases (and the
+ * single-key one too, although the simple @des@ calls are quicker for that).
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stddef.h>
+
+#include <mLib/bits.h>
+
+#ifndef DES_H
+# include "des.h"
+#endif
+
+/*----- Magical numbers ---------------------------------------------------*/
+
+#define DES3_BLKSZ 8
+#define DES3_KEYSZ 21
+#define DES3_CLASS (N, B, 64)
+
+/*----- Data structures ---------------------------------------------------*/
+
+typedef struct des3_ctx {
+ des_ctx a, b, c;
+} des3_ctx;
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @des3_init@ --- *
+ *
+ * Arguments: @des3_ctx *k@ = pointer to key block
+ * @const void *buf@ = pointer to key buffer
+ * @size_t sz@ = size of key material
+ *
+ * Returns: ---
+ *
+ * Use: Initializes a DES key buffer. The key buffer may have length
+ * 7, 8, 14, 16, 21, or 24. These correspond to one, two or
+ * three DES keys, either packed or unpacked (i.e., still
+ * containing parity bits).
+ */
+
+extern void des3_init(des3_ctx */*k*/, const void */*buf*/, size_t /*sz*/);
+
+/* --- @des3_eblk@, @des_dblk@ --- *
+ *
+ * Arguments: @const des3_ctx *k@ = pointer to key block
+ * @const uint32 s[2]@ = pointer to source block
+ * @uint32 d[2]@ = pointer to destination block
+ *
+ * Returns: ---
+ *
+ * Use: Low-level block encryption and decryption.
+ */
+
+extern void des3_eblk(const des3_ctx */*k*/,
+ const uint32 */*s*/, uint32 */*d*/);
+extern void des3_dblk(const des3_ctx */*k*/,
+ const uint32 */*s*/, uint32 */*d*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: ecb.h,v 1.1 1999/09/03 08:41:12 mdw Exp $
+ *
+ * Ciphertext block chaining for block ciphers
+ *
+ * (c) 1999 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: ecb.h,v $
+ * Revision 1.1 1999/09/03 08:41:12 mdw
+ * Initial import.
+ *
+ */
+
+#ifndef ECB_H
+#define ECB_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <assert.h>
+#include <string.h>
+
+#include <mLib/bits.h>
+
+#ifndef BLKC_H
+# include "blkc.h"
+#endif
+
+/*----- Macros ------------------------------------------------------------*/
+
+/* --- @ECB_DECL@ --- *
+ *
+ * Arguments: @PRE@, @pre@ = prefixes for the underlying block cipher
+ *
+ * Use: Creates declarations for ECB stealing mode.
+ */
+
+#define ECB_DECL(PRE, pre) \
+ \
+typedef struct pre ## _ecbctx { \
+ pre ## _ctx ctx; /* Underlying cipher context */ \
+} pre ## _ecbctx; \
+ \
+extern void pre ## _ecbsetkey(pre ## _ecbctx */*ctx*/, \
+ const pre ## _ctx */*k*/); \
+ \
+extern void pre ## _ecbinit(pre ## _ecbctx */*ctx*/, \
+ const void */*key*/, size_t /*sz*/, \
+ const void */*iv*/); \
+ \
+extern void pre ## _ecbencrypt(pre ## _ecbctx */*ctx*/, \
+ const void */*src*/, void */*dest*/, \
+ size_t /*sz*/); \
+ \
+extern void pre ## _ecbdecrypt(pre ## _ecbctx */*ctx*/, \
+ const void */*src*/, void */*dest*/, \
+ size_t /*sz*/); \
+
+/* --- @ECB_DEF@ --- *
+ *
+ * Arguments: @PRE@, @pre@ = prefixes for the underlying block cipher
+ *
+ * Use: Creates an implementation for ECB stealing mode.
+ */
+
+#define ECB_DEF(PRE, pre) \
+ \
+/* --- @pre_ecbsetkey@ --- * \
+ * \
+ * Arguments: @pre_ecbctx *ctx@ = pointer to ECB context block \
+ * @const pre_ctx *k@ = pointer to cipher context \
+ * \
+ * Returns: --- \
+ * \
+ * Use: Sets the ECB context to use a different cipher key. \
+ */ \
+ \
+void pre ## _ecbsetkey(pre ## _ecbctx *ctx, const pre ## _ctx *k) \
+{ \
+ ctx->ctx = *k; \
+} \
+ \
+/* --- @pre_ecbinit@ --- * \
+ * \
+ * Arguments: @pre_ecbctx *ctx@ = pointer to cipher context \
+ * @const void *key@ = pointer to the key buffer \
+ * @size_t sz@ = size of the key \
+ * @const void *iv@ = pointer to initialization vector \
+ * \
+ * Returns: --- \
+ * \
+ * Use: Initializes an ECB context ready for use. This is \
+ * equivalent to calls to @pre_init@ and @pre_setkey@. \
+ */ \
+ \
+void pre ## _ecbinit(pre ## _ecbctx *ctx, \
+ const void *key, size_t sz, \
+ const void *iv) \
+{ \
+ pre ## _init(&ctx->ctx, key, sz); \
+} \
+ \
+/* --- @pre_ecbencrypt@ --- * \
+ * \
+ * Arguments: @pre_ecbctx *ctx@ = pointer to ECB context block \
+ * @const void *src@ = pointer to source data \
+ * @void *dest@ = pointer to destination data \
+ * @size_t sz@ = size of block to be encrypted \
+ * \
+ * Returns: --- \
+ * \
+ * Use: Encrypts a block with a block cipher in ECB mode, with \
+ * ciphertext stealing and other clever tricks. \
+ * Essentially, data can be encrypted in arbitrary sized \
+ * chunks, although decryption must use the same chunks. \
+ */ \
+ \
+void pre ## _ecbencrypt(pre ## _ecbctx *ctx, \
+ const void *src, void *dest, \
+ size_t sz) \
+{ \
+ const octet *s = src; \
+ octet *d = dest; \
+ \
+ /* --- Empty blocks are trivial --- */ \
+ \
+ if (!sz) \
+ return; \
+ \
+ /* --- Short blocks aren't allowed in ECB --- * \
+ * \
+ * There's absolutely nothing secure I can do with them. \
+ */ \
+ \
+ assert(((void)"ECB must have at least one whole block to work with", \
+ sz >= PRE ## _BLKSZ)); \
+ \
+ /* --- Do the main chunk of encryption --- * \
+ * \
+ * This will do the whole lot if it's a whole number of blocks. Just \
+ * give each block to the cipher in turn. This is trivial. \
+ * Hopefully... \
+ */ \
+ \
+ while (sz >= 2 * PRE ## _BLKSZ || sz == PRE ## _BLKSZ) { \
+ uint32 x[PRE ## _BLKSZ / 4]; \
+ BLKC_LOAD(PRE, x, s); \
+ pre ## _eblk(&ctx->ctx, x, x); \
+ BLKC_STORE(PRE, d, x); \
+ s += PRE ## _BLKSZ; \
+ d += PRE ## _BLKSZ; \
+ sz -= PRE ## _BLKSZ; \
+ } \
+ \
+ /* --- Do the tail-end block and bit-left-over --- * \
+ * \
+ * This isn't very efficient. That shouldn't matter much. \
+ */ \
+ \
+ if (sz) { \
+ uint32 x[PRE ## _BLKSZ / 4]; \
+ octet b[PRE ## _BLKSZ]; \
+ unsigned i; \
+ \
+ /* --- Let @sz@ be the size of the partial block --- */ \
+ \
+ sz -= PRE ## _BLKSZ; \
+ \
+ /* --- First stage --- * \
+ * \
+ * Read in the current block, and encrypt it. The first part of \
+ * the result is the partial ciphertext block. Don't write that \
+ * out yet, because I've not read the partial plaintext block. \
+ */ \
+ \
+ BLKC_LOAD(PRE, x, s); \
+ pre ## _eblk(&ctx->ctx, x, x); \
+ BLKC_STORE(PRE, b, x); \
+ \
+ /* --- Second stage --- * \
+ * \
+ * Now move in the partial plaintext block, writing out the \
+ * ciphertext as I go. Then encrypt, and write the complete \
+ * ciphertext block. \
+ */ \
+ \
+ s += PRE ## _BLKSZ; \
+ d += PRE ## _BLKSZ; \
+ for (i = 0; i < sz; i++) { \
+ register octet y = b[i]; \
+ b[i] = s[i]; \
+ d[i] = y; \
+ } \
+ BLKC_LOAD(PRE, x, b); \
+ pre ## _eblk(&ctx->ctx, x, x); \
+ BLKC_STORE(PRE, d - PRE ## _BLKSZ, x); \
+ } \
+ \
+ /* --- Done --- */ \
+ \
+ return; \
+} \
+ \
+/* --- @pre_ecbdecrypt@ --- * \
+ * \
+ * Arguments: @pre_ecbctx *ctx@ = pointer to ECB context block \
+ * @const void *src@ = pointer to source data \
+ * @void *dest@ = pointer to destination data \
+ * @size_t sz@ = size of block to be encrypted \
+ * \
+ * Returns: --- \
+ * \
+ * Use: Encrypts a block with a block cipher in ECB mode, with \
+ * ciphertext stealing and other clever tricks. \
+ * Essentially, data can be encrypted in arbitrary sized \
+ * chunks, although decryption must use the same chunks. \
+ */ \
+ \
+void pre ## _ecbdecrypt(pre ## _ecbctx *ctx, \
+ const void *src, void *dest, \
+ size_t sz) \
+{ \
+ const octet *s = src; \
+ octet *d = dest; \
+ \
+ /* --- Empty blocks are trivial --- */ \
+ \
+ if (!sz) \
+ return; \
+ \
+ /* --- Short blocks aren't allowed in ECB --- * \
+ * \
+ * There's absolutely nothing secure I can do with them. \
+ */ \
+ \
+ assert(((void)"ECB must have at least one whole block to work with", \
+ sz >= PRE ## _BLKSZ)); \
+ \
+ /* --- Do the main chunk of decryption --- * \
+ * \
+ * This will do the whole lot if it's a whole number of blocks. \
+ * Each block is just handed to the block cipher in turn. \
+ */ \
+ \
+ while (sz >= 2 * PRE ## _BLKSZ || sz == PRE ## _BLKSZ) { \
+ uint32 x[PRE ## _BLKSZ / 4]; \
+ BLKC_LOAD(PRE, x, s); \
+ pre ## _dblk(&ctx->ctx, x, x); \
+ BLKC_STORE(PRE, d, x); \
+ s += PRE ## _BLKSZ; \
+ d += PRE ## _BLKSZ; \
+ sz -= PRE ## _BLKSZ; \
+ } \
+ \
+ /* --- Do the tail-end block and bit-left-over --- * \
+ * \
+ * This isn't very efficient. That shouldn't matter much. \
+ */ \
+ \
+ if (sz) { \
+ uint32 x[PRE ## _BLKSZ / 4]; \
+ octet b[PRE ## _BLKSZ]; \
+ unsigned i; \
+ \
+ /* --- Let @sz@ be the size of the partial block --- */ \
+ \
+ sz -= PRE ## _BLKSZ; \
+ \
+ /* --- First stage --- * \
+ * \
+ * Take the complete ciphertext block, and decrypt it. This block \
+ * is carried over for the next encryption operation. \
+ */ \
+ \
+ BLKC_LOAD(PRE, x, s); \
+ pre ## _dblk(&ctx->ctx, x, x); \
+ BLKC_STORE(PRE, b, x); \
+ \
+ /* --- Second stage --- * \
+ * \
+ * The first few bytes are the partial plaintext block. Write that \
+ * and replace with the partial ciphertext block. Then decrypt \
+ * what's left as the complete plaintext. \
+ */ \
+ \
+ s += PRE ## _BLKSZ; \
+ d += PRE ## _BLKSZ; \
+ for (i = 0; i < sz; i++) { \
+ register octet y = s[i]; \
+ d[i] = b[i]; \
+ b[i] = y; \
+ } \
+ BLKC_LOAD(PRE, x, b); \
+ pre ## _dblk(&ctx->ctx, x, x); \
+ BLKC_STORE(PRE, d - PRE ## _BLKSZ, x); \
+ } \
+ \
+ /* --- Done --- */ \
+ \
+ return; \
+} \
+ \
+ECB_TEST(PRE, pre)
+
+/*----- Test rig ----------------------------------------------------------*/
+
+#ifdef TEST_RIG
+
+#include <stdio.h>
+
+#include "daftstory.h"
+
+/* --- @ECB_TEST@ --- *
+ *
+ * Arguments: @PRE@, @pre@ = prefixes for block cipher definitions
+ *
+ * Use: Standard test rig for ECB functions.
+ */
+
+#define ECB_TEST(PRE, pre) \
+ \
+/* --- Initial plaintext for the test --- */ \
+ \
+static const octet text[] = TEXT; \
+ \
+/* --- Key and IV to use --- */ \
+ \
+static const octet key[] = KEY; \
+static const octet iv[] = IV; \
+ \
+/* --- Buffers for encryption and decryption output --- */ \
+ \
+static octet ct[sizeof(text)]; \
+static octet pt[sizeof(text)]; \
+ \
+static void hexdump(const octet *p, size_t sz) \
+{ \
+ const octet *q = p + sz; \
+ for (sz = 0; p < q; p++, sz++) { \
+ printf("%02x", *p); \
+ if ((sz + 1) % PRE ## _BLKSZ == 0) \
+ putchar(':'); \
+ } \
+} \
+ \
+int main(void) \
+{ \
+ size_t sz = 0, rest; \
+ pre ## _ecbctx ctx; \
+ int status = 0; \
+ int done = 0; \
+ \
+ size_t keysz = PRE ## _KEYSZ ? \
+ PRE ## _KEYSZ : strlen((const char *)key); \
+ \
+ fputs(#pre "-ecb: ", stdout); \
+ \
+ pre ## _ecbinit(&ctx, key, keysz, iv); \
+ \
+ while (sz <= sizeof(text)) { \
+ rest = sizeof(text) - sz; \
+ if ((sz != 0 && sz < PRE ## _BLKSZ) || \
+ (rest != 0 && rest < PRE ## _BLKSZ)) \
+ goto next; \
+ memcpy(ct, text, sizeof(text)); \
+ pre ## _ecbencrypt(&ctx, ct, ct, sz); \
+ pre ## _ecbencrypt(&ctx, ct + sz, ct + sz, rest); \
+ memcpy(pt, ct, sizeof(text)); \
+ pre ## _ecbdecrypt(&ctx, pt, pt, sz); \
+ pre ## _ecbdecrypt(&ctx, pt + sz, pt + sz, rest); \
+ if (memcmp(pt, text, sizeof(text)) == 0) { \
+ done++; \
+ if (sizeof(text) < 40 || done % 8 == 0) \
+ fputc('.', stdout); \
+ if (done % 480 == 0) \
+ fputs("\n\t", stdout); \
+ fflush(stdout); \
+ } else { \
+ printf("\nError (sz = %lu)\n", (unsigned long)sz); \
+ status = 1; \
+ printf("\tplaintext = "); hexdump(text, sz); \
+ printf(", "); hexdump(text + sz, rest); \
+ fputc('\n', stdout); \
+ printf("\tciphertext = "); hexdump(ct, sz); \
+ printf(", "); hexdump(ct + sz, rest); \
+ fputc('\n', stdout); \
+ printf("\trecovered text = "); hexdump(pt, sz); \
+ printf(", "); hexdump(pt + sz, rest); \
+ fputc('\n', stdout); \
+ fputc('\n', stdout); \
+ } \
+ next: \
+ if (sz < 63) \
+ sz++; \
+ else \
+ sz += 9; \
+ } \
+ \
+ fputs(status ? " failed\n" : " ok\n", stdout); \
+ return (status); \
+}
+
+#else
+# define ECB_TEST(PRE, pre)
+#endif
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
--- /dev/null
+#! /bin/sh
+
+baselist=$1
+extlist=$2
+
+for i in $baselist; do
+ I=`echo "$i" | tr -d '\n' | tr a-z A-Z | tr -c a-zA-Z0-9 _`
+ for j in $extlist; do
+ J=`echo "$j" | tr -d '\n' | tr a-z A-Z | tr -c a-zA-Z0-9 _`
+ guard="${I}_${J}_H"
+ cat >$i-$j.h <<EOF
+/* -*-c-*-
+ *
+ * $i-$j.h [generated]
+ */
+
+#ifndef $guard
+#define $guard
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#ifndef ${J}_H
+# include "$j.h"
+#endif
+
+#ifndef ${I}_H
+# include "$i.h"
+#endif
+
+${J}_DECL($I, $i)
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
+EOF
+ cat >$i-$j.c <<EOF
+/* -*-c-*-
+ *
+ * $i-$j.h [generated]
+ */
+
+#include "$i-$j.h"
+${J}_DEF($I, $i)
+EOF
+ done
+done
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: hash.h,v 1.1 1999/09/03 08:41:12 mdw Exp $
+ *
+ * Generic handling for message digest functions
+ *
+ * (c) 1998 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: hash.h,v $
+ * Revision 1.1 1999/09/03 08:41:12 mdw
+ * Initial import.
+ *
+ */
+
+#ifndef HASH_H
+#define HASH_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <string.h>
+
+#include <mLib/bits.h>
+
+/*----- Macros ------------------------------------------------------------*/
+
+/* --- @HASH_BUFFER@ --- *
+ *
+ * Arguments: @PRE@, @pre@ = prefixes for hash-specific definitions
+ * @ictx@ = pointer to context block for the hash
+ * @ibuf@ = pointer to input data to hash
+ * @isz@ = size of buffer
+ *
+ * Use: Handles buffering of input data to a hash function. The
+ * hash's compression function is called when the buffer is
+ * full. Note that the compression function can be called on
+ * data which is at odd alignments; it is expected to cope
+ * gracefully with this (possibly by copying the data into its
+ * internal buffer before starting).
+ */
+
+#define HASH_BUFFER(PRE, pre, ictx, ibuf, isz) do { \
+ pre##_ctx *_bctx = (ictx); \
+ size_t _bsz = (isz); \
+ const octet *_bbuf = (octet *)(ibuf); \
+ \
+ /* --- Add on the size done so far --- */ \
+ \
+ _bctx->count += _bsz; \
+ \
+ /* --- Handle very small contributions --- */ \
+ \
+ if (_bctx->off + _bsz < PRE##_BUFSZ) { \
+ memcpy(_bctx->buf + _bctx->off, _bbuf, _bsz); \
+ _bctx->off += _bsz; \
+ } else { \
+ \
+ /* --- Handle an initial partial buffer --- */ \
+ \
+ if (_bctx->off) { \
+ size_t s = PRE##_BUFSZ - _bctx->off; \
+ memcpy(_bctx->buf + _bctx->off, _bbuf, s); \
+ pre##_compress(_bctx, _bctx->buf); \
+ _bsz -= s; _bbuf += s; \
+ } \
+ \
+ /* --- Do whole buffers while we can --- */ \
+ \
+ while (_bsz >= PRE##_BUFSZ) { \
+ pre##_compress(_bctx, _bbuf); \
+ _bsz -= PRE##_BUFSZ; _bbuf += PRE##_BUFSZ; \
+ } \
+ \
+ /* --- And wrap up at the end --- */ \
+ \
+ if (_bsz) \
+ memcpy(_bctx->buf, _bbuf, _bsz); \
+ _bctx->off = _bsz; \
+ } \
+} while (0)
+
+/* --- @HASH_PAD@ --- *
+ *
+ * Arguments: @PRE@, @pre@ = prefixes for hash-specific definitions
+ * @ictx@ = pointer to context block for the hash
+ * @term@ = terminator character to write following the data
+ * @pad@ = pad character to fill with
+ * @diff@ = size of space to leave at the end of the last block
+ *
+ * Use: Does padding for message digest functions.
+ */
+
+#define HASH_PAD(PRE, pre, ictx, term, pad, diff) do { \
+ pre##_ctx *_pctx = (ictx); \
+ \
+ _pctx->buf[_pctx->off] = term; \
+ _pctx->off++; \
+ if (_pctx->off > PRE##_BUFSZ - diff) { \
+ if (_pctx->off < PRE##_BUFSZ) \
+ memset(_pctx->buf + _pctx->off, pad, PRE##_BUFSZ - _pctx->off); \
+ pre##_compress(_pctx, _pctx->buf); \
+ memset(_pctx->buf, pad, PRE##_BUFSZ - diff); \
+ } else \
+ memset(_pctx->buf + _pctx->off, pad, \
+ PRE##_BUFSZ - _pctx->off - diff); \
+} while (0)
+
+/* --- @HASH_MD5STRENGTH@ --- *
+ *
+ * Arguments: @PRE@, @pre@ = prefixes for hash-specific definitions
+ * @ictx@ = pointer to context block for the hash
+ *
+ * Use: Does MD5-style MD strengthening. The data is terminated
+ * by a single set bit, padded with zero bits, and then a 64-
+ * bit length is written, little-end first.
+ */
+
+#define HASH_MD5STRENGTH(PRE, pre, ictx) do { \
+ pre##_ctx *_mctx = (ictx); \
+ HASH_PAD(PRE, pre, _mctx, 0x80u, 0, 8); \
+ STORE32_L(_mctx->buf + PRE##_BUFSZ - 8, _mctx->count << 3); \
+ STORE32_L(_mctx->buf + PRE##_BUFSZ - 4, _mctx->count >> 29); \
+ pre##_compress(_mctx, _mctx->buf); \
+} while (0)
+
+/* --- @HASH_TEST@ --- *
+ *
+ * Arguments: @PRE@, @pre@ = prefixes for hash-specfic definitions
+ *
+ * Use: Standard test rig for hash functions.
+ */
+
+#ifdef TEST_RIG
+
+#include <mLib/quis.h>
+#include <mLib/testrig.h>
+
+#define HASH_TEST(PRE, pre) \
+ \
+static int verify(dstr *v) \
+{ \
+ pre##_ctx ctx; \
+ int ok = 1; \
+ int i; \
+ octet *p; \
+ int szs[] = { 1, 7, 192, -1, 0 }, *ip; \
+ size_t sz; \
+ dstr d; \
+ \
+ dstr_create(&d); \
+ dstr_ensure(&d, PRE##_HASHSZ); \
+ d.len = PRE##_HASHSZ; \
+ \
+ for (ip = szs; *ip; ip++) { \
+ i = *ip; \
+ sz = v[0].len; \
+ if (i == -1) \
+ i = sz; \
+ if (i > sz) \
+ continue; \
+ p = (octet *)v[0].buf; \
+ pre##_init(&ctx); \
+ while (sz) { \
+ if (i > sz) \
+ i = sz; \
+ pre##_hash(&ctx, p, i); \
+ p += i; \
+ sz -= i; \
+ } \
+ pre##_done(&ctx, d.buf); \
+ if (memcmp(d.buf, v[1].buf, PRE##_HASHSZ) != 0) { \
+ printf("\nfail:\n\tstep = %i\n\tinput = `%s'\n\texpected = ", \
+ *ip, v[0].buf); \
+ type_hex.dump(&v[1], stdout); \
+ fputs("\n\tcomputed = ", stdout); \
+ type_hex.dump(&d, stdout); \
+ putchar('\n'); \
+ ok = 0; \
+ } \
+ } \
+ \
+ dstr_destroy(&d); \
+ return (ok); \
+} \
+ \
+static test_chunk defs[] = { \
+ { #pre, verify, { &type_string, &type_hex, 0 } }, \
+ { 0, 0, { 0 } } \
+}; \
+ \
+int main(int argc, char *argv[]) \
+{ \
+ ego(argv[0]); \
+ test_run(argc, argv, defs, SRCDIR"/tests/" #pre); \
+ return (0); \
+}
+
+#else
+# define HASH_TEST(PRE, pre)
+#endif
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: hmac.h,v 1.1 1999/09/03 08:41:12 mdw Exp $
+ *
+ * Generic code for HMAC and NMAC
+ *
+ * (c) 1998 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: hmac.h,v $
+ * Revision 1.1 1999/09/03 08:41:12 mdw
+ * Initial import.
+ *
+ */
+
+/*----- Notes on the HMAC and NMAC constructions --------------------------*
+ *
+ * Designed by Mihir Bellare, Ran Canetti and Hugo Krawczyk, NMAC is a
+ * method for constructing keyed message authentication algorithms from
+ * unkeyed hash functions. HMAC is an alternative formulation which doesn't
+ * require low-level access to the hash function's implementation. NMAC was
+ * designed to allow MD5 has a suitable underlying hash function, even though
+ * doubts were already being raised about its collision resistance.
+ */
+
+#ifndef HMAC_H
+#define HMAC_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <mLib/bits.h>
+
+#ifndef PARANOIA_H
+# include "paranoia.h"
+#endif
+
+/*----- Macros ------------------------------------------------------------*/
+
+/* --- @HMAC_DECL@ --- *
+ *
+ * Arguments: @PRE@, @pre@ = prefixes for the underlying hash function
+ *
+ * Use: Creates declarations for the HMAC and NMAC functions.
+ */
+
+#define HMAC_DECL(PRE, pre) \
+ \
+typedef struct pre##_mackey { \
+ octet ochain[PRE##_HASHSZ]; /* Chaining for outer hash */ \
+ unsigned long ocount; /* Byte count for outer hash */ \
+ octet ichain[PRE##_HASHSZ]; /* Chaining for inner hash */ \
+ unsigned long icount; /* Byte count for inner hash */ \
+} pre##_mackey; \
+ \
+typedef struct pre##_macctx { \
+ pre##_ctx ctx; /* Context for main hashing */ \
+ octet chain[PRE##_HASHSZ]; /* Chaining for outer hash */ \
+ unsigned long count; /* Byte count for outer hash */ \
+} pre##_macctx; \
+ \
+extern void pre##_nmac(pre##_mackey */*key*/, \
+ const void */*ok*/, const void */*ik*/); \
+ \
+extern void pre##_hmac(pre##_mackey */*key*/, \
+ const void */*k*/, size_t /*sz*/); \
+ \
+extern void pre##_macinit(pre##_macctx */*ctx*/, \
+ const pre##_mackey */*key*/); \
+ \
+extern void pre##_mac(pre##_macctx */*ctx*/, \
+ const void */*buf*/, size_t /*sz*/); \
+ \
+extern void pre##_macdone(pre##_macctx */*ctx*/, void */*mac*/);
+
+/* --- @HMAC_DEF@ --- *
+ *
+ * Arguments: @PRE@, @pre@ = prefixes for the underlying hash function
+ *
+ * Use: Creates implementations for the HMAC and NMAC functions.
+ */
+
+#define HMAC_DEF(PRE, pre) \
+ \
+/* --- @pre_nmac@ --- * \
+ * \
+ * Arguments: @pre_macctx *key@ = pointer to a MAC key object \
+ * @const void *ok@ = pointer to outer hash init vector \
+ * @const void *ik@ = pointer to inner hash init vector \
+ * \
+ * Returns: --- \
+ * \
+ * Use: Initializes a MAC key for doing NMAC hashing. \
+ */ \
+ \
+void pre##_nmac(pre##_mackey *key, const void *ok, const void *ik) \
+{ \
+ memcpy(key->ochain, ok, PRE##_HASHSZ); \
+ memcpy(key->ichain, ik, PRE##_HASHSZ); \
+ key->ocount = key->icount = 0; \
+} \
+ \
+/* --- @pre_hmac@ --- * \
+ * \
+ * Arguments: @pre_mackey *key@ = pointer to MAC key object \
+ * @const void *k@ = pointer to key to use \
+ * @size_t sz@ = size of key data \
+ * \
+ * Returns: --- \
+ * \
+ * Use: Initializes a MAC key for doing HMAC hashing. Keys \
+ * longer than the hash function's output size aren't very \
+ * useful, but are accepted. Keys longer than the hash's \
+ * block size are also accepted; they are hashed before \
+ * use, as specified in RFC2104. \
+ */ \
+ \
+void pre##_hmac(pre##_mackey *key, const void *k, size_t sz) \
+{ \
+ int i; \
+ const octet *kbuf = k; \
+ pre##_ctx ctx; \
+ octet buf[PRE##_HASHSZ]; \
+ \
+ if (sz > PRE##_BUFSZ) { \
+ pre##_init(&ctx); \
+ pre##_hash(&ctx, k, sz); \
+ pre##_done(&ctx, buf); \
+ kbuf = buf; \
+ sz = PRE##_HASHSZ; \
+ } \
+ \
+ pre##_init(&ctx); \
+ memset(ctx.buf, 0x5c, PRE##_BUFSZ); \
+ for (i = 0; i < sz; i++) \
+ ctx.buf[i] ^= kbuf[i]; \
+ pre##_compress(&ctx, ctx.buf); \
+ pre##_state(&ctx, key->ochain); \
+ \
+ pre##_init(&ctx); \
+ memset(ctx.buf, 0x36, PRE##_BUFSZ); \
+ for (i = 0; i < sz; i++) \
+ ctx.buf[i] ^= kbuf[i]; \
+ pre##_compress(&ctx, ctx.buf); \
+ pre##_state(&ctx, key->ichain); \
+ \
+ key->ocount = key->icount = PRE##_BUFSZ; \
+ BURN(ctx); \
+} \
+ \
+/* --- @pre_macinit@ --- * \
+ * \
+ * Arguments: @pre_macctx *ctx@ = pointer to MAC context block \
+ * @const pre_mackey *key@ = pointer to MAC key block \
+ * \
+ * Returns: --- \
+ * \
+ * Use: Instantiates a MAC context from a key block. \
+ */ \
+ \
+void pre##_macinit(pre##_macctx *ctx, const pre##_mackey *key) \
+{ \
+ memcpy(ctx->chain, key->ochain, PRE##_HASHSZ); \
+ ctx->count = key->ocount; \
+ pre##_set(&ctx->ctx, key->ichain, key->icount); \
+} \
+ \
+/* --- @pre_mac@ --- * \
+ * \
+ * Arguments: @pre_macctx *ctx@ = pointer to MAC context block \
+ * @const void *buf@ = pointer to buffer \
+ * @size_t sz@ = size of the buffer \
+ * \
+ * Returns: --- \
+ * \
+ * Use: Hashes a buffer. \
+ */ \
+ \
+void pre##_mac(pre##_macctx *ctx, const void *buf, size_t sz) \
+{ \
+ pre##_hash(&ctx->ctx, buf, sz); \
+} \
+ \
+/* --- @pre_macdone@ --- * \
+ * \
+ * Arguments: @pre_macctx *ctx@ = pointer to MAC context block \
+ * @void *mac@ = pointer to buffer to receive MAC \
+ * \
+ * Returns: --- \
+ * \
+ * Use: Returns the result of a MAC computation. \
+ */ \
+ \
+void pre##_macdone(pre##_macctx *ctx, void *mac) \
+{ \
+ pre##_done(&ctx->ctx, mac); \
+ pre##_set(&ctx->ctx, ctx->chain, ctx->count); \
+ pre##_hash(&ctx->ctx, mac, PRE##_HASHSZ); \
+ pre##_done(&ctx->ctx, mac); \
+} \
+ \
+HMAC_TEST(PRE, pre) \
+
+/* --- @HMAC_TEST@ --- *
+ *
+ * Arguments: @PRE@, @pre@ = prefixes for hash-specfic definitions
+ *
+ * Use: Standard test rig for MAC functions.
+ */
+
+#ifdef TEST_RIG
+
+#include <mLib/dstr.h>
+#include <mLib/quis.h>
+#include <mLib/testrig.h>
+
+#define HMAC_TEST(PRE, pre) \
+ \
+static int macverify(dstr *v) \
+{ \
+ pre##_macctx cctx; \
+ pre##_mackey ckey; \
+ int ok = 1; \
+ int i; \
+ octet *p; \
+ int szs[] = { 1, 7, 192, -1, 0 }, *ip; \
+ size_t csz; \
+ dstr d; \
+ \
+ dstr_create(&d); \
+ dstr_ensure(&d, PRE##_HASHSZ); \
+ d.len = PRE##_HASHSZ; \
+ \
+ pre##_hmac(&ckey, v[1].buf, v[1].len); \
+ \
+ for (ip = szs; *ip; ip++) { \
+ i = *ip; \
+ csz = v[0].len; \
+ if (i == -1) \
+ i = csz; \
+ if (i > csz) \
+ continue; \
+ p = (octet *)v[0].buf; \
+ pre##_macinit(&cctx, &ckey); \
+ while (csz) { \
+ if (i > csz) \
+ i = csz; \
+ pre##_mac(&cctx, p, i); \
+ p += i; \
+ csz -= i; \
+ } \
+ pre##_macdone(&cctx, d.buf); \
+ if (memcmp(d.buf, v[2].buf, PRE##_HASHSZ) != 0) { \
+ printf("\nfail:\n\tstep = %i\n\tinput = `%s'\n\tkey = ", \
+ *ip, v[0].buf); \
+ type_hex.dump(&v[1], stdout); \
+ fputs("\n\texpected = ", stdout); \
+ type_hex.dump(&v[2], stdout); \
+ fputs("\n\tcomputed = ", stdout); \
+ type_hex.dump(&d, stdout); \
+ putchar('\n'); \
+ ok = 0; \
+ } \
+ } \
+ \
+ dstr_destroy(&d); \
+ return (ok); \
+} \
+ \
+static test_chunk macdefs[] = { \
+ { #pre "-hmac", macverify, \
+ { &type_string, &type_hex, &type_hex, 0 } }, \
+ { 0, 0, { 0 } } \
+}; \
+ \
+int main(int argc, char *argv[]) \
+{ \
+ ego(argv[0]); \
+ test_run(argc, argv, macdefs, SRCDIR"/tests/" #pre); \
+ return (0); \
+}
+
+#else
+# define HMAC_TEST(PRE, pre)
+#endif
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: idea.c,v 1.1 1999/09/03 08:41:12 mdw Exp $
+ *
+ * Implementation of the IDEA cipher
+ *
+ * (c) 1999 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: idea.c,v $
+ * Revision 1.1 1999/09/03 08:41:12 mdw
+ * Initial import.
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <mLib/bits.h>
+
+#include "blkc.h"
+#include "idea.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @inv@ --- *
+ *
+ * Arguments: @uint16 n@ = number to invert
+ *
+ * Returns: Multiplicative inverse of @n@ %$\pmod{2^{16} + 1}$%.
+ *
+ * Use: Computes multiplicative inverses. This is handy for the
+ * decryption key scheduling.
+ */
+
+static uint16 inv(uint16 n)
+{
+ uint32 m = 0x10001;
+ uint32 a = 1, b = 0;
+
+ for (;;) {
+ uint32 q, r, t;
+ if (!(r = m % n))
+ break;
+ q = m / n;
+ m = n; n = r;
+ t = a; a = b - q * a; b = t;
+ }
+ if (a > MASK16)
+ a += 1;
+ return (U16(a));
+}
+
+/* --- @MUL@ --- *
+ *
+ * Arguments @x@ and @y@ are two 32-bit values to multiply. On exit, @x@ is
+ * the product of the two arguments. The result is not normalized back to 16
+ * bits; the arguments are not expected to be normalized.
+ */
+
+#define MUL(x, y) do { \
+ uint32 _mx, _my = (y); \
+ if ((_mx = U16(x)) == 0) \
+ (x) = 1 - _my; \
+ else if (_my == 0) \
+ (x) = 1 - _mx; \
+ else { \
+ _my *= _mx; \
+ _mx = U16(_my); _my >>= 16; \
+ if (_mx < _my) \
+ (x) = _mx - _my + 1; \
+ else \
+ (x) = _mx - _my; \
+ } \
+} while (0)
+
+/* --- @idea_init@ --- *
+ *
+ * Arguments: @idea_ctx *k@ = pointer to key block
+ * @const void *buf@ = pointer to key buffer
+ * @size_t sz@ = size of key material
+ *
+ * Returns: ---
+ *
+ * Use: Initializes an IDEA key buffer. The buffer must be exactly
+ * 16 bytes in size, because IDEA is only defined with a key
+ * size of 128 bits.
+ */
+
+void idea_init(idea_ctx *k, const void *buf, size_t sz)
+{
+ assert(((void)"IDEA key must be 128 bits", sz == IDEA_KEYSZ));
+
+ /* --- Unpack the encryption key --- */
+
+ {
+ const octet *p = buf;
+ uint16 *q = k->e;
+ uint32 a = LOAD32(p + 0);
+ uint32 b = LOAD32(p + 4);
+ uint32 c = LOAD32(p + 8);
+ uint32 d = LOAD32(p + 12);
+ int i;
+
+ /* --- Main unpacking loop --- */
+
+ for (i = 0; i < 6; i++) {
+
+ /* --- Spit out the next 8 subkeys --- */
+
+ q[0] = U16(a >> 16);
+ q[1] = U16(a >> 0);
+ q[2] = U16(b >> 16);
+ q[3] = U16(b >> 0);
+ q[4] = U16(c >> 16);
+ q[5] = U16(c >> 0);
+ q[6] = U16(d >> 16);
+ q[7] = U16(d >> 0);
+ q += 8;
+
+ /* --- Rotate and permute the subkeys --- */
+
+ {
+ uint32 t = a;
+ a = U32((a << 25) | (b >> 7));
+ b = U32((b << 25) | (c >> 7));
+ c = U32((c << 25) | (d >> 7));
+ d = U32((d << 25) | (t >> 7));
+ }
+ }
+
+ /* --- Write out the tail-enders --- */
+
+ q[0] = U16(a >> 16);
+ q[1] = U16(a >> 0);
+ q[2] = U16(b >> 16);
+ q[3] = U16(b >> 0);
+ }
+
+ /* --- Convert this into the decryption key --- */
+
+ {
+ uint16 *p = k->e + 52;
+ uint16 *q = k->d;
+ int i;
+
+ /* --- Translate the main round keys --- */
+
+ for (i = 0; i < 8; i++) {
+ p -= 6;
+ q[4] = p[0];
+ q[5] = p[1];
+ q[0] = inv(p[2]);
+ q[3] = inv(p[5]);
+ if (i) {
+ q[1] = 0x10000 - p[4];
+ q[2] = 0x10000 - p[3];
+ } else {
+ q[1] = 0x10000 - p[3];
+ q[2] = 0x10000 - p[4];
+ }
+ q += 6;
+ }
+
+ /* --- Translate the tail-enders --- */
+
+ p -= 4;
+ q[0] = inv(p[0]);
+ q[1] = 0x10000 - p[1];
+ q[2] = 0x10000 - p[2];
+ q[3] = inv(p[3]);
+ }
+}
+
+/* --- @ROUND@ --- */
+
+#define MIX(k, a, b, c, d) do { \
+ MUL(a, (k)[0]); \
+ (b) += (k)[1]; \
+ (c) += (k)[2]; \
+ MUL(d, (k)[3]); \
+} while (0)
+
+#define MA(k, a, b, c, d) do { \
+ unsigned _u = (a) ^ (c); \
+ unsigned _v = (b) ^ (d); \
+ MUL(_u, (k)[4]); \
+ _v += _u; \
+ MUL(_v, (k)[5]); \
+ _u += _v; \
+ (a) ^= _v; \
+ (b) ^= _u; \
+ (c) ^= _v; \
+ (d) ^= _u; \
+} while (0);
+
+#define ROUND(k, a, b, c, d) do { \
+ MIX((k), (a), (b), (c), (d)); \
+ MA((k), (a), (b), (c), (d)); \
+ (k) += 6; \
+} while (0)
+
+/* --- Encryption --- */
+
+#define EBLK(k, a, b, c, d) do { \
+ unsigned _a = U16(a >> 16); \
+ unsigned _b = U16(a >> 0); \
+ unsigned _c = U16(b >> 16); \
+ unsigned _d = U16(b >> 0); \
+ const uint16 *_k = (k); \
+ \
+ ROUND(_k, _a, _b, _c, _d); \
+ ROUND(_k, _a, _c, _b, _d); \
+ ROUND(_k, _a, _b, _c, _d); \
+ ROUND(_k, _a, _c, _b, _d); \
+ ROUND(_k, _a, _b, _c, _d); \
+ ROUND(_k, _a, _c, _b, _d); \
+ ROUND(_k, _a, _b, _c, _d); \
+ ROUND(_k, _a, _c, _b, _d); \
+ MIX (_k, _a, _c, _b, _d); \
+ (c) = (U16(_a) << 16) | U16(_c); \
+ (d) = (U16(_b) << 16) | U16(_d); \
+} while (0)
+
+#define DBLK(k, a, b) EBLK((k), (a), (b))
+
+/* --- @idea_eblk@, @idea_dblk@ --- *
+ *
+ * Arguments: @const idea_ctx *k@ = pointer to a key block
+ * @const uint32 s[2]@ = pointer to source block
+ * @uint32 d[2]@ = pointer to destination block
+ *
+ * Returns: ---
+ *
+ * Use: Low-level block encryption and decryption.
+ */
+
+void idea_eblk(const idea_ctx *k, const uint32 *s, uint32 *d)
+{
+ EBLK(k->e, s[0], s[1], d[0], d[1]);
+}
+
+void idea_dblk(const idea_ctx *k, const uint32 *s, uint32 *d)
+{
+ EBLK(k->d, s[0], s[1], d[0], d[1]);
+}
+
+BLKC_TEST(IDEA, idea)
+
+/*----- That's all, folks -------------------------------------------------*/
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: idea.h,v 1.1 1999/09/03 08:41:12 mdw Exp $
+ *
+ * Implementation of the IDEA cipher
+ *
+ * (c) 1999 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: idea.h,v $
+ * Revision 1.1 1999/09/03 08:41:12 mdw
+ * Initial import.
+ *
+ */
+
+/*----- Notes on the IDEA block cipher ------------------------------------*
+ *
+ * IDEA was invented by James Massey and Xuejia Lai. The fundamental idea
+ * underlying the cipher is combining incompatible group operations. The
+ * algorithm's main claim to fame is that it is the symmetric cipher in PGP
+ * version 2.
+ *
+ * The IDEA algorithm is allegedly patented by Ascom Tech A.G., even in the
+ * UK and Europe. Ascom are willing to grant licences for use in software
+ * which forbids commercial use, but this is not compatible with Free
+ * Software Foundation ideology. The author recommends against the use of
+ * the IDEA cipher entirely. Blowfish is conceptually simpler, appears more
+ * concervative, offers a larger keyspace, runs faster, and is in the public
+ * domain.
+ */
+
+#ifndef IDEA_H
+#define IDEA_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stddef.h>
+
+#include <mLib/bits.h>
+
+/*----- Magical numbers ---------------------------------------------------*/
+
+#define IDEA_BLKSZ 8
+#define IDEA_KEYSZ 16
+#define IDEA_CLASS (N, B, 64)
+
+/*----- Data structures ---------------------------------------------------*/
+
+typedef struct idea_ctx {
+ uint16 e[52];
+ uint16 d[52];
+} idea_ctx;
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @idea_init@ --- *
+ *
+ * Arguments: @idea_ctx *k@ = pointer to key block
+ * @const void *buf@ = pointer to key buffer
+ * @size_t sz@ = size of key material
+ *
+ * Returns: ---
+ *
+ * Use: Initializes an IDEA key buffer. The buffer must be exactly
+ * 16 bytes in size, because IDEA is only defined with a key
+ * size of 128 bits.
+ */
+
+extern void idea_init(idea_ctx */*k*/, const void */*buf*/, size_t /*sz*/);
+
+/* --- @idea_eblk@, @idea_dblk@ --- *
+ *
+ * Arguments: @const idea_ctx *k@ = pointer to a key block
+ * @const uint32 s[2]@ = pointer to source block
+ * @uint32 d[2]@ = pointer to destination block
+ *
+ * Returns: ---
+ *
+ * Use: Low-level block encryption and decryption.
+ */
+
+extern void idea_eblk(const idea_ctx */*k*/,
+ const uint32 */*s*/, uint32 */*d*/);
+extern void idea_dblk(const idea_ctx */*k*/,
+ const uint32 */*s*/, uint32 */*d*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
--- /dev/null
+.\" -*-nroff-*-
+.TH key 1 "5 June 1999" Catacomb
+.SH NAME
+key \- simple key management system
+.SH SYNOPSIS
+.B key
+.RB [ \-k
+.IR keyring ]
+.I command
+.PP
+where
+.I command
+is one of:
+.PP
+.B add
+.RB [ \-b
+.IR bits ]
+.RB [ \-e
+.IR expire ]
+.RB [ \-c
+.IR comment ]
+.I type
+.IR attr ...
+.br
+.B expire
+.IR keyid ...
+.br
+.B delete
+.IR keyid ...
+.br
+.B setattr
+.I keyid
+.IR attr ...
+.br
+.B list
+.RB [ \-qv ]
+.br
+.B tidy
+.br
+.B extract
+.I file
+.IR keyid ...
+.br
+.B merge
+.I file
+.SH DESCRIPTION
+The
+.B key
+command performs useful operations on Catacomb keyring files. It
+provides a number of subcommands, by which the various operations may be
+carried out.
+.SS "Global options"
+Before the command name,
+.I "global options"
+may be given. The following global options are supported:
+.TP
+.B "\-h, \-\-help"
+Writes a brief summary of
+.BR key 's
+various options to standard output, and
+returns a successful exit status.
+.TP
+.B "\-v, \-\-version"
+Writes the program's version number to standard output, and returns a
+successful exit status.
+.TP
+.B "\-u, \-\-usage"
+Writes a very terse command line summary to standard output, and returns
+a successful exit status.
+.TP
+.BI "\-k, \-\-keyring=" file
+Names the keyring file which
+.B key
+is to process. The default keyring, used if this option doesn't specify
+one, is the file named
+.B keyring
+in the current directory. The keyring must be stored in a regular file:
+pipes, sockets, devices etc. are not allowed.
+The
+.B key
+program attempts to lock the keyring before accessing it, using
+.BR fcntl (2)
+locking. It will however time out after a short while (10 seconds) and
+report a failure.
+.SS Concepts
+In addition to the actual key data itself, a Catacomb key has a number
+of other pieces of information attached to it:
+.TP
+.B keyid
+Every key has a 32-bit identifying number, written in hexadecimal. The
+keyid is derived from the actual key contents (although knowledge of a
+key's keyid doesn't help one to guess the key itself). Applications use
+keyids to refer to specific keys. A
+.I deleted
+key cannot be looked up by keyid.
+.TP
+.B type
+A key's type string describes what the key may be used for. The type
+string is arbitrary, except that it may not contain whitespace
+characters. Applications use key types to obtain an arbitrary but
+suitable key for some purpose. An
+.I expired
+key cannot be looked up by type, but may be looked up by keyid.
+.TP
+.B "expiry time"
+Most keys expire after a certain amount of time. Once a key has
+expired, it will no longer be chosen as a result of a lookup by key
+type. However, it is not deleted until its deletion time is also
+reached.
+.TP
+.B "deletion time"
+A key's deletion time is the latest expiry time of any of the objects
+which require that key. For example, a key used for authenticating
+cryptographic cookies should have its deletion time set to the longest
+expiry time of any of the cookies it can authenticate. A key is never
+deleted until it has also expired. Once a key has expired
+.I and
+its deletion time is passed, it can no longer be referred to by
+applications, and will be removed from the keyring next time it's
+written to disk.
+.TP
+.B comment
+A key may be given a comment when it's created. The comment is for the
+benefit of users, and isn't interpreted by applications at all.
+(Hopefully.)
+.TP
+.B attributes
+A key as zero or more name/value pairs. The names and values are
+arbitrary strings, except they may not contain null bytes. Some
+attributes may have meaning for particular applications or key types;
+others may be assigned global meanings in future.
+.SH "COMMAND REFERENCE"
+.SS add
+The
+.B add
+command creates a new key and adds it to the keyring. The command
+accepts the following options:
+.TP
+.BI "\-b, \-\-bits=" bits
+The length of the key to generate, in bits. The default, if this option
+is not supplied, is 128 bits. The bit length must be nonzero, and must
+be a multiple of 8.
+.TP
+.BI "\-e, \-\-expire=" expire
+The expiry date for the generated key. This may be the string
+.RB ` forever '
+if the key should never expire automatically, or any date acceptable to
+the
+.BR getdate (3)
+library function. Briefly,
+.B getdate
+understands absolute dates such as
+.RB ` 1999-08-02 '
+or
+.RB ` "August 2nd, 1999" ',
+and (perhaps more usefully) relative dates such as
+.RB ` "+2 weeks" '.
+The default is to allow a 2 week expiry, which isn't useful.
+.TP
+.BI "\-c, \-\-comment=" comment
+Sets a comment for the key. The default is not to attach a comment.
+.PP
+The key's type is given by the required
+.I type
+argument. Following the type are zero or more attributes, which are
+attached to the key in the same way as for the
+.B setattr
+command.
+.PP
+The
+.B key
+program only generates random bitstrings, which are suitable for most
+symmetric algorithms but not for public key cryptography. Generating
+keys for more exotic algorithms is a feature which will be added later.
+The keys are generated using the Catacomb random number generator, using
+the
+.B rand_goodbits
+function. The Catacomb generator is believed to be strong.
+.SS expire
+Forces keys to immediately expire. An expired key is not chosen when a
+program requests a key by its type. The keys to expire are listed by
+their
+.IR keyid s.
+.SS delete
+Deletes keys immediately. The keys to delete are listed by their
+.IR keyid s.
+Be careful when deleting keys. It might be a better idea
+to expire keys rather than deleting them.
+.SS setattr
+Attaches attributes to a key. The key to which the attributes should be
+attached is given by its
+.IR keyid .
+Each attribute has the form
+.IB name = value\fR.
+An attribute can be deleted by assigning it an empty value. Although
+the keyring file format is capable of representing an attribute with an
+empty value as distinct from a nonexistant attribute, this interface
+does not allow empty attributes to be set.
+.SS list
+Lists the keys in the keyring. A couple of options are supported:
+.TP
+.B "\-v, \-\-verbose"
+Increases the amount of information displayed for each key. Repeat for
+a greater effect.
+.TP
+.B "\-q, \-\-quiet"
+Decreases the amount of information displayed for each key. Each use
+cancels a
+.RB ` \-v '
+option.
+.PP
+By default, a single line of output is generated for each, showing
+keyids, types, expiry and deletion dates, and comments. Additional
+.RB ` \-v '
+options show more information, such as the exact time of day for expiry
+and deletion, key attributes, and a hex dump of the actual key data.
+.SS tidy
+Simply reads the keyring from file and writes it back again. This has
+the effect of removing any deleted keys from the file.
+.SS extract
+Writes a selection of keys to the named
+.IR file ,
+which may be
+.RB ` \- '
+to designate standard output. The keys to extract are listed by their
+.IR keyid s.
+The output is a valid keyring file.
+.SS merge
+Merges the keys from the named
+.IR file ,
+which may be
+.RB ` \- '
+to designate standard input, with the keyring. Keys already in the
+keyring are not overwritten: you must explicitly remove them first if
+you want them to be replaced during the merge.
+.SH BUGS
+The ability to generate keys for specific algorithms ought to be added,
+for DES (setting the parity bits correctly), RSA, ElGamal and DSA, at
+the very least. (None of these systems are actually implemented in
+Catacomb at the moment, however.)
+.SH "SEE ALSO"
+.BR keyring (5).
+.SH AUTHOR
+Mark Wooding, <mdw@nsict.org>
+
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: key.c,v 1.1 1999/09/03 08:41:12 mdw Exp $
+ *
+ * Simple key management
+ *
+ * (c) 1999 Mark Wooding
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: key.c,v $
+ * Revision 1.1 1999/09/03 08:41:12 mdw
+ * Initial import.
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <mLib/alloc.h>
+#include <mLib/base64.h>
+#include <mLib/bits.h>
+#include <mLib/crc32.h>
+#include <mLib/dstr.h>
+#include <mLib/hash.h>
+#include <mLib/lock.h>
+#include <mLib/report.h>
+#include <mLib/str.h>
+#include <mLib/sub.h>
+#include <mLib/sym.h>
+#include <mLib/url.h>
+
+#include "key.h"
+
+/*----- Useful macros -----------------------------------------------------*/
+
+#define KEY_PARANOID
+#define NOTHING
+
+#ifdef KEY_PARANOID
+# define KEY_WRITE(f, func, val) do { \
+ if (!(f)->f & KF_WRITE) { \
+ moan(#func " [caller error]: keyfile is readonly"); \
+ errno = EROFS; \
+ return val; \
+ } \
+ } while (0)
+#else
+# define KEY_WRITE(f, func) do { ; } while (0)
+#endif
+
+#define KEY_MODIFY(f) do { (f)->f |= KF_MODIFIED; } while (0)
+
+#define KEY_LOAD(n) ((n) * 2)
+
+/*----- Sanity checking of values -----------------------------------------*/
+
+/* --- @key_chktype@ --- *
+ *
+ * Arguments: @const char *type@ = pointer to a type string
+ *
+ * Returns: Zero if OK, -1 on error.
+ *
+ * Use: Checks whether a type string is OK.
+ */
+
+int key_chktype(const char *type)
+{
+ if (!type || !*type)
+ goto fail;
+ while (*type) {
+ if (isspace((unsigned char)*type))
+ goto fail;
+ type++;
+ }
+ return (0);
+
+fail:
+ errno = EINVAL;
+ return (-1);
+}
+
+/* --- @key_chkcomment@ --- *
+ *
+ * Arguments: @const char *comment@ = pointer to a comment string
+ *
+ * Returns: Zero if OK, -1 on error.
+ *
+ * Use: Checks whether a comment string is OK.
+ */
+
+int key_chkcomment(const char *c)
+{
+ if (!c)
+ return (0);
+ if (!*c)
+ goto fail;
+ while (*c) {
+ if (*c == '\n')
+ goto fail;
+ c++;
+ }
+ return (0);
+
+fail:
+ errno = EINVAL;
+ return (-1);
+}
+
+/*----- Low-level fiddling ------------------------------------------------*/
+
+/* --- @insert@ --- *
+ *
+ * Arguments: @key_file *f@ = pointer to file structure
+ * @const char *type@ = type of key to insert
+ * @const void *k@ = pointer to key data
+ * @size_t ksz@ = size of key data
+ * @time_t exp@ = expiry time for key
+ * @time_t del@ = deletion time for key
+ *
+ * Returns: Pointer to key block to fill in the rest of, or zero.
+ *
+ * Use: Inserts a key into a key file.
+ */
+
+static key *insert(key_file *f,
+ const char *type,
+ const void *k, size_t ksz,
+ time_t exp, time_t del)
+{
+ uint32 id;
+ key *kk;
+ key_type *t;
+
+ /* --- Sanity preservatives --- */
+
+ if (key_chktype(type))
+ return (0);
+
+ /* --- Insert into the id table --- */
+
+ {
+ hash_base **bin, **b;
+
+ CRC32(id, 0, k, ksz);
+ bin = HASH_BIN(&f->byid, id);
+ for (b = bin; *b; b = &(*b)->next) {
+ if ((*b)->hash == id) {
+ errno = EEXIST;
+ return (0);
+ }
+ }
+
+ kk = CREATE(key);
+ kk->_b.next = 0;
+ *b = &kk->_b;
+ kk->_b.hash = id;
+ }
+
+ /* --- Extend the table --- */
+
+ if (f->idload > 0)
+ f->idload--;
+ else if (hash_extend(&f->byid))
+ f->idload = KEY_LOAD(f->byid.mask / 2);
+
+ /* --- Initialize the key block --- */
+
+ kk->id = id;
+ kk->k = sub_alloc(ksz);
+ memcpy(kk->k, k, ksz);
+ kk->ksz = ksz;
+ kk->type = xstrdup(type);
+ kk->exp = exp;
+ kk->del = del;
+ sym_create(&kk->a);
+ kk->c = 0;
+
+ /* --- Insert into the type table --- */
+
+ {
+ unsigned found;
+ t = sym_find(&f->bytype, type, -1, sizeof(*t), &found);
+ if (!found) {
+ t->k = kk;
+ kk->next = 0;
+ } else {
+ key **p = &t->k;
+ if (exp != KEXP_FOREVER) {
+ while (*p && (*p)->exp != KEXP_EXPIRE && (*p)->exp > exp)
+ p = &(*p)->next;
+ }
+ kk->next = *p;
+ *p = kk;
+ }
+ }
+
+ return (kk);
+}
+
+/*----- Iteration and iterators -------------------------------------------*/
+
+/* --- @key_mkiter@ --- *
+ *
+ * Arguments: @key_iter *i@ = pointer to iterator object
+ * @key_file *f@ = pointer to file structure
+ *
+ * Returns: ---
+ *
+ * Use: Initializes a key iterator. The keys are returned by
+ * @key_next@.
+ */
+
+void key_mkiter(key_iter *i, key_file *f)
+{
+ HASH_MKITER(&i->i, &f->byid);
+ i->t = time(0);
+}
+
+/* --- @key_next@ --- *
+ *
+ * Arguments: @key_iter *i@ = pointer to iterator object
+ *
+ * Returns: Pointer to next key, or null.
+ *
+ * Use: Returns the next key in some arbitrary sequence.
+ */
+
+key *key_next(key_iter *i)
+{
+ hash_base *b;
+ key *k;
+ do {
+ HASH_NEXT(&i->i, b);
+ k = (key *)b;
+ } while (k && KEY_EXPIRED(i->t, k->exp) && KEY_DELETED(i->t, k->del));
+ return (k);
+}
+
+/* --- @key_mkattriter@ --- *
+ *
+ * Arguments: @key_attriter *i@ = pointer to attribute iterator
+ * @key_file *f@ = pointer to key file
+ * @key *k@ = pointer to key
+ *
+ * Returns: ---
+ *
+ * Use: Initializes an attribute iterator. The attributes are
+ * returned by @key_nextattr@.
+ */
+
+void key_mkattriter(key_attriter *i, key_file *f, key *k)
+{
+ sym_mkiter(&i->i, &k->a);
+}
+
+/* --- @key_nextattr@ --- *
+ *
+ * Arguments: @key_attriter *i@ = pointer to attribute iterator
+ * @const char **n, **v@ = pointers to name and value
+ *
+ * Returns: Zero if no attribute available, or nonzero if returned OK.
+ *
+ * Use: Returns the next attribute.
+ */
+
+int key_nextattr(key_attriter *i, const char **n, const char **v)
+{
+ key_attr *a = sym_next(&i->i);
+ if (!a)
+ return (0);
+ *n = SYM_NAME(a);
+ *v = a->p;
+ return (1);
+}
+
+/*----- Lookup ------------------------------------------------------------*/
+
+/* --- @key_bytype@ --- *
+ *
+ * Arguments: @key_file *f@ = key file we want a key from
+ * @const char *type@ = type string for desired key
+ *
+ * Returns: Pointer to the best key to use, or null.
+ *
+ * Use: Looks up a key by its type. Returns the key with the latest
+ * expiry time. This function will not return an expired key.
+ */
+
+key *key_bytype(key_file *f, const char *type)
+{
+ time_t now = time(0);
+ key *k;
+ key_type *t;
+
+ if ((t = sym_find(&f->bytype, type, -1, 0, 0)) == 0)
+ return (0);
+ for (k = t->k; k && KEY_EXPIRED(now, k->exp); k = k->next)
+ ;
+ return (k);
+}
+
+/* --- @key_byid@ --- *
+ *
+ * Arguments: @key_file *f@ = key file to find a key from
+ * @uint32 id@ = id to look for
+ *
+ * Returns: Key with matching id.
+ *
+ * Use: Returns a key given its id. This function will return an
+ * expired key, but not a deleted one.
+ */
+
+key *key_byid(key_file *f, uint32 id)
+{
+ time_t t = time(0);
+ hash_base **bin, *b;
+
+ bin = HASH_BIN(&f->byid, id);
+ for (b = *bin; b; b = b->next) {
+ if (b->hash == id) {
+ key *k = (key *)b;
+ if (KEY_EXPIRED(t, k->exp) && KEY_DELETED(t, k->del))
+ return (0);
+ return (k);
+ }
+ }
+ return (0);
+}
+
+/*----- Attributes --------------------------------------------------------*/
+
+/* --- @key_getattr@ --- *
+ *
+ * Arguments: @key_file *f@ = pointer to file
+ * @key *k@ = pointer to key
+ * @const char *n@ = pointer to attribute name
+ *
+ * Returns: Pointer to attribute value, or null if not found.
+ *
+ * Use: Returns the value of a key attribute.
+ */
+
+const char *key_getattr(key_file *f, key *k, const char *n)
+{
+ key_attr *a;
+ if ((a = sym_find(&k->a, n, -1, 0, 0)) == 0)
+ return (0);
+ return (a->p);
+}
+
+/* --- @key_putattr@ --- *
+ *
+ * Arguments: @key_file *f@ = pointer to file
+ * @key *k@ = pointer to key
+ * @const char *n@ = pointer to attribute name
+ * @const char *v@ = pointer to attribute value or null
+ *
+ * Returns: ---
+ *
+ * Use: Inserts an attribute on a key. If an attribute with the same
+ * name already exists, it is deleted. Setting a null value
+ * removes the attribute.
+ */
+
+void key_putattr(key_file *f, key *k, const char *n, const char *v)
+{
+ key_attr *a;
+ unsigned found;
+
+ KEY_WRITE(f, key_putattr, NOTHING);
+
+ if (v) {
+ a = sym_find(&k->a, n, -1, sizeof(*a), &found);
+ if (found)
+ free(a->p);
+ a->p = xstrdup(v);
+ } else if ((a = sym_find(&k->a, n, -1, 0, 0)) != 0) {
+ free(a->p);
+ sym_remove(&k->a, a);
+ }
+
+ KEY_MODIFY(f);
+}
+
+/* --- @key_setcomment@ --- *
+ *
+ * Arguments: @key_file *f@ = pointer to key file block
+ * @key *k@ = pointer to key block
+ * @const char *c@ = pointer to comment to set, or zero
+ *
+ * Returns: ---
+ *
+ * Use: Replaces the key's current comment with a new one.
+ */
+
+void key_setcomment(key_file *f, key *k, const char *c)
+{
+ KEY_WRITE(f, key_setcomment, NOTHING);
+ if (key_chkcomment(c))
+ return;
+ if (k->c)
+ free(k->c);
+ if (c)
+ k->c = xstrdup(c);
+ else
+ k->c = 0;
+ KEY_MODIFY(f);
+}
+
+/*----- Low-level file I/O ------------------------------------------------*/
+
+/* --- @key_merge@ --- *
+ *
+ * Arguments: @key_file *f@ = pointer to file structure
+ * @const char *file@ = name of file (for error messages)
+ * @FILE *fp@ = file handle to read from
+ *
+ * Returns: ---
+ *
+ * Use: Reads keys from a file, and inserts them into the file.
+ */
+
+void key_merge(key_file *f, const char *file, FILE *fp)
+{
+ int line = 0;
+ dstr l = DSTR_INIT;
+ dstr d = DSTR_INIT;
+ dstr n = DSTR_INIT, v = DSTR_INIT;
+
+ KEY_WRITE(f, key_merge, NOTHING);
+
+ for (; dstr_putline(&l, fp) != EOF; DRESET(&l)) {
+ char *vf[6];
+ char *p = l.buf;
+ key *k;
+
+ /* --- Skip blank lines and comments --- *
+ *
+ * Quite what they're doing in what ought to be an automatically-
+ * maintained file I don't know.
+ */
+
+ line++;
+ while (isspace((unsigned char)*p))
+ p++;
+ if (!*p || *p == '#')
+ continue;
+
+ /* --- Break the line into fields --- *
+ *
+ * There are currently six fields of interest:
+ *
+ * * The key's type tag.
+ * * The actual key data itself.
+ * * The key expiry time.
+ * * The key deletion time.
+ * * The attributes field.
+ * * Any further comments.
+ *
+ * All but the last field can contain no spaces.
+ */
+
+ {
+ int n = str_split(p, vf, 5, &vf[5]);
+ if (n < 4) {
+ moan("key file `%s', line %i: too few fields", file, line);
+ continue;
+ }
+ }
+
+ /* --- Decode various bits and insert the key --- */
+
+ {
+ base64_ctx b;
+ time_t exp, del;
+
+ base64_init(&b);
+ base64_decode(&b, vf[1], strlen(vf[1]), &d);
+ base64_decode(&b, 0, 0, &d);
+
+ exp = (time_t)atol(vf[2]);
+ del = (time_t)atol(vf[3]);
+
+ if ((k = insert(f, vf[0], d.buf, d.len, exp, del)) == 0)
+ continue;
+ DRESET(&d);
+ }
+
+ /* --- Parse up the attributes, if specified --- */
+
+ if (vf[4]) {
+ url_dctx uc;
+ for (url_initdec(&uc, vf[4]); url_dec(&uc, &n, &v); ) {
+ key_putattr(f, k, n.buf, v.buf);
+ DRESET(&n); DRESET(&v);
+ }
+ }
+
+ /* --- Insert the comment --- */
+
+ if (vf[5])
+ k->c = xstrdup(vf[5]);
+ }
+
+ /* --- Extensive tidying up now required --- */
+
+ dstr_destroy(&l);
+ dstr_destroy(&d);
+ dstr_destroy(&n);
+ dstr_destroy(&v);
+ KEY_MODIFY(f);
+}
+
+/* --- @key_extract@ --- *
+ *
+ * Arguments: @key_file *f@ = pointer to file structure
+ * @key *k@ = key to extract
+ * @FILE *fp@ = file to write on
+ *
+ * Returns: Zero if OK, EOF on error.
+ *
+ * Use: Extracts a key to an ouptut file.
+ */
+
+int key_extract(key_file *f, key *k, FILE *fp)
+{
+ dstr d = DSTR_INIT;
+
+ /* --- Encode the key and write the easy stuff --- */
+
+ {
+ base64_ctx b;
+ base64_init(&b);
+ b.indent = "";
+ base64_encode(&b, k->k, k->ksz, &d);
+ base64_encode(&b, 0, 0, &d);
+ DPUTZ(&d);
+ fprintf(fp, "%s %s %li %li ",
+ k->type, d.buf, (long)k->exp, (long)k->del);
+ DRESET(&d);
+ }
+
+ /* --- Output the attributes --- */
+
+ {
+ int none = 1;
+ sym_iter i;
+ key_attr *a;
+ url_ectx uc;
+
+ url_initenc(&uc);
+ for (sym_mkiter(&i, &k->a); (a = sym_next(&i)) != 0; ) {
+ none = 0;
+ url_enc(&uc, &d, SYM_NAME(a), a->p);
+ }
+ if (none)
+ DPUTS(&d, "-");
+ DWRITE(&d, fp);
+ }
+
+ dstr_destroy(&d);
+ if (k->c) {
+ putc(' ', fp);
+ fputs(k->c, fp);
+ }
+ putc('\n', fp);
+ return (ferror(fp) ? EOF : 0);
+}
+
+/* --- @fdcopy@ --- *
+ *
+ * Arguments: @int source@ = source file descriptor
+ * @int dest@ = destination file descriptor
+ *
+ * Returns: Zero if OK, nonzero otherwise.
+ *
+ * Use: Copies data from one file descriptor to another.
+ */
+
+static int fdcopy(int source, int dest)
+{
+ char buf[4096];
+
+ if (lseek(source, 0, SEEK_SET) < 0||
+ lseek(dest, 0, SEEK_SET) < 0 ||
+ ftruncate(dest, 0) < 0)
+ return (-1);
+ for (;;) {
+ int n = read(source, buf, sizeof(buf));
+ if (n < 0)
+ return (-1);
+ else if (n == 0)
+ break;
+ else if (write(dest, buf, n) < 0)
+ return (-1);
+ }
+ return (0);
+}
+
+/* --- @key_write@ --- *
+ *
+ * Arguments: @key_file *f@ = pointer to key file block
+ *
+ * Returns: A @KWRITE_@ code indicating how well it worked.
+ *
+ * Use: Writes a key file's data back to the actual file. This code
+ * is extremely careful about error handling. It should usually
+ * be able to back out somewhere sensible, but it can tell when
+ * it's got itself into a real pickle and starts leaving well
+ * alone.
+ *
+ * Callers, please make sure that you ring alarm bells when this
+ * function returns @KWRITE_BROKEN@.
+ */
+
+int key_write(key_file *f)
+{
+ dstr n_older = DSTR_INIT, n_old = DSTR_INIT, n_new = DSTR_INIT;
+ int rc = KWRITE_FAIL;
+
+ if (!(f->f & KF_MODIFIED))
+ return (KWRITE_OK);
+
+ /* --- Write a new key file out --- *
+ *
+ * Check for an error after each key line. This ought to be enough.
+ * Checking after each individual byte write and @fprintf@ isn't much fun.
+ */
+
+ dstr_putf(&n_new, "%s.new", f->name);
+
+ {
+ key *k;
+ key_iter i;
+ FILE *fp;
+
+ if ((fp = fopen(n_new.buf, "w")) == 0)
+ goto fail_open;
+
+ for (key_mkiter(&i, f); (k = key_next(&i)) != 0; ) {
+ if (key_extract(f, k, fp)) {
+ fclose(fp);
+ goto fail_write;
+ }
+ }
+
+ if (fclose(fp))
+ goto fail_write;
+ }
+
+ /* --- Set up the other filenames --- */
+
+ dstr_putf(&n_older, "%s.older", f->name);
+ dstr_putf(&n_old, "%s.old", f->name);
+
+ /* --- Move the current backup on one --- *
+ *
+ * If the `older' file exists, then we're in need of attention.
+ */
+
+ {
+ struct stat st;
+ if (stat(n_older.buf, &st) == 0 || errno != ENOENT) {
+ errno = EEXIST;
+ rc = KWRITE_BROKEN;
+ goto fail_shift;
+ }
+ if (rename(n_old.buf, n_older.buf) && errno != ENOENT)
+ goto fail_shift;
+ }
+
+ /* --- Copy the current file to the backup --- */
+
+ {
+ int fd;
+ if ((fd = open(n_old.buf, O_WRONLY | O_CREAT | O_EXCL, 0600)) < 0)
+ goto fail_backup;
+ if (fdcopy(f->fd, fd)) {
+ close(fd);
+ goto fail_backup;
+ }
+ if (close(fd))
+ goto fail_backup;
+ }
+
+ /* --- Copy the newly created file to the current one --- *
+ *
+ * This is the dangerous bit.
+ */
+
+ {
+ int fd;
+ if ((fd = open(n_new.buf, O_RDONLY)) < 0)
+ goto fail_update;
+ if (fdcopy(fd, f->fd)) {
+ close(fd);
+ goto fail_update;
+ }
+ close(fd);
+ if (fsync(f->fd))
+ goto fail_update;
+ }
+
+ /* --- Clean up --- *
+ *
+ * Remove the `new' file and the `older' backup. Then we're done.
+ */
+
+ unlink(n_new.buf);
+ unlink(n_older.buf);
+ return (KWRITE_OK);
+
+ /* --- Failure while writing the new key file --- *
+ *
+ * I need to copy the backup back. If that fails then I'm really stuffed.
+ * If not, then I might as well try to get the backups sorted back out
+ * again.
+ */
+
+fail_update:
+ {
+ int fd;
+ int e = errno;
+
+ if ((fd = open(n_old.buf, O_RDONLY)) < 0)
+ rc = KWRITE_BROKEN;
+ else if (fdcopy(fd, f->fd)) {
+ close(fd);
+ rc = KWRITE_BROKEN;
+ } else {
+ close(fd);
+ if (fsync(f->fd))
+ rc = KWRITE_BROKEN;
+ }
+
+ errno = e;
+ if (rc == KWRITE_BROKEN)
+ goto fail_shift;
+ }
+ /* Now drop through */
+
+ /* --- Failure while writing the new backup --- *
+ *
+ * The new backup isn't any use. Try to recover the old one.
+ */
+
+fail_backup:
+ {
+ int e = errno;
+ unlink(n_old.buf);
+ if (rename(n_older.buf, n_old.buf) && errno != ENOENT)
+ rc = KWRITE_BROKEN;
+ errno = e;
+ }
+ /* Now drop through */
+
+ /* --- Failure while demoting the current backup --- *
+ *
+ * Leave the completed output file there for the operator in case he wants
+ * to clean up.
+ */
+
+fail_shift:
+ dstr_destroy(&n_new);
+ dstr_destroy(&n_old);
+ dstr_destroy(&n_older);
+ return (rc);
+
+/* --- Failure during write of new data --- *
+ *
+ * Clean up the new file and return. These errors can never cause
+ * breakage.
+ */
+
+fail_write:
+ unlink(n_new.buf);
+ fail_open:
+ dstr_destroy(&n_new);
+ return (rc);
+}
+
+/*----- Opening and closing files -----------------------------------------*/
+
+/* --- @key_open@ --- *
+ *
+ * Arguments: @key_file *f@ = pointer to file structure to initialize
+ * @const char *file@ = pointer to the file name
+ * @int how@ = opening options (@KOPEN_*@).
+ *
+ * Returns: Zero if it worked, nonzero otherwise.
+ *
+ * Use: Opens a key file, reads its contents, and stores them in a
+ * structure. The file is locked appropriately until closed
+ * using @key_close@. On an error, everything is cleared away
+ * tidily. If the file is opened with @KOPEN_WRITE@, it's
+ * created if necessary, with read and write permissions for its
+ * owner only.
+ */
+
+int key_open(key_file *f, const char *file, int how)
+{
+ FILE *fp;
+
+ /* --- Trivial bits of initialization --- */
+
+ f->f = 0;
+ f->name = xstrdup(file);
+
+ /* --- Open the file and get the lock --- */
+
+ {
+ int of, lf;
+ const char *ff;
+ int fd;
+
+ /* --- Lots of things depend on whether we're writing --- */
+
+ switch (how) {
+ case KOPEN_READ:
+ of = O_RDONLY;
+ lf = LOCK_NONEXCL;
+ ff = "r";
+ break;
+ case KOPEN_WRITE:
+ of = O_RDWR | O_CREAT;
+ lf = LOCK_EXCL;
+ ff = "r+";
+ break;
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if ((fd = open(file, of, 0600)) < 0)
+ return (-1);
+ if (fcntl(fd, F_SETFD, 1) < 0 ||
+ lock_file(fd, lf) < 0 || (fp = fdopen(fd, ff)) == 0) {
+ close(fd);
+ return (-1);
+ }
+ f->fd = fd;
+ }
+
+ /* --- Read the file of keys into the table --- */
+
+ hash_create(&f->byid, 64);
+ f->idload = KEY_LOAD(64);
+ sym_create(&f->bytype);
+ f->f |= KF_WRITE;
+ key_merge(f, file, fp);
+ if (how == KOPEN_READ)
+ f->f &= ~(KF_WRITE | KF_MODIFIED);
+ else
+ f->f &= ~KF_MODIFIED;
+
+ /* --- Close the file if only needed for reading --- */
+
+ if (how == KOPEN_READ) {
+ f->fp = 0;
+ fclose(fp);
+ } else
+ f->fp = fp;
+
+ return (0);
+}
+
+/* --- @key_close@ --- *
+ *
+ * Arguments: @key_file *f@ = pointer to key file block
+ *
+ * Returns: A @KWRITE_@ code indicating how it went.
+ *
+ * Use: Frees all the key data, writes any changes. Make sure that
+ * all hell breaks loose if this returns @KWRITE_BROKEN@.
+ */
+
+int key_close(key_file *f)
+{
+ int e;
+ hash_base *b;
+ hash_iter i;
+
+ if ((e = key_write(f)) != KWRITE_OK)
+ return (e);
+
+ /* --- Free all the individual keys --- */
+
+ for (hash_mkiter(&i, &f->byid); (b = hash_next(&i)) != 0; ) {
+ sym_iter j;
+ key_attr *a;
+ key *k = (key *)b;
+
+ sub_free(k->k, k->ksz);
+ free(k->type);
+ if (k->c)
+ free(k->c);
+ for (sym_mkiter(&j, &k->a); (a = sym_next(&j)) != 0; )
+ free(a->p);
+ sym_destroy(&k->a);
+ DESTROY(k);
+ }
+ hash_destroy(&f->byid);
+ sym_destroy(&f->bytype);
+
+ if (f->fp)
+ fclose(f->fp);
+ free(f->name);
+ return (KWRITE_OK);
+}
+
+/*----- Miscellaneous functions -------------------------------------------*/
+
+/* --- @key_new@ ---
+ *
+ * Arguments: @key_file *f@ = pointer to key file
+ * @const char *type@ = the type of this key
+ * @const void *k@ = pointer to key data
+ * @size_t ksz@ = size of key data
+ * @time_t exp@ = when the key expires
+ * @const char *c@ = textual comment to attach
+ *
+ * Returns: Key block containing new data, or null if it couldn't be
+ * done.
+ *
+ * Use: Attaches a new key to a key file. You must have a writable
+ * key file for this to work.
+ *
+ * The type is a key type string. This interface doesn't care
+ * about how type strings are formatted: it just treats them as
+ * opaque gobs of text. Clients are advised to choose some
+ * standard for representing key types, though.
+ *
+ * The key can be any old binary mess.
+ *
+ * The expiry time should either be a time in the future, or the
+ * magic value @KEXP_FOREVER@ which means `never expire this
+ * key'. Be careful with `forever' keys. If I were you, I'd
+ * use a more sophisticated key management system than this for
+ * them.
+ *
+ * The comment can be any old text not containing newlines or
+ * nulls. This interface doesn't impose any length restrictions
+ * on comment lengths.
+ */
+
+key *key_new(key_file *f, const char *type,
+ const void *k, size_t ksz,
+ time_t exp, const char *c)
+{
+ key *kk;
+ time_t t = time(0);
+
+ KEY_WRITE(f, key_new, 0);
+
+ if (KEY_EXPIRED(t, exp) ||
+ key_chktype(type) || key_chkcomment(c) ||
+ (kk = insert(f, type, k, ksz, exp, KEXP_UNUSED)) == 0)
+ return (0);
+ if (c)
+ kk->c = xstrdup(c);
+ KEY_MODIFY(f);
+ return (kk);
+}
+
+/* --- @key_delete@ --- *
+ *
+ * Arguments: @key_file *f@ = pointer to file block
+ * @key *k@ = key to delete
+ *
+ * Returns: ---
+ *
+ * Use: Removes the given key from the list. The key file must be
+ * writable. (Due to the horridness of the data structures,
+ * deleted keys aren't actually removed, just marked so that
+ * they can't be looked up or iterated over. One upshot of
+ * this is that they don't get written back to the file when
+ * it's closed.)
+ */
+
+void key_delete(key_file *f, key *k)
+{
+ KEY_WRITE(f, key_delete, NOTHING);
+ k->exp = KEXP_EXPIRE;
+ k->del = KEXP_UNUSED;
+ KEY_MODIFY(f);
+}
+
+/* --- @key_expire@ --- *
+ *
+ * Arguments: @key_file *f@ = pointer to file block
+ * @key *k@ = pointer to key block
+ *
+ * Returns: ---
+ *
+ * Use: Immediately marks the key as expired. It may be removed
+ * immediately, if it is no longer required, and will be removed
+ * by a tidy operation when it is no longer required. The key
+ * file must be writable.
+ */
+
+void key_expire(key_file *f, key *k)
+{
+ KEY_WRITE(f, key_expire, NOTHING);
+ k->exp = KEXP_EXPIRE;
+ if (k->del == KEXP_FOREVER)
+ k->del = KEXP_UNUSED;
+ KEY_MODIFY(f);
+}
+
+/* --- @key_used@ --- *
+ *
+ * Arguments: @key_file *f@ = pointer to key file
+ * @key *k@ = pointer to key block
+ * @time_t t@ = when key can be removed
+ *
+ * Returns: Zero if OK, nonzero on failure.
+ *
+ * Use: Marks a key as being required until a given time. Even
+ * though the key may expire before then (and won't be returned
+ * by type after that time), it will still be available when
+ * requested explicitly by id. The key file must be writable.
+ *
+ * The only (current) reason for failure is attempting to use
+ * a key which can expire for something which can't.
+ */
+
+int key_used(key_file *f, key *k, time_t t)
+{
+ KEY_WRITE(f, key_used, -1);
+ if (t == KEXP_FOREVER) {
+ if (k->exp != KEXP_FOREVER) {
+ errno = EINVAL;
+ return (-1);
+ }
+ } else if (k->del >= t)
+ return (0);
+
+ k->del = t;
+ KEY_MODIFY(f);
+ return (0);
+}
+
+/*----- That's all, folks -------------------------------------------------*/
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: key.h,v 1.1 1999/09/03 08:41:12 mdw Exp $
+ *
+ * Simple key management
+ *
+ * (c) 1999 Mark Wooding
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: key.h,v $
+ * Revision 1.1 1999/09/03 08:41:12 mdw
+ * Initial import.
+ *
+ */
+
+#ifndef KEY_H
+#define KEY_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stdio.h>
+#include <time.h>
+
+#include <mLib/bits.h>
+#include <mLib/hash.h>
+#include <mLib/sym.h>
+
+/*----- Data structures ---------------------------------------------------*/
+
+/* --- Key attributes --- *
+ *
+ * Each attribute is stored as a symbol in a symbol table. The value is
+ * the plain (not url-encoded) text to be written to the the file. If the
+ * value is binary data, then by this point it's base-64 encoded.
+ */
+
+typedef struct key_attr {
+ sym_base _b; /* Symbol table data */
+ char *p; /* Pointer to attribute value */
+} key_attr;
+
+/* --- Main key structure --- *
+ *
+ * Each key is stored in two symbol tables, one indexed by keyid, and the
+ * other indexed by type. Because many keys can have the same type, the type
+ * table contains a list of keys, sorted in descending order of expiry.
+ */
+
+typedef struct key {
+ hash_base _b; /* Symbol table data */
+ struct key *next; /* Next key of the same type */
+ uint32 id; /* Key id used to name it */
+ char *type; /* Textual key type */
+ void *k; /* Actual key data */
+ size_t ksz; /* Size of the key data */
+ time_t exp, del; /* Expiry times for keys */
+ sym_table a; /* Hashtable of key attributes */
+ char *c; /* Any additional comments */
+} key;
+
+/* --- The keys-by-type entries --- */
+
+typedef struct key_type {
+ sym_base _b; /* Symbol table data */
+ key *k; /* Pointer to first key in list */
+} key_type;
+
+/* --- A key file --- */
+
+typedef struct key_file {
+ FILE *fp; /* File pointer open on file */
+ int fd; /* File descriptor open on file */
+ char *name; /* Filename used to create it */
+ unsigned f; /* Various useful flags */
+ hash_table byid; /* Table of keys by keyid */
+ sym_table bytype; /* Table of keys by type */
+ size_t idload; /* Loading on id table */
+} key_file;
+
+/* --- Key file flags --- */
+
+enum {
+ KF_WRITE = 1, /* File opened for writing */
+ KF_MODIFIED = 2 /* File has been modified */
+};
+
+/* --- Iterating over keys --- *
+ *
+ * Both of these are simple symbol table iterators, but they're made distinct
+ * types for the dubious benefits that type safety brings.
+ */
+
+typedef struct { hash_iter i; time_t t; } key_iter;
+typedef struct { sym_iter i; } key_attriter;
+
+/* --- File opening options --- */
+
+enum {
+ KOPEN_READ,
+ KOPEN_WRITE
+};
+
+/* --- Various other magic numbers --- */
+
+#define KEXP_UNUSED ((time_t)0) /* Key has never been used */
+#define KEXP_FOREVER ((time_t)-1) /* Never expire this key */
+#define KEXP_EXPIRE ((time_t)-2) /* Expire this key when unused */
+
+/* --- Write attempt codes --- */
+
+enum {
+ KWRITE_OK, /* Everything went fine */
+ KWRITE_FAIL = -1, /* Close attempt failed */
+ KWRITE_BROKEN = -2 /* Key ring needs manual fixing */
+};
+
+/* --- Macros for testing expiry --- */
+
+#define KEY_EXPIRED(now, exp) \
+ ((exp) == KEXP_EXPIRE || ((exp) != KEXP_FOREVER && (exp) < (now)))
+
+#define KEY_DELETED(now, del) ((del) == KEXP_FOREVER || (del) < (now))
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @key_chktype@ --- *
+ *
+ * Arguments: @const char *type@ = pointer to a type string
+ *
+ * Returns: Zero if OK, -1 on error.
+ *
+ * Use: Checks whether a type string is OK.
+ */
+
+extern int key_chktype(const char */*type*/);
+
+/* --- @key_chkcomment@ --- *
+ *
+ * Arguments: @const char *comment@ = pointer to a comment string
+ *
+ * Returns: Zero if OK, -1 on error.
+ *
+ * Use: Checks whether a comment string is OK.
+ */
+
+extern int key_chkcomment(const char */*c*/);
+
+/* --- @key_mkiter@ --- *
+ *
+ * Arguments: @key_iter *i@ = pointer to iterator object
+ * @key_file *f@ = pointer to file structure
+ *
+ * Returns: ---
+ *
+ * Use: Initializes a key iterator. The keys are returned by
+ * @key_next@.
+ */
+
+extern void key_mkiter(key_iter */*i*/, key_file */*f*/);
+
+/* --- @key_next@ --- *
+ *
+ * Arguments: @key_iter *i@ = pointer to iterator object
+ *
+ * Returns: Pointer to next key, or null.
+ *
+ * Use: Returns the next key in some arbitrary sequence.
+ */
+
+extern key *key_next(key_iter */*i*/);
+
+/* --- @key_mkattriter@ --- *
+ *
+ * Arguments: @key_attriter *i@ = pointer to attribute iterator
+ * @key_file *f@ = pointer to key file
+ * @key *k@ = pointer to key
+ *
+ * Returns: ---
+ *
+ * Use: Initializes an attribute iterator. The attributes are
+ * returned by @key_nextattr@.
+ */
+
+extern void key_mkattriter(key_attriter */*i*/, key_file */*f*/, key */*k*/);
+
+/* --- @key_nextattr@ --- *
+ *
+ * Arguments: @key_attriter *i@ = pointer to attribute iterator
+ * @const char **n, **v@ = pointers to name and value
+ *
+ * Returns: Zero if no attribute available, or nonzero if returned OK.
+ *
+ * Use: Returns the next attribute.
+ */
+
+extern int key_nextattr(key_attriter */*i*/,
+ const char **/*n*/, const char **/*v*/);
+
+/* --- @key_bytype@ --- *
+ *
+ * Arguments: @key_file *f@ = key file we want a key from
+ * @const char *type@ = type string for desired key
+ *
+ * Returns: Pointer to the best key to use, or null.
+ *
+ * Use: Looks up a key by its type. Returns the key with the latest
+ * expiry time. This function will not return an expired key.
+ */
+
+extern key *key_bytype(key_file */*f*/, const char */*type*/);
+
+/* --- @key_byid@ --- *
+ *
+ * Arguments: @key_file *f@ = key file to find a key from
+ * @uint32 id@ = id to look for
+ *
+ * Returns: Key with matching id.
+ *
+ * Use: Returns a key given its id. This function will return an
+ * expired key, but not a deleted one.
+ */
+
+extern key *key_byid(key_file */*f*/, uint32 /*id*/);
+
+/* --- @key_getattr@ --- *
+ *
+ * Arguments: @key_file *f@ = pointer to file
+ * @key *k@ = pointer to key
+ * @const char *n@ = pointer to attribute name
+ *
+ * Returns: Pointer to attribute value, or null if not found.
+ *
+ * Use: Returns the value of a key attribute.
+ */
+
+extern const char *key_getattr(key_file */*f*/, key */*k*/,
+ const char */*n*/);
+
+/* --- @key_putattr@ --- *
+ *
+ * Arguments: @key_file *f@ = pointer to file
+ * @key *k@ = pointer to key
+ * @const char *n@ = pointer to attribute name
+ * @const char *v@ = pointer to attribute value
+ *
+ * Returns: ---
+ *
+ * Use: Inserts an attribute on a key. If an attribute with the same
+ * name already exists, it is deleted.
+ */
+
+extern void key_putattr(key_file */*f*/, key */*k*/,
+ const char */*n*/, const char */*v*/);
+
+/* --- @key_setcomment@ --- *
+ *
+ * Arguments: @key_file *f@ = pointer to key file block
+ * @key *k@ = pointer to key block
+ * @const char *c@ = pointer to comment to set, or zero
+ *
+ * Returns: ---
+ *
+ * Use: Replaces the key's current comment with a new one.
+ */
+
+extern void key_setcomment(key_file */*f*/, key */*k*/, const char */*c*/);
+
+/* --- @key_merge@ --- *
+ *
+ * Arguments: @key_file *f@ = pointer to file structure
+ * @const char *file@ = name of file (for error messages)
+ * @FILE *fp@ = file handle to read from
+ *
+ * Returns: ---
+ *
+ * Use: Reads keys from a file, and inserts them into the file.
+ */
+
+extern void key_merge(key_file */*f*/, const char */*file*/, FILE */*fp*/);
+
+/* --- @key_extract@ --- *
+ *
+ * Arguments: @key_file *f@ = pointer to file structure
+ * @key *k@ = key to extract
+ * @FILE *fp@ = file to write on
+ *
+ * Returns: Zero if OK, EOF on error.
+ *
+ * Use: Extracts a key to an ouptut file.
+ */
+
+extern int key_extract(key_file */*f*/, key */*k*/, FILE */*fp*/);
+
+/* --- @key_write@ --- *
+ *
+ * Arguments: @key_file *f@ = pointer to key file block
+ *
+ * Returns: A @KWRITE_@ code indicating how well it worked.
+ *
+ * Use: Writes a key file's data back to the actual file. This code
+ * is extremely careful about error handling. It should usually
+ * be able to back out somewhere sensible, but it can tell when
+ * it's got itself into a real pickle and starts leaving well
+ * alone.
+ *
+ * Callers, please make sure that you ring alarm bells when this
+ * function returns @KWRITE_BROKEN@.
+ */
+
+extern int key_write(key_file */*f*/);
+
+/* --- @key_open@ --- *
+ *
+ * Arguments: @key_file *f@ = pointer to file structure to initialize
+ * @const char *file@ = pointer to the file name
+ * @int how@ = opening options (@KOPEN_*@).
+ *
+ * Returns: Zero if it worked, nonzero otherwise.
+ *
+ * Use: Opens a key file, reads its contents, and stores them in a
+ * structure. The file is locked appropriately until closed
+ * using @key_close@. On an error, everything is cleared away
+ * tidily. If the file is opened with @KOPEN_WRITE@, it's
+ * created if necessary, with read and write permissions for its
+ * owner only.
+ */
+
+extern int key_open(key_file */*f*/, const char */*file*/, int /*how*/);
+
+/* --- @key_close@ --- *
+ *
+ * Arguments: @key_file *f@ = pointer to key file block
+ *
+ * Returns: A @KWRITE_@ code indicating how it went.
+ *
+ * Use: Frees all the key data, writes any changes. Make sure that
+ * all hell breaks loose if this returns @KWRITE_BROKEN@.
+ */
+
+extern int key_close(key_file */*f*/);
+
+/* --- @key_new@ ---
+ *
+ * Arguments: @key_file *f@ = pointer to key file
+ * @const char *type@ = the type of this key
+ * @const void *k@ = pointer to key data
+ * @size_t ksz@ = size of key data
+ * @time_t exp@ = when the key expires
+ * @const char *c@ = textual comment to attach
+ *
+ * Returns: Key block containing new data, or null if it couldn't be
+ * done.
+ *
+ * Use: Attaches a new key to a key file. You must have a writable
+ * key file for this to work.
+ *
+ * The type is a key type string. This interface doesn't care
+ * about how type strings are formatted: it just treats them as
+ * opaque gobs of text. Clients are advised to choose some
+ * standard for representing key types, though.
+ *
+ * The key can be any old binary mess.
+ *
+ * The expiry time should either be a time in the future, or the
+ * magic value @KEXP_FOREVER@ which means `never expire this
+ * key'. Be careful with `forever' keys. If I were you, I'd
+ * use a more sophisticated key management system than this for
+ * them.
+ *
+ * The comment can be any old text not containing newlines or
+ * nulls. This interface doesn't impose any length restrictions
+ * on comment lengths.
+ */
+
+extern key *key_new(key_file */*f*/, const char */*type*/,
+ const void */*k*/, size_t /*ksz*/,
+ time_t /*exp*/, const char */*c*/);
+
+/* --- @key_delete@ --- *
+ *
+ * Arguments: @key_file *f@ = pointer to file block
+ * @key *k@ = key to delete
+ *
+ * Returns: ---
+ *
+ * Use: Removes the given key from the list. The key file must be
+ * writable. (Due to the horridness of the data structures,
+ * deleted keys aren't actually removed, just marked so that
+ * they can't be looked up or iterated over. One upshot of
+ * this is that they don't get written back to the file when
+ * it's closed.)
+ */
+
+extern void key_delete(key_file */*f*/, key */*k*/);
+
+/* --- @key_expire@ --- *
+ *
+ * Arguments: @key_file *f@ = pointer to file block
+ * @key *k@ = pointer to key block
+ *
+ * Returns: ---
+ *
+ * Use: Immediately marks the key as expired. It may be removed
+ * immediately, if it is no longer required, and will be removed
+ * by a tidy operation when it is no longer required. The key
+ * file must be writable.
+ */
+
+extern void key_expire(key_file */*f*/, key */*k*/);
+
+/* --- @key_used@ --- *
+ *
+ * Arguments: @key_file *f@ = pointer to key file
+ * @key *k@ = pointer to key block
+ * @time_t t@ = when key can be removed
+ *
+ * Returns: Zero if OK, nonzero on failure.
+ *
+ * Use: Marks a key as being required until a given time. Even
+ * though the key may expire before then (and won't be returned
+ * by type after that time), it will still be available when
+ * requested explicitly by id. The key file must be writable.
+ *
+ * The only (current) reason for failure is attempting to use
+ * a key which can expire for something which can't.
+ */
+
+extern int key_used(key_file */*f*/, key */*k*/, time_t /*t*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
--- /dev/null
+.\" -*-nroff-*-
+.TH keyring 5 "5 June 1999" Catacomb
+.SH NAME
+keyring \- description of Catacomb keyring files
+.SH DESCRIPTION
+Keyring files are line-oriented text files. It is recommended that
+programs use only the provided interface for reading and modifying
+keyring files, for consistency of locking and representation: this
+description is provided for the benefit of administrators attempting to
+understand or repair keyring files.
+.PP
+Lines containing only whitespace and lines whose first non-whitespace
+character is
+.RB ` # '
+are ignored, but are not written back to the file. Thus, the comment
+facility is not particularly useful.
+.PP
+Each other line describes a key. Key descriptions consist of between 4
+and six whitespace-separated fields. The final comment field may
+contain whitespace characters. The fields are, in order:
+.TP
+.B type
+The key's type string, set when the key was created.
+.TP
+.B "key data"
+The actual key, Base64 encoded, as described in RFC2045.
+.TP
+.B "expiry time"
+The time at which this key expires, represented as an integer number of
+seconds since 1970-01-01 00:00:00 UTC, not counting leap seconds. The
+special value \-1 signifies that this key never expires.
+.TP
+.B "deletion time"
+The time at which this key should be deleted, using the same
+representation as the expiry time. The special value 0 signifies that
+the key should be deleted on expiry.
+.TP
+.B attributes
+The key's attributes, encoded using the `form-urlencoded' encoding
+defined in RFC1866. This field is optional: if it is omitted, the key
+has no attributes. Alternatively, if there are no attributes, this
+field may be given as a single dash
+.RB ` \- '.
+.TP
+.B comment
+The comment field. This field is optional. It may contain whitespace.
+It is deliberately not included as an attribute, since the urlencoded
+nature of attributes makes them hard to read when perusing a keyring
+file.
+.PP
+It is not envisaged that the file format will change in the future. Any
+extensions will be made by defining new attributes.
+.SH AUTHOR
+Mark Wooding, <mdw@nsict.org>
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: keyutil.c,v 1.1 1999/09/03 08:41:12 mdw Exp $
+ *
+ * Simple key manager program
+ *
+ * (c) 1999 Mark Wooding
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: keyutil.c,v $
+ * Revision 1.1 1999/09/03 08:41:12 mdw
+ * Initial import.
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include "config.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <mLib/mdwopt.h>
+#include <mLib/quis.h>
+#include <mLib/report.h>
+#include <mLib/sub.h>
+
+#include <noise.h>
+#include <rand.h>
+
+#include "getdate.h"
+#include "key.h"
+
+/*----- Handy global state ------------------------------------------------*/
+
+static const char *keyfile = "keyring";
+
+/*----- Useful shared functions -------------------------------------------*/
+
+/* --- @doopen@ --- *
+ *
+ * Arguments: @key_file *f@ = pointer to key file block
+ * @unsigned how@ = method to open file with
+ *
+ * Returns: ---
+ *
+ * Use: Opens a key file and handles errors by panicking
+ * appropriately.
+ */
+
+static void doopen(key_file *f, unsigned how)
+{
+ if (key_open(f, keyfile, how))
+ die(1, "couldn't open file `%s': %s", keyfile, strerror(errno));
+}
+
+/* --- @doclose@ --- *
+ *
+ * Arguments: @key_file *f@ = pointer to key file block
+ *
+ * Returns: ---
+ *
+ * Use: Closes a key file and handles errors by panicking
+ * appropriately.
+ */
+
+static void doclose(key_file *f)
+{
+ switch (key_close(f)) {
+ case KWRITE_FAIL:
+ die(EXIT_FAILURE, "couldn't write file `%s': %s",
+ keyfile, strerror(errno));
+ case KWRITE_BROKEN:
+ die(EXIT_FAILURE, "keyring file `%s' broken: %s (repair manually)",
+ keyfile, strerror(errno));
+ }
+}
+
+/* --- @setattr@ --- *
+ *
+ * Arguments: @key_file *f@ = pointer to key file block
+ * @key *k@ = pointer to key block
+ * @char *v[]@ = array of assignments (overwritten!)
+ *
+ * Returns: ---
+ *
+ * Use: Applies the attribute assignments to the key.
+ */
+
+static void setattr(key_file *f, key *k, char *v[])
+{
+ while (*v) {
+ char *p = *v;
+ size_t eq = strcspn(p, "=");
+ if (p[eq] == 0)
+ moan("invalid assignment: `%s'", p);
+ p[eq] = 0;
+ p += eq + 1;
+ key_putattr(f, k, *v, *p ? p : 0);
+ v++;
+ }
+}
+
+/*----- Command implementation --------------------------------------------*/
+
+/* --- @cmd_add@ --- */
+
+static int cmd_add(int argc, char *argv[])
+{
+ key_file f;
+ key *k;
+ int bits = 128;
+ time_t exp = KEXP_EXPIRE;
+ unsigned fl = 0;
+ unsigned char *p;
+ size_t sz;
+ const char *c = 0;
+
+ /* --- Various useful flag bits --- */
+
+ enum {
+ f_bogus = 1
+ };
+
+ /* --- Parse options for the subcommand --- */
+
+ for (;;) {
+ static struct option opt[] = {
+ { "bits", OPTF_ARGREQ, 0, 'b' },
+ { "expire", OPTF_ARGREQ, 0, 'e' },
+ { "comment", OPTF_ARGREQ, 0, 'c' },
+ { 0, 0, 0, 0 }
+ };
+ int i = mdwopt(argc, argv, "+b:e:c:", opt, 0, 0, 0);
+ if (i < 0)
+ break;
+
+ /* --- Handle the various options --- */
+
+ switch (i) {
+
+ /* --- Bits must be nonzero and a multiple of 8 --- */
+
+ case 'b':
+ if (!(bits = atoi(optarg)) || bits % 8)
+ die(EXIT_FAILURE, "bad number of bits: `%s'", optarg);
+ break;
+
+ /* --- Expiry dates get passed to @get_date@ for parsing --- */
+
+ case 'e':
+ if (strcmp(optarg, "forever") == 0)
+ exp = KEXP_FOREVER;
+ else {
+ exp = get_date(optarg, 0);
+ if (exp == -1)
+ die(EXIT_FAILURE, "bad expiry date: `%s'", optarg);
+ }
+ break;
+
+ /* --- Store comments without interpretation --- */
+
+ case 'c':
+ if (key_chkcomment(c))
+ die(EXIT_FAILURE, "bad comment string: `%s'", optarg);
+ c = optarg;
+ break;
+
+ /* --- Other things are bogus --- */
+
+ default:
+ fl |= f_bogus;
+ break;
+ }
+ }
+
+ /* --- Various sorts of bogusity --- */
+
+ if (fl & f_bogus || optind + 1 > argc) {
+ die(EXIT_FAILURE,
+ "Usage: add [-b BITS] [-e EXPIRE] [-c COMMENT] TYPE [ATTR...]");
+ }
+ if (key_chktype(argv[optind]))
+ die(EXIT_FAILURE, "bad key type: `%s'", argv[optind]);
+ if (exp == KEXP_EXPIRE)
+ exp = time(0) + 14 * 24 * 60 * 60;
+
+ /* --- Initialize the Catacomb random number generator --- */
+
+ rand_init(RAND_GLOBAL);
+ rand_noisesrc(RAND_GLOBAL, &noise_source);
+
+ /* --- Extract the key data from the generator --- */
+
+ sz = bits / 8;
+ p = xmalloc(sz);
+ rand_getgood(RAND_GLOBAL, p, sz);
+
+ /* --- Open the file, add the key, set attributes, close, return --- */
+
+ doopen(&f, KOPEN_WRITE);
+ if (!(k = key_new(&f, argv[optind], p, sz, exp, c)))
+ moan("key not added: expiry date in past?");
+ setattr(&f, k, argv + optind + 1);
+ doclose(&f);
+ return (0);
+}
+
+/* --- @cmd_expire@ --- */
+
+static int cmd_expire(int argc, char *argv[])
+{
+ key_file f;
+ key *k;
+ uint32 id;
+ int i;
+ int rc = 0;
+
+ if (argc < 2)
+ die(EXIT_FAILURE, "Usage: expire KEYID...");
+ doopen(&f, KOPEN_WRITE);
+ for (i = 1; i < argc; i++) {
+ id = (uint32)strtoul(argv[i], 0, 16);
+ if ((k = key_byid(&f, id)) != 0)
+ key_expire(&f, k);
+ else {
+ moan("keyid %lx not found", (unsigned long)id);
+ rc = 1;
+ }
+ }
+ doclose(&f);
+ return (rc);
+}
+
+/* --- @cmd_delete@ --- */
+
+static int cmd_delete(int argc, char *argv[])
+{
+ key_file f;
+ key *k;
+ uint32 id;
+ int i;
+ int rc = 0;
+
+ if (argc < 2)
+ die(EXIT_FAILURE, "Usage: delete KEYID...");
+ doopen(&f, KOPEN_WRITE);
+ for (i = 1; i < argc; i++) {
+ id = (uint32)strtoul(argv[i], 0, 16);
+ if ((k = key_byid(&f, id)) != 0)
+ key_delete(&f, k);
+ else {
+ moan("keyid %lx not found", (unsigned long)id);
+ rc = 1;
+ }
+ }
+ doclose(&f);
+ return (rc);
+}
+
+/* --- @cmd_setattr@ --- */
+
+static int cmd_setattr(int argc, char *argv[])
+{
+ key_file f;
+ key *k;
+ uint32 id;
+
+ if (argc < 3)
+ die(EXIT_FAILURE, "Usage: setattr KEYID ATTR...");
+ doopen(&f, KOPEN_WRITE);
+ id = (uint32)strtoul(argv[1], 0, 16);
+ if ((k = key_byid(&f, id)) == 0)
+ die(EXIT_FAILURE, "keyid %lx not found", (unsigned long)id);
+ setattr(&f, k, argv + 2);
+ doclose(&f);
+ return (0);
+}
+
+/* --- @cmd_comment@ --- */
+
+static int cmd_comment(int argc, char *argv[])
+{
+ uint32 id;
+ key_file f;
+ key *k;
+
+ if (argc < 2 || argc > 3)
+ die(EXIT_FAILURE, "Usage: comment KEYID [COMMENT]");
+ doopen(&f, KOPEN_WRITE);
+ id = (uint32)strtoul(argv[1], 0, 16);
+ if ((k = key_byid(&f, id)) == 0)
+ die(EXIT_FAILURE, "keyid %lx not found", (unsigned long)id);
+ if (key_chkcomment(argv[2]))
+ die(EXIT_FAILURE, "bad comment: `%s'", argv[2]);
+ key_setcomment(&f, k, argv[2]);
+ doclose(&f);
+ return (0);
+}
+
+/* --- @cmd_list@ --- */
+
+static int cmd_list(int argc, char *argv[])
+{
+ key_file f;
+ key *k;
+ key_iter i;
+ unsigned fl = 0;
+ const char *tfmt;
+ int v = 0;
+ time_t t;
+
+ enum {
+ f_bogus = 1,
+ f_newline = 2,
+ f_attr = 4
+ };
+
+ /* --- Parse subcommand options --- */
+
+ for (;;) {
+ static struct option opt[] = {
+ { "quiet", 0, 0, 'q' },
+ { "verbose", 0, 0, 'v' },
+ { 0, 0, 0, 0 }
+ };
+ int i = mdwopt(argc, argv, "qv", opt, 0, 0, 0);
+ if (i < 0)
+ break;
+
+ switch (i) {
+ case 'q':
+ if (v)
+ v--;
+ break;
+ case 'v':
+ v++;
+ break;
+ default:
+ fl |= f_bogus;
+ break;
+ }
+ }
+
+ if (fl & f_bogus || optind != argc)
+ die(EXIT_FAILURE, "Usage: list [-qv]");
+
+ /* --- Open the key file --- */
+
+ doopen(&f, KOPEN_READ);
+ t = time(0);
+
+ /* --- Write the header --- */
+
+ tfmt = v ? "%Y-%m-%d %H:%M:%S" : "%Y-%m-%d";
+
+ /* --- Now iterate through the keys --- */
+
+ for (key_mkiter(&i, &f); (k = key_next(&i)) != 0; ) {
+ char ebuf[24], dbuf[24];
+ struct tm *tm;
+
+ /* --- Sort out the expiry times --- */
+
+ if (KEY_EXPIRED(t, k->exp)) {
+ strcpy(ebuf, "expired");
+ if (KEY_DELETED(t, k->del)) {
+ strcpy(dbuf, "deleted");
+ goto donetime;
+ } else
+ goto deltime;
+ }
+
+ if (k->exp == KEXP_FOREVER)
+ strcpy(ebuf, "forever");
+ else {
+ tm = localtime(&k->exp);
+ strftime(ebuf, sizeof(ebuf), tfmt, tm);
+ }
+
+ /* --- Sort out the delete times --- */
+
+ deltime:
+ if (k->del == KEXP_UNUSED)
+ strcpy(dbuf, "on expiry");
+ else if (k->del == KEXP_FOREVER)
+ strcpy(dbuf, "forever");
+ else {
+ tm = localtime(&k->del);
+ strftime(dbuf, sizeof(dbuf), tfmt, tm);
+ }
+
+ donetime:;
+
+ /* --- Display the data obtained so far --- */
+
+ if (!v) {
+ if (!(fl & f_newline)) {
+ printf("%8s %-20s %-10s %-10s %-23s\n",
+ "Id", "Type", "Expire", "Delete", "Comment");
+ }
+ printf("%08lx %-20s %-10s %-10s %-23s\n",
+ (unsigned long)k->id, k->type, ebuf, dbuf,
+ k->c ? k->c : "<none>");
+ fl |= f_newline;
+ } else {
+
+ /* --- Display the standard header --- */
+
+ if (fl & f_newline)
+ fputc('\n', stdout);
+ printf("keyid: %08lx\n", (unsigned long)k->id);
+ printf("type: %s\n", k->type);
+ printf("expiry: %s\n", ebuf);
+ printf("delete: %s\n", dbuf);
+ printf("comment: %s\n", k->c ? k->c : "<none>");
+
+ /* --- Display the attributes --- */
+
+ if (v > 1) {
+ key_attriter i;
+ const char *av, *an;
+
+ fl &= ~f_attr;
+ printf("attributes:");
+ for (key_mkattriter(&i, &f, k); key_nextattr(&i, &an, &av); ) {
+ printf("\n\t%s = %s", an, av);
+ fl |= f_attr;
+ }
+ if (fl & f_attr)
+ fputc('\n', stdout);
+ else
+ puts(" <none>");
+ }
+
+ /* --- If dumping requested, dump the raw key data in hex --- */
+
+ if (v > 2) {
+ unsigned char *p = k->k;
+ unsigned char *l = p + k->ksz;
+ size_t sz = 0;
+
+ fputs("key:", stdout);
+ while (p < l) {
+ if (sz % 16 == 0)
+ fputs("\n\t", stdout);
+ else if (sz % 8 == 0)
+ fputs(" ", stdout);
+ else
+ fputc(' ', stdout);
+ printf("%02x", *p++);
+ sz++;
+ }
+ fputc('\n', stdout);
+ }
+ }
+ }
+
+ doclose(&f);
+ return (0);
+}
+
+/* --- @cmd_extract@ --- */
+
+static int cmd_extract(int argc, char *argv[])
+{
+ key_file f;
+ key *k;
+ uint32 id;
+ int i;
+ int rc = 0;
+ FILE *fp;
+
+ if (argc < 3)
+ die(EXIT_FAILURE, "Usage: extract FILE KEYID...");
+ if (strcmp(argv[1], "-") == 0)
+ fp = stdout;
+ else if (!(fp = fopen(argv[1], "w"))) {
+ die(EXIT_FAILURE, "couldn't open `%s' for writing: %s",
+ argv[1], strerror(errno));
+ }
+
+ doopen(&f, KOPEN_WRITE);
+ for (i = 2; i < argc; i++) {
+ id = (uint32)strtoul(argv[i], 0, 16);
+ if ((k = key_byid(&f, id)) != 0)
+ key_extract(&f, k, fp);
+ else {
+ moan("keyid %lx not found", (unsigned long)id);
+ rc = 1;
+ }
+ }
+ doclose(&f);
+ return (rc);
+}
+
+/* --- @cmd_tidy@ --- */
+
+static int cmd_tidy(int argc, char *argv[])
+{
+ key_file f;
+ if (argc != 1)
+ die(EXIT_FAILURE, "usage: tidy");
+ doopen(&f, KOPEN_WRITE);
+ f.f |= KF_MODIFIED; /* Nasty hack */
+ doclose(&f);
+ return (0);
+}
+
+/* --- @cmd_merge@ --- */
+
+static int cmd_merge(int argc, char *argv[])
+{
+ key_file f;
+ FILE *fp;
+
+ if (argc != 2)
+ die(EXIT_FAILURE, "Usage: merge FILE");
+ if (strcmp(argv[1], "-") == 0)
+ fp = stdin;
+ else if (!(fp = fopen(argv[1], "r"))) {
+ die(EXIT_FAILURE, "couldn't open `%s' for writing: %s",
+ argv[1], strerror(errno));
+ }
+
+ doopen(&f, KOPEN_WRITE);
+ key_merge(&f, argv[1], fp);
+ doclose(&f);
+ return (0);
+}
+
+/*----- Main command table ------------------------------------------------*/
+
+static struct cmd {
+ const char *name;
+ int (*cmd)(int /*argc*/, char */*argv*/[]);
+ const char *help;
+} cmds[] = {
+ { "add", cmd_add,
+ "add [-b BITS] [-e EXPIRE] [-c COMMENT] TYPE [ATTR...]" },
+ { "expire", cmd_expire, "expire KEYID..." },
+ { "delete", cmd_delete, "delete KEYID..." },
+ { "setattr", cmd_setattr, "setattr KEYID ATTR..." },
+ { "comment", cmd_comment, "comment KEYID [COMMENT]" },
+ { "list", cmd_list, "list [-qv]" },
+ { "tidy", cmd_tidy, "tidy" },
+ { "extract", cmd_extract, "extract FILE KEYID..." },
+ { "merge", cmd_merge, "merge FILE" },
+ { 0, 0, 0 }
+};
+
+typedef struct cmd cmd;
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- Helpful GNUy functions --- */
+
+void usage(FILE *fp)
+{
+ fprintf(fp, "Usage: %s [-k file] command [args]\n", QUIS);
+}
+
+void version(FILE *fp)
+{
+ fprintf(fp, "%s, Catacomb version " VERSION "\n", QUIS);
+}
+
+void help(FILE *fp)
+{
+ cmd *c;
+ version(fp);
+ fputc('\n', fp);
+ usage(fp);
+ fputs("\n\
+Performs various simple key management operations. Command line options\n\
+recognized are:\n\
+\n\
+-h, --help Display this help text.\n\
+-v, --version Display version number.\n\
+-u, --usage Display short usage summary.\n\
+\n\
+-k, --keyring=FILE Read and write keys in FILE.\n\
+\n\
+The following commands are understood:\n\n",
+ fp);
+ for (c = cmds; c->name; c++)
+ fprintf(fp, "%s\n", c->help);
+}
+
+/* --- @main@ --- *
+ *
+ * Arguments: @int argc@ = number of command line arguments
+ * @char *argv[]@ = array of command line arguments
+ *
+ * Returns: Nonzero on failure.
+ *
+ * Use: Main program. Performs simple key management functions.
+ */
+
+int main(int argc, char *argv[])
+{
+ unsigned f = 0;
+
+ enum {
+ f_bogus = 1
+ };
+
+ /* --- Initialization --- */
+
+ ego(argv[0]);
+ sub_init();
+
+ /* --- Parse command line options --- */
+
+ for (;;) {
+ static struct option opt[] = {
+
+ /* --- Standard GNUy help options --- */
+
+ { "help", 0, 0, 'h' },
+ { "version", 0, 0, 'v' },
+ { "usage", 0, 0, 'u' },
+
+ /* --- Real live useful options --- */
+
+ { "keyring", OPTF_ARGREQ, 0, 'k' },
+
+ /* --- Magic terminator --- */
+
+ { 0, 0, 0, 0 }
+ };
+ int i = mdwopt(argc, argv, "+hvu k:", opt, 0, 0, 0);
+
+ if (i < 0)
+ break;
+ switch (i) {
+
+ /* --- GNU help options --- */
+ case 'h':
+ help(stdout);
+ exit(0);
+ case 'v':
+ version(stdout);
+ exit(0);
+ case 'u':
+ usage(stdout);
+ exit(0);
+
+ /* --- Real useful options --- */
+
+ case 'k':
+ keyfile = optarg;
+ break;
+
+ /* --- Bogosity --- */
+
+ default:
+ f |= f_bogus;
+ break;
+ }
+ }
+
+ /* --- Complain about excessive bogons --- */
+
+ if (f & f_bogus || optind == argc) {
+ usage(stderr);
+ exit(1);
+ }
+
+ /* --- Dispatch to appropriate command handler --- */
+
+ argc -= optind;
+ argv += optind;
+ optind = 0;
+
+ {
+ cmd *c, *chosen = 0;
+ size_t sz = strlen(argv[0]);
+
+ for (c = cmds; c->name; c++) {
+ if (strncmp(argv[0], c->name, sz) == 0) {
+ if (c->name[sz] == 0) {
+ chosen = c;
+ break;
+ } else if (chosen)
+ die(EXIT_FAILURE, "ambiguous command name `%s'", argv[0]);
+ else
+ chosen = c;
+ }
+ }
+ if (!chosen)
+ die(EXIT_FAILURE, "unknown command name `%s'", argv[0]);
+ return (chosen->cmd(argc, argv));
+ }
+}
+
+/*----- That's all, folks -------------------------------------------------*/
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: md4.c,v 1.1 1999/09/03 08:41:12 mdw Exp $
+ *
+ * The MD4 message digest function
+ *
+ * (c) 1999 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: md4.c,v $
+ * Revision 1.1 1999/09/03 08:41:12 mdw
+ * Initial import.
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <mLib/bits.h>
+
+#include "hash.h"
+#include "md4.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @md4_compress@ --- *
+ *
+ * Arguments: @md4_ctx *ctx@ = pointer to context block
+ * @const void *sbuf@ = pointer to buffer of appropriate size
+ *
+ * Returns: ---
+ *
+ * Use: RIPEMD-160 compression function.
+ */
+
+void md4_compress(md4_ctx *ctx, const void *sbuf)
+{
+ uint32 a, b, c, d;
+ uint32 buf[16];
+
+ /* --- Fetch the chaining variables --- */
+
+ a = ctx->a;
+ b = ctx->b;
+ c = ctx->c;
+ d = ctx->d;
+
+ /* --- Fetch the buffer contents --- */
+
+ {
+ int i;
+ const octet *p;
+
+ for (i = 0, p = sbuf; i < 16; i++, p += 4)
+ buf[i] = LOAD32_L(p);
+ }
+
+ /* --- Definitions for round functions --- */
+
+#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+
+#define T(w, x, y, z, i, r, k, f) do { \
+ uint32 _t = w + f(x, y, z) + buf[i] + k; \
+ w = ROL32(_t, r); \
+} while (0)
+
+#define FF(w, x, y, z, i, r) T(w, x, y, z, i, r, 0x00000000, F)
+#define GG(w, x, y, z, i, r) T(w, x, y, z, i, r, 0x5a827999, G)
+#define HH(w, x, y, z, i, r) T(w, x, y, z, i, r, 0x6ed9eba1, H)
+
+ /* --- The main compression function --- */
+
+ FF(a, b, c, d, 0, 3);
+ FF(d, a, b, c, 1, 7);
+ FF(c, d, a, b, 2, 11);
+ FF(b, c, d, a, 3, 19);
+ FF(a, b, c, d, 4, 3);
+ FF(d, a, b, c, 5, 7);
+ FF(c, d, a, b, 6, 11);
+ FF(b, c, d, a, 7, 19);
+ FF(a, b, c, d, 8, 3);
+ FF(d, a, b, c, 9, 7);
+ FF(c, d, a, b, 10, 11);
+ FF(b, c, d, a, 11, 19);
+ FF(a, b, c, d, 12, 3);
+ FF(d, a, b, c, 13, 7);
+ FF(c, d, a, b, 14, 11);
+ FF(b, c, d, a, 15, 19);
+
+ GG(a, b, c, d, 0, 3);
+ GG(d, a, b, c, 4, 5);
+ GG(c, d, a, b, 8, 9);
+ GG(b, c, d, a, 12, 13);
+ GG(a, b, c, d, 1, 3);
+ GG(d, a, b, c, 5, 5);
+ GG(c, d, a, b, 9, 9);
+ GG(b, c, d, a, 13, 13);
+ GG(a, b, c, d, 2, 3);
+ GG(d, a, b, c, 6, 5);
+ GG(c, d, a, b, 10, 9);
+ GG(b, c, d, a, 14, 13);
+ GG(a, b, c, d, 3, 3);
+ GG(d, a, b, c, 7, 5);
+ GG(c, d, a, b, 11, 9);
+ GG(b, c, d, a, 15, 13);
+
+ HH(a, b, c, d, 0, 3);
+ HH(d, a, b, c, 8, 9);
+ HH(c, d, a, b, 4, 11);
+ HH(b, c, d, a, 12, 15);
+ HH(a, b, c, d, 2, 3);
+ HH(d, a, b, c, 10, 9);
+ HH(c, d, a, b, 6, 11);
+ HH(b, c, d, a, 14, 15);
+ HH(a, b, c, d, 1, 3);
+ HH(d, a, b, c, 9, 9);
+ HH(c, d, a, b, 5, 11);
+ HH(b, c, d, a, 13, 15);
+ HH(a, b, c, d, 3, 3);
+ HH(d, a, b, c, 11, 9);
+ HH(c, d, a, b, 7, 11);
+ HH(b, c, d, a, 15, 15);
+
+ /* --- Update the chaining variables --- */
+
+ ctx->a += a;
+ ctx->b += b;
+ ctx->c += c;
+ ctx->d += d;
+}
+
+/* --- @md4_init@ --- *
+ *
+ * Arguments: @md4_ctx *ctx@ = pointer to context block to initialize
+ *
+ * Returns: ---
+ *
+ * Use: Initializes a context block ready for hashing.
+ */
+
+void md4_init(md4_ctx *ctx)
+{
+ ctx->a = 0x67452301;
+ ctx->b = 0xefcdab89;
+ ctx->c = 0x98badcfe;
+ ctx->d = 0x10325476;
+ ctx->off = 0;
+ ctx->count = 0;
+}
+
+/* --- @md4_set@ --- *
+ *
+ * Arguments: @md4_ctx *ctx@ = pointer to context block
+ * @const void *buf@ = pointer to state buffer
+ * @unsigned long count@ = current count of bytes processed
+ *
+ * Returns: ---
+ *
+ * Use: Initializes a context block from a given state. This is
+ * useful in cases where the initial hash state is meant to be
+ * secret, e.g., for NMAC and HMAC support.
+ */
+
+void md4_set(md4_ctx *ctx, const void *buf, unsigned long count)
+{
+ const octet *p = buf;
+ ctx->a = LOAD32_L(p + 0);
+ ctx->b = LOAD32_L(p + 4);
+ ctx->c = LOAD32_L(p + 8);
+ ctx->d = LOAD32_L(p + 12);
+ ctx->off = 0;
+ ctx->count = count;
+}
+
+/* --- @md4_hash@ --- *
+ *
+ * Arguments: @md4_ctx *ctx@ = pointer to context block
+ * @const void *buf@ = buffer of data to hash
+ * @size_t sz@ = size of buffer to hash
+ *
+ * Returns: ---
+ *
+ * Use: Hashes a buffer of data. The buffer may be of any size and
+ * alignment.
+ */
+
+void md4_hash(md4_ctx *ctx, const void *buf, size_t sz)
+{
+ HASH_BUFFER(MD4, md4, ctx, buf, sz);
+}
+
+/* --- @md4_done@ --- *
+ *
+ * Arguments: @md4_ctx *ctx@ = pointer to context block
+ * @void *hash@ = pointer to output buffer
+ *
+ * Returns: ---
+ *
+ * Use: Returns the hash of the data read so far.
+ */
+
+void md4_done(md4_ctx *ctx, void *hash)
+{
+ octet *p = hash;
+ HASH_MD5STRENGTH(MD4, md4, ctx);
+ STORE32_L(p + 0, ctx->a);
+ STORE32_L(p + 4, ctx->b);
+ STORE32_L(p + 8, ctx->c);
+ STORE32_L(p + 12, ctx->d);
+}
+
+/* --- @md4_state@ --- *
+ *
+ * Arguments: @md4_ctx *ctx@ = pointer to context
+ * @void *state@ = pointer to buffer for current state
+ *
+ * Returns: Number of bytes written to the hash function so far.
+ *
+ * Use: Returns the current state of the hash function such that
+ * it can be passed to @md4_set@.
+ */
+
+unsigned long md4_state(md4_ctx *ctx, void *state)
+{
+ octet *p = state;
+ STORE32_L(p + 0, ctx->a);
+ STORE32_L(p + 4, ctx->b);
+ STORE32_L(p + 8, ctx->c);
+ STORE32_L(p + 12, ctx->d);
+ return (ctx->count);
+}
+
+/* --- Test rig --- */
+
+HASH_TEST(MD4, md4)
+
+/*----- That's all, folks -------------------------------------------------*/
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: md4.h,v 1.1 1999/09/03 08:41:12 mdw Exp $
+ *
+ * The MD4 message digest function
+ *
+ * (c) 1998 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: md4.h,v $
+ * Revision 1.1 1999/09/03 08:41:12 mdw
+ * Initial import.
+ *
+ */
+
+/*----- Notes on the MD4 hash function ------------------------------------*
+ *
+ * MD4 was designed by Ron Rivest. It's now well and truly broken: not only
+ * have collisions been discovered, a slightly cut-down version has been
+ * shown to be non-preimage-resistant. On the other hand, MD4 is fast and
+ * makes a good heavy-duty checksum. Just don't rely on it being
+ * cryptographically strong, 'cos it ain't.
+ */
+
+#ifndef MD4_H
+#define MD4_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <mLib/bits.h>
+
+/*----- Magic numbers -----------------------------------------------------*/
+
+#define MD4_BUFSZ 64
+#define MD4_HASHSZ 16
+
+/*----- Data structures ---------------------------------------------------*/
+
+typedef struct md4_ctx {
+ uint32 a, b, c, d; /* Chaining variables */
+ unsigned long count; /* Byte count so far */
+ int off; /* Offset into buffer */
+ octet buf[MD4_BUFSZ]; /* Accumulation buffer */
+} md4_ctx;
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @md4_compress@ --- *
+ *
+ * Arguments: @md4_ctx *ctx@ = pointer to context block
+ * @const void *sbuf@ = pointer to buffer of appropriate size
+ *
+ * Returns: ---
+ *
+ * Use: MD4 compression function.
+ */
+
+extern void md4_compress(md4_ctx */*ctx*/, const void */*sbuf*/);
+
+/* --- @md4_init@ --- *
+ *
+ * Arguments: @md4_ctx *ctx@ = pointer to context block to initialize
+ *
+ * Returns: ---
+ *
+ * Use: Initializes a context block ready for hashing.
+ */
+
+extern void md4_init(md4_ctx */*ctx*/);
+
+/* --- @md4_set@ --- *
+ *
+ * Arguments: @md4_ctx *ctx@ = pointer to context block
+ * @const void *buf@ = pointer to state buffer
+ * @unsigned long count@ = current count of bytes processed
+ *
+ * Returns: ---
+ *
+ * Use: Initializes a context block from a given state. This is
+ * useful in cases where the initial hash state is meant to be
+ * secret, e.g., for NMAC and HMAC support.
+ */
+
+extern void md4_set(md4_ctx */*ctx*/, const void */*buf*/,
+ unsigned long /*count*/);
+
+/* --- @md4_hash@ --- *
+ *
+ * Arguments: @md4_ctx *ctx@ = pointer to context block
+ * @const void *buf@ = buffer of data to hash
+ * @size_t sz@ = size of buffer to hash
+ *
+ * Returns: ---
+ *
+ * Use: Hashes a buffer of data. The buffer may be of any size and
+ * alignment.
+ */
+
+extern void md4_hash(md4_ctx */*ctx*/, const void */*buf*/, size_t /*sz*/);
+
+/* --- @md4_done@ --- *
+ *
+ * Arguments: @md4_ctx *ctx@ = pointer to context block
+ * @void *hash@ = pointer to output buffer
+ *
+ * Returns: ---
+ *
+ * Use: Returns the hash of the data read so far.
+ */
+
+extern void md4_done(md4_ctx */*ctx*/, void */*hash*/);
+
+/* --- @md4_state@ --- *
+ *
+ * Arguments: @md4_ctx *ctx@ = pointer to context
+ * @void *state@ = pointer to buffer for current state
+ *
+ * Returns: Number of bytes written to the hash function so far.
+ *
+ * Use: Returns the current state of the hash function such that
+ * it can be passed to @md4_set@.
+ */
+
+extern unsigned long md4_state(md4_ctx */*ctx*/, void */*state*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: md5.c,v 1.1 1999/09/03 08:41:12 mdw Exp $
+ *
+ * The MD5 message digest function
+ *
+ * (c) 1998 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: md5.c,v $
+ * Revision 1.1 1999/09/03 08:41:12 mdw
+ * Initial import.
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <mLib/bits.h>
+
+#include "hash.h"
+#include "md5.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @md5_compress@ --- *
+ *
+ * Arguments: @md5_ctx *ctx@ = pointer to context block
+ * @const void *sbuf@ = pointer to buffer of appropriate size
+ *
+ * Returns: ---
+ *
+ * Use: MD5 compression function.
+ */
+
+void md5_compress(md5_ctx *ctx, const void *sbuf)
+{
+ uint32 a, b, c, d;
+ uint32 buf[16];
+
+ /* --- Fetch the chaining variables --- */
+
+ a = ctx->a;
+ b = ctx->b;
+ c = ctx->c;
+ d = ctx->d;
+
+ /* --- Fetch the buffer contents --- */
+
+ {
+ int i;
+ const octet *p;
+
+ for (i = 0, p = sbuf; i < 16; i++, p += 4)
+ buf[i] = LOAD32_L(p);
+ }
+
+ /* --- Definitions for round functions --- */
+
+#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | ~(z)))
+
+#define T(w, x, y, z, i, r, k, f) do { \
+ uint32 _t = w + f(x, y, z) + buf[i] + k; \
+ w = ROL32(_t, r) + x; \
+} while (0)
+
+#define FF(w, x, y, z, i, r, k) T(w, x, y, z, i, r, k, F)
+#define GG(w, x, y, z, i, r, k) T(w, x, y, z, i, r, k, G)
+#define HH(w, x, y, z, i, r, k) T(w, x, y, z, i, r, k, H)
+#define II(w, x, y, z, i, r, k) T(w, x, y, z, i, r, k, I)
+
+ /* --- The main compression function --- */
+
+ FF(a, b, c, d, 0, 7, 0xd76aa478);
+ FF(d, a, b, c, 1, 12, 0xe8c7b756);
+ FF(c, d, a, b, 2, 17, 0x242070db);
+ FF(b, c, d, a, 3, 22, 0xc1bdceee);
+ FF(a, b, c, d, 4, 7, 0xf57c0faf);
+ FF(d, a, b, c, 5, 12, 0x4787c62a);
+ FF(c, d, a, b, 6, 17, 0xa8304613);
+ FF(b, c, d, a, 7, 22, 0xfd469501);
+ FF(a, b, c, d, 8, 7, 0x698098d8);
+ FF(d, a, b, c, 9, 12, 0x8b44f7af);
+ FF(c, d, a, b, 10, 17, 0xffff5bb1);
+ FF(b, c, d, a, 11, 22, 0x895cd7be);
+ FF(a, b, c, d, 12, 7, 0x6b901122);
+ FF(d, a, b, c, 13, 12, 0xfd987193);
+ FF(c, d, a, b, 14, 17, 0xa679438e);
+ FF(b, c, d, a, 15, 22, 0x49b40821);
+
+ GG(a, b, c, d, 1, 5, 0xf61e2562);
+ GG(d, a, b, c, 6, 9, 0xc040b340);
+ GG(c, d, a, b, 11, 14, 0x265e5a51);
+ GG(b, c, d, a, 0, 20, 0xe9b6c7aa);
+ GG(a, b, c, d, 5, 5, 0xd62f105d);
+ GG(d, a, b, c, 10, 9, 0x02441453);
+ GG(c, d, a, b, 15, 14, 0xd8a1e681);
+ GG(b, c, d, a, 4, 20, 0xe7d3fbc8);
+ GG(a, b, c, d, 9, 5, 0x21e1cde6);
+ GG(d, a, b, c, 14, 9, 0xc33707d6);
+ GG(c, d, a, b, 3, 14, 0xf4d50d87);
+ GG(b, c, d, a, 8, 20, 0x455a14ed);
+ GG(a, b, c, d, 13, 5, 0xa9e3e905);
+ GG(d, a, b, c, 2, 9, 0xfcefa3f8);
+ GG(c, d, a, b, 7, 14, 0x676f02d9);
+ GG(b, c, d, a, 12, 20, 0x8d2a4c8a);
+
+ HH(a, b, c, d, 5, 4, 0xfffa3942);
+ HH(d, a, b, c, 8, 11, 0x8771f681);
+ HH(c, d, a, b, 11, 16, 0x6d9d6122);
+ HH(b, c, d, a, 14, 23, 0xfde5380c);
+ HH(a, b, c, d, 1, 4, 0xa4beea44);
+ HH(d, a, b, c, 4, 11, 0x4bdecfa9);
+ HH(c, d, a, b, 7, 16, 0xf6bb4b60);
+ HH(b, c, d, a, 10, 23, 0xbebfbc70);
+ HH(a, b, c, d, 13, 4, 0x289b7ec6);
+ HH(d, a, b, c, 0, 11, 0xeaa127fa);
+ HH(c, d, a, b, 3, 16, 0xd4ef3085);
+ HH(b, c, d, a, 6, 23, 0x04881d05);
+ HH(a, b, c, d, 9, 4, 0xd9d4d039);
+ HH(d, a, b, c, 12, 11, 0xe6db99e5);
+ HH(c, d, a, b, 15, 16, 0x1fa27cf8);
+ HH(b, c, d, a, 2, 23, 0xc4ac5665);
+
+ II(a, b, c, d, 0, 6, 0xf4292244);
+ II(d, a, b, c, 7, 10, 0x432aff97);
+ II(c, d, a, b, 14, 15, 0xab9423a7);
+ II(b, c, d, a, 5, 21, 0xfc93a039);
+ II(a, b, c, d, 12, 6, 0x655b59c3);
+ II(d, a, b, c, 3, 10, 0x8f0ccc92);
+ II(c, d, a, b, 10, 15, 0xffeff47d);
+ II(b, c, d, a, 1, 21, 0x85845dd1);
+ II(a, b, c, d, 8, 6, 0x6fa87e4f);
+ II(d, a, b, c, 15, 10, 0xfe2ce6e0);
+ II(c, d, a, b, 6, 15, 0xa3014314);
+ II(b, c, d, a, 13, 21, 0x4e0811a1);
+ II(a, b, c, d, 4, 6, 0xf7537e82);
+ II(d, a, b, c, 11, 10, 0xbd3af235);
+ II(c, d, a, b, 2, 15, 0x2ad7d2bb);
+ II(b, c, d, a, 9, 21, 0xeb86d391);
+
+ /* --- Update the chaining variables --- */
+
+ ctx->a += a;
+ ctx->b += b;
+ ctx->c += c;
+ ctx->d += d;
+}
+
+/* --- @md5_init@ --- *
+ *
+ * Arguments: @md5_ctx *ctx@ = pointer to context block to initialize
+ *
+ * Returns: ---
+ *
+ * Use: Initializes a context block ready for hashing.
+ */
+
+void md5_init(md5_ctx *ctx)
+{
+ ctx->a = 0x67452301;
+ ctx->b = 0xefcdab89;
+ ctx->c = 0x98badcfe;
+ ctx->d = 0x10325476;
+ ctx->off = 0;
+ ctx->count = 0;
+}
+
+/* --- @md5_set@ --- *
+ *
+ * Arguments: @md5_ctx *ctx@ = pointer to context block
+ * @const void *buf@ = pointer to state buffer
+ * @unsigned long count@ = current count of bytes processed
+ *
+ * Returns: ---
+ *
+ * Use: Initializes a context block from a given state. This is
+ * useful in cases where the initial hash state is meant to be
+ * secret, e.g., for NMAC and HMAC support.
+ */
+
+void md5_set(md5_ctx *ctx, const void *buf, unsigned long count)
+{
+ const octet *p = buf;
+ ctx->a = LOAD32_L(p + 0);
+ ctx->b = LOAD32_L(p + 4);
+ ctx->c = LOAD32_L(p + 8);
+ ctx->d = LOAD32_L(p + 12);
+ ctx->off = 0;
+ ctx->count = count;
+}
+
+/* --- @md5_hash@ --- *
+ *
+ * Arguments: @md5_ctx *ctx@ = pointer to context block
+ * @const void *buf@ = buffer of data to hash
+ * @size_t sz@ = size of buffer to hash
+ *
+ * Returns: ---
+ *
+ * Use: Hashes a buffer of data. The buffer may be of any size and
+ * alignment.
+ */
+
+void md5_hash(md5_ctx *ctx, const void *buf, size_t sz)
+{
+ HASH_BUFFER(MD5, md5, ctx, buf, sz);
+}
+
+/* --- @md5_done@ --- *
+ *
+ * Arguments: @md5_ctx *ctx@ = pointer to context block
+ * @void *hash@ = pointer to output buffer
+ *
+ * Returns: ---
+ *
+ * Use: Returns the hash of the data read so far.
+ */
+
+void md5_done(md5_ctx *ctx, void *hash)
+{
+ octet *p = hash;
+ HASH_MD5STRENGTH(MD5, md5, ctx);
+ STORE32_L(p + 0, ctx->a);
+ STORE32_L(p + 4, ctx->b);
+ STORE32_L(p + 8, ctx->c);
+ STORE32_L(p + 12, ctx->d);
+}
+
+/* --- @md5_state@ --- *
+ *
+ * Arguments: @md5_ctx *ctx@ = pointer to context
+ * @void *state@ = pointer to buffer for current state
+ *
+ * Returns: Number of bytes written to the hash function so far.
+ *
+ * Use: Returns the current state of the hash function such that
+ * it can be passed to @md5_set@.
+ */
+
+unsigned long md5_state(md5_ctx *ctx, void *state)
+{
+ octet *p = state;
+ STORE32_L(p + 0, ctx->a);
+ STORE32_L(p + 4, ctx->b);
+ STORE32_L(p + 8, ctx->c);
+ STORE32_L(p + 12, ctx->d);
+ return (ctx->count);
+}
+
+/* --- Test code --- */
+
+HASH_TEST(MD5, md5)
+
+/*----- That's all, folks -------------------------------------------------*/
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: md5.h,v 1.1 1999/09/03 08:41:12 mdw Exp $
+ *
+ * The MD5 message digest function
+ *
+ * (c) 1998 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: md5.h,v $
+ * Revision 1.1 1999/09/03 08:41:12 mdw
+ * Initial import.
+ *
+ */
+
+/*----- Notes on the MD5 hash function ------------------------------------*
+ *
+ * MD5 was designed by Ron Rivest. It was intended to be a more conservative
+ * design than the slightly earlier MD4, and indeed while MD4 has been pretty
+ * much demolished by subsequent cryptanalysis, MD5 is still standing
+ * shakily. It's provided here not because the author recommends its use but
+ * because it's a common standard, and is often handy in non-cryptographic
+ * applications. It's also still useful in constructions such as HMAC.
+ */
+
+#ifndef MD5_H
+#define MD5_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <mLib/bits.h>
+
+/*----- Magic numbers -----------------------------------------------------*/
+
+#define MD5_BUFSZ 64
+#define MD5_HASHSZ 16
+
+/*----- Data structures ---------------------------------------------------*/
+
+typedef struct md5_ctx {
+ uint32 a, b, c, d; /* Chaining variables */
+ unsigned long count; /* Byte count so far */
+ int off; /* Offset into buffer */
+ octet buf[MD5_BUFSZ]; /* Accumulation buffer */
+} md5_ctx;
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @md5_compress@ --- *
+ *
+ * Arguments: @md5_ctx *ctx@ = pointer to context block
+ * @const void *sbuf@ = pointer to buffer of appropriate size
+ *
+ * Returns: ---
+ *
+ * Use: MD5 compression function.
+ */
+
+extern void md5_compress(md5_ctx */*ctx*/, const void */*sbuf*/);
+
+/* --- @md5_init@ --- *
+ *
+ * Arguments: @md5_ctx *ctx@ = pointer to context block to initialize
+ *
+ * Returns: ---
+ *
+ * Use: Initializes a context block ready for hashing.
+ */
+
+extern void md5_init(md5_ctx */*ctx*/);
+
+/* --- @md5_set@ --- *
+ *
+ * Arguments: @md5_ctx *ctx@ = pointer to context block
+ * @const void *buf@ = pointer to state buffer
+ * @unsigned long count@ = current count of bytes processed
+ *
+ * Returns: ---
+ *
+ * Use: Initializes a context block from a given state. This is
+ * useful in cases where the initial hash state is meant to be
+ * secret, e.g., for NMAC and HMAC support.
+ */
+
+extern void md5_set(md5_ctx */*ctx*/, const void */*buf*/,
+ unsigned long /*count*/);
+
+/* --- @md5_hash@ --- *
+ *
+ * Arguments: @md5_ctx *ctx@ = pointer to context block
+ * @const void *buf@ = buffer of data to hash
+ * @size_t sz@ = size of buffer to hash
+ *
+ * Returns: ---
+ *
+ * Use: Hashes a buffer of data. The buffer may be of any size and
+ * alignment.
+ */
+
+extern void md5_hash(md5_ctx */*ctx*/, const void */*buf*/, size_t /*sz*/);
+
+/* --- @md5_done@ --- *
+ *
+ * Arguments: @md5_ctx *ctx@ = pointer to context block
+ * @void *hash@ = pointer to output buffer
+ *
+ * Returns: ---
+ *
+ * Use: Returns the hash of the data read so far.
+ */
+
+extern void md5_done(md5_ctx */*ctx*/, void */*hash*/);
+
+/* --- @md5_state@ --- *
+ *
+ * Arguments: @md5_ctx *ctx@ = pointer to context
+ * @void *state@ = pointer to buffer for current state
+ *
+ * Returns: Number of bytes written to the hash function so far.
+ *
+ * Use: Returns the current state of the hash function such that
+ * it can be passed to @md5_set@.
+ */
+
+extern unsigned long md5_state(md5_ctx */*ctx*/, void */*state*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: mp.c,v 1.1 1999/09/03 08:41:12 mdw Exp $
+ *
+ * Multiprecision arithmetic
+ *
+ * (c) 1998 Mark Wooding
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: mp.c,v $
+ * Revision 1.1 1999/09/03 08:41:12 mdw
+ * Initial import.
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <limits.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "alloc.c"
+#include "bits.h"
+#include "exc.h"
+
+/*----- Important types ---------------------------------------------------*/
+
+/* For now... */
+
+#ifndef TEST_RIG
+
+typedef unsigned short mpw;
+#define MPW_BITS 16
+#define MPW_MAX 0xffffu
+typedef unsigned int mpd;
+#define MPD_BITS 32
+#define MPD_MAX 0xffffffffu
+
+#else
+
+typedef unsigned long mpw;
+static unsigned mpw_bits;
+static mpw mpw_max;
+typedef unsigned long mpd;
+
+#define MPW_BITS mpw_bits
+#define MPW_MAX mpw_max
+
+#endif
+
+/*----- Data structures ---------------------------------------------------*/
+
+/*----- Some basic values which are important -----------------------------*/
+
+static mpw mp__v[] = { 1, 2, 3, 4, 5, 10 };
+const mp mp_std[] = {
+ { 0, 0, 0, 0 }, /* 0 */
+ { mp__v + 0, 0, 0, 1 }, /* 1 */
+ { mp__v + 1, 0, 0, 1 }, /* 2 */
+ { mp__v + 2, 0, 0, 1 }, /* 3 */
+ { mp__v + 3, 0, 0, 1 }, /* 4 */
+ { mp__v + 4, 0, 0, 1 }, /* 5 */
+ { mp__v + 5, 0, 0, 1 }, /* 10 */
+ { mp__v + 0, MPF_SIGN, 0, 1 } /* -1 */
+};
+
+/*----- Memory management -------------------------------------------------*/
+
+/* --- @mp_create@ --- *
+ *
+ * Arguments @mp *x@ = pointer to MP head
+ *
+ * Returns: ---
+ *
+ * Use: Initializes an MP ready for use. The initial value is zero.
+ */
+
+void mp_create(mp *x)
+{
+ x->v = 0;
+ x->f = 0;
+ x->sz = 0;
+ x->len = 0;
+}
+
+/* --- @mp_destroy@ --- *
+ *
+ * Arguments: @mp *x@ = pointer to MP head
+ *
+ * Returns: ---
+ *
+ * Use: Releases the memory used by an MP.
+ */
+
+void mp_destroy(mp *x) { MP_DESTROY(x); }
+
+/* --- @mp_resize@ --- *
+ *
+ * Arguments: @mp *x@ = pointer to MP head
+ * @size_t sz@ = size required (in words)
+ *
+ * Returns: ---
+ *
+ * Use: Resizes the MP so that its word vector has space for
+ * exactly @sz@ words.
+ */
+
+void mp_resize(mp *x, size_t sz)
+{
+ if (sz == 0)
+ mp_destroy(x);
+ else {
+ size_t min = sz > x->sz ? x->sz : sz;
+ mpw *v = xmalloc(sz * sizeof(mpw));
+ if (min)
+ memcpy(v, x->v, min * sizeof(mpw));
+ MP_BURN(x);
+ if (x->v)
+ free(x->v);
+ if (sz > min)
+ memset(v + min, 0, (sz - min) * sizeof(mpw));
+ x->v = v;
+ x->sz = sz;
+ }
+}
+
+/* --- @mp_norm@ --- *
+ *
+ * Arguments: @mp *x@ = pointer to MP head
+ *
+ * Returns: ---
+ *
+ * Use: `Normalizes' an MP. Fixes the @len@ field so that it's
+ * correct. Assumes that @len@ is either already correct or
+ * too large.
+ */
+
+void mp_norm(mp *x) { MP_NORM(x); }
+
+/* --- @mp_dump@ --- *
+ *
+ * Arguments: @mp *x@ = pointer to MP head
+ * @FILE *fp@ = pointer to stream to write on
+ *
+ * Returns: ---
+ *
+ * Use: Dumps an MP to a stream.
+ */
+
+void mp_dump(mp *x, FILE *fp)
+{
+ if (x->v) {
+ mpw *v = x->v, *vl = v + x->len;
+ while (v < vl) {
+ fprintf(fp, "%lx", (unsigned long)*v++);
+ if (v < vl) fputc('-', fp);
+ }
+ } else
+ fputs("<0>", fp);
+}
+
+/* --- @mp_copy@ --- *
+ *
+ * Arguments: @mp *d@ = pointer to MP head for destination
+ * @const mp *s@ = pointer to MP head for source
+ *
+ * Returns: ---
+ *
+ * Use: Copies an MP.
+ */
+
+void mp_copy(mp *d, const mp *s)
+{
+ if (d == s) {
+ MP_NORM(d);
+ return;
+ }
+ MP_BURN(d);
+ MP_ENSURE(d, s->len);
+ memcpy(d->v, s->v, s->len * sizeof(mpw));
+ if (d->f & MPF_BURN && d->sz > s->len)
+ memset(d->v + s->len, 0, (d->sz - s->len) * sizeof(mpw));
+ d->len = s->len;
+ d->f = s->f;
+ MP_NORM(d);
+}
+
+/* --- @mp_bits@ --- *
+ *
+ * Arguments: @mp *x@ = pointer to MP head
+ *
+ * Returns: Length of the number in bits.
+ *
+ * Use: Calculates the number of bits required to represent a number.
+ * The number must be normalized.
+ */
+
+unsigned long mp_bits(mp *x)
+{
+ if (!x->v)
+ return (0);
+ else {
+ unsigned long bits = MPW_BITS * (x->len - 1);
+ mpw w = x->v[x->len - 1];
+ while (w) {
+ bits++;
+ w >>= 1;
+ }
+ return (bits);
+ }
+}
+
+/* --- @mp_octets@ --- *
+ *
+ * Arguments: @mp *x@ = pointer to MP head
+ *
+ * Returns: Length of number in octets.
+ *
+ * Use: Calculates the number of octets required to represent a
+ * number. The number must be normalized.
+ */
+
+size_t mp_octets(mp *x)
+{
+ return ((mp_bits(x) + 7) & 7);
+}
+
+/*----- Loading and storing as binary data --------------------------------*/
+
+/* --- @mp_storel@ --- *
+ *
+ * Arguments: @mp *x@ = pointer to MP head
+ * @octet *p@ = pointer to octet array
+ * @size_t sz@ = size of octet array
+ *
+ * Returns: ---
+ *
+ * Use: Stores an MP in an octet array, least significant octet
+ * first. High-end octets are silently discarded if there
+ * isn't enough space for them.
+ */
+
+void mp_storel(mp *x, octet *p, size_t sz)
+{
+ mpw *v = x->v, *vl = x->v + x->len;
+ mpw n, w = 0;
+ octet *q = p + sz;
+ unsigned bits = 0;
+
+ while (p < q) {
+ if (bits < 8) {
+ n = (v >= vl) ? 0 : *v++;
+ *p++ = (w | n << bits) & MASK8;
+ w = n >> (8 - bits);
+ bits += MPW_BITS - 8;
+ } else {
+ *p++ = w & MASK8;
+ w >>= 8;
+ bits -= 8;
+ }
+ }
+}
+
+/* --- @mp_loadl@ --- *
+ *
+ * Arguments: @mp *x@ = pointer to MP head
+ * @const octet *p@ = pointer to octet array
+ * @size_t sz@ = size of octet array
+ *
+ * Returns: ---
+ *
+ * Use: Loads an MP in an octet array, least significant octet
+ * first.
+ */
+
+void mp_loadl(mp *x, const octet *p, size_t sz)
+{
+ mpw *v;
+ mpw w = 0;
+ unsigned n;
+ const octet *q = p + sz;
+ unsigned bits = 0;
+
+ MP_BURN(x);
+ MP_ENSURE(x, ((sz * 8 + MPW_BITS - 1) * MPW_BITS) / MPW_BITS);
+ v = x->v;
+
+ while (p < q) {
+ n = *p++ & MASK8;
+ w |= n << bits;
+ bits += 8;
+ if (bits >= MPW_BITS) {
+ *v++ = w & MPW_MAX;
+ w = n >> (MPW_BITS - bits + 8);
+ bits -= MPW_BITS;
+ }
+ }
+ *v++ = w;
+ x->len = v - x->v;
+ x->f = 0;
+ MP_NORM(x);
+}
+
+/* --- @mp_storeb@ --- *
+ *
+ * Arguments: @mp *x@ = pointer to MP head
+ * @octet *p@ = pointer to octet array
+ * @size_t sz@ = size of octet array
+ *
+ * Returns: ---
+ *
+ * Use: Stores an MP in an octet array, most significant octet
+ * first. High-end octets are silently discarded if there
+ * isn't enough space for them.
+ */
+
+void mp_storeb(mp *x, octet *p, size_t sz)
+{
+ mpw *v = x->v, *vl = x->v + x->len;
+ mpw n, w = 0;
+ octet *q = p + sz;
+ unsigned bits = 0;
+
+ while (q > p) {
+ if (bits < 8) {
+ n = (v >= vl) ? 0 : *v++;
+ *--q = (w | n << bits) & MASK8;
+ w = n >> (8 - bits);
+ bits += MPW_BITS - 8;
+ } else {
+ *--q= w & MASK8;
+ w >>= 8;
+ bits -= 8;
+ }
+ }
+}
+
+/* --- @mp_loadb@ --- *
+ *
+ * Arguments: @mp *x@ = pointer to MP head
+ * @const octet *p@ = pointer to octet array
+ * @size_t sz@ = size of octet array
+ *
+ * Returns: ---
+ *
+ * Use: Loads an MP in an octet array, most significant octet
+ * first.
+ */
+
+void mp_loadb(mp *x, const octet *p, size_t sz)
+{
+ mpw *v;
+ mpw w = 0;
+ unsigned n;
+ const octet *q = p + sz;
+ unsigned bits = 0;
+
+ MP_BURN(x);
+ MP_ENSURE(x, ((sz * 8 + MPW_BITS - 1) * MPW_BITS) / MPW_BITS);
+ v = x->v;
+
+ while (q > p) {
+ n = *--q & MASK8;
+ w |= n << bits;
+ bits += 8;
+ if (bits >= MPW_BITS) {
+ *v++ = w & MPW_MAX;
+ w = n >> (MPW_BITS - bits + 8);
+ bits -= MPW_BITS;
+ }
+ }
+ *v++ = w;
+ x->len = v - x->v;
+ x->f = 0;
+ MP_NORM(x);
+}
+
+/*----- Iterating through bits --------------------------------------------*/
+
+/* --- @mp_mkbitscan@ --- *
+ *
+ * Arguments: @mp_bitscan *sc@ = pointer to bitscan object
+ * @const mp *x@ = pointer to MP head
+ *
+ * Returns: ---
+ *
+ * Use: Initializes a bitscan object.
+ */
+
+void mp_mkbitscan(mp_bitscan *sc, const mp *x)
+{
+ sc->x = x;
+ sc->bits = 0;
+ sc->i = 0;
+}
+
+/* --- @mp_bstep@ --- *
+ *
+ * Arguments: @mp_bitscan *sc@ = pointer to bitscanner object
+ *
+ * Returns: Nonzero if there is another bit to read.
+ *
+ * Use: Steps on to the next bit, and tells the caller whether one
+ * exists.
+ */
+
+int mp_bstep(mp_bitscan *sc)
+{
+ if (sc->bits) {
+ sc->w >>= 1;
+ sc->bits--;
+ return (1);
+ }
+ if (sc->i >= sc->x->len)
+ return (0);
+ sc->w = sc->x->v[sc->i++];
+ sc->bits = MPW_BITS - 1;
+ return (1);
+}
+
+/* --- @mp_bit@ --- *
+ *
+ * Arguments: @const mp_bitscan *sc@ = pointer to bitscanner
+ *
+ * Returns: Current bit value.
+ *
+ * Use: Returns the value of the current bit.
+ */
+
+int mp_bit(const mp_bitscan *sc) { return (MP_BIT(sc)); }
+
+/*----- Shifting ----------------------------------------------------------*/
+
+/* --- @mp_lsl@ --- *
+ *
+ * Arguments: @mp *d@ = pointer to MP head of destination
+ * @const mp *x@ = pointer to MP head of source
+ * @size_t n@ = number of bits to shift
+ *
+ * Returns: ---
+ *
+ * Use: Shifts a number left by a given number of bit positions.
+ */
+
+void mp_lsl(mp *d, const mp *x, size_t n)
+{
+ size_t nw = n / MPW_BITS;
+ unsigned nb = n % MPW_BITS;
+ unsigned nr = MPW_BITS - nb;
+ size_t req;
+
+ /* --- Trivial special case --- */
+
+ if (n == 0 || mp_ucmp(x, MP_ZERO) == 0) {
+ mp_copy(d, x);
+ goto copied;
+ }
+
+ /* --- Decide on the about of memory needed in the destination --- */
+
+ req = x->len + nw;
+ if (nb && (x->v[x->len - 1] >> nr) != 0)
+ req++;
+ if (d != x)
+ MP_BURN(d);
+ MP_ENSURE(d, req);
+
+ /* --- Handle single bit shifting --- */
+
+ if (n == 1) {
+ mpw *v = d->v;
+ const mpw *vx = x->v;
+ const mpw *vl;
+ mpw w = 0;
+
+ vl = vx + x->len;
+ while (vx < vl) {
+ mpw t = *vx++;
+ *v++ = ((t << 1) | w) & MPW_MAX;
+ w = t >> (MPW_BITS - 1);
+ }
+ if (v < d->v + req)
+ *v++ = w & MPW_MAX;
+ goto done;
+ }
+
+ /* --- Handle shifts by a multiple of the word size --- *
+ *
+ * This would be easy, except that C is irritating. Shifting an integer
+ * by an amount equal to the type's width yields undefined behaviour;
+ * in particular, under Intel it's a no-op.
+ */
+
+ if (!nb) {
+ mpw *v = d->v;
+ const mpw *vx = x->v;
+ memmove(v + nw, vx, (req - nw) * sizeof(mpw));
+ memset(v, 0, nw * sizeof(mpw));
+ goto done;
+ }
+
+ /* --- Now do the difficult version --- */
+
+ {
+ mpw *v = d->v + req;
+ const mpw *vx = x->v + x->len;
+ const mpw *vl;
+ mpw w = *--vx;
+
+ /* --- First shift the data over --- */
+
+ if (req > x->len + nw)
+ *--v = w >> nr;
+ vl = x->v;
+ while (vx > vl) {
+ mpw t = *--vx;
+ *--v = ((w << nb) | (t >> nr)) & MPW_MAX;
+ w = t;
+ }
+
+ /* --- Deal with tail-end data --- */
+
+ vl = d->v;
+ if (v > vl) {
+ *--v = w << nb;
+ while (v > vl)
+ *--v = 0;
+ }
+ }
+
+ /* --- Common end code --- */
+
+done:
+ d->len = req;
+ d->f = x->f;
+copied:
+ MP_NORM(d);
+}
+
+/* --- @mp_lsr@ --- *
+ *
+ * Arguments: @mp *d@ = pointer to MP head of destination
+ * @const mp *x@ = pointer to MP head of source
+ * @size_t n@ = number of bits to shift
+ *
+ * Returns: ---
+ *
+ * Use: Shifts a number right by a given number of bit positions.
+ */
+
+void mp_lsr(mp *d, const mp *x, size_t n)
+{
+ size_t nw = n / MPW_BITS;
+ unsigned nb = n % MPW_BITS;
+ unsigned nr = MPW_BITS - nb;
+ size_t req;
+
+ /* --- Trivial special case --- */
+
+ if (n == 0 || mp_ucmp(x, MP_ZERO) == 0) {
+ mp_copy(d, x);
+ goto copied;
+ }
+
+ /* --- Decide on the about of memory needed in the destination --- */
+
+ req = x->len - nw;
+ if ((x->v[x->len - 1] >> nb) == 0)
+ req--;
+ if (d != x)
+ MP_BURN(d);
+ MP_ENSURE(d, req);
+
+ /* --- Handle single bit shifting --- */
+
+ if (n == 1) {
+ mpw *v = d->v + req;
+ const mpw *vx = x->v + x->len;
+ const mpw *vl;
+ mpw w = *--vx;
+
+ if (req == x->len)
+ *--v = (w >> 1) & MPW_MAX;
+ vl = x->v;
+ while (vx > vl) {
+ mpw t = *--vx;
+ *--v = (w << (MPW_BITS - 1) | (t >> 1)) & MPW_MAX;
+ w = t;
+ }
+ goto done;
+ }
+
+ /* --- Handle shifts by a multiple of the word size --- *
+ *
+ * This would be easy, except that C is irritating. Shifting an integer
+ * by an amount equal to the type's width yields undefined behaviour;
+ * in particular, under Intel it's a no-op.
+ */
+
+ if (!nb) {
+ mpw *v = d->v;
+ const mpw *vx = x->v;
+ memmove(v, vx + nw, (x->len - nw) * sizeof(mpw));
+ goto done;
+ }
+
+ /* --- Now do the difficult version --- */
+
+ {
+ mpw *v = d->v;
+ const mpw *vx = x->v + nw;
+ const mpw *vl;
+ mpw w = *vx++;
+
+ /* --- First shift the data over --- */
+
+ vl = x->v + x->len;
+ while (vx < vl) {
+ mpw t = *vx++;
+ *v++ = ((w >> nb) | (t << nr)) & MPW_MAX;
+ w = t;
+ }
+ if (req == x->len - nw) {
+ *v++ = (w >> nb) & MPW_MAX;
+ }
+ }
+
+ /* --- Common end code --- */
+
+done:
+ d->len = req;
+ d->f = x->f;
+copied:
+ MP_NORM(d);
+}
+
+/*----- Adding and subtracting --------------------------------------------*/
+
+/* --- @mp_uadd@ --- *
+ *
+ * Arguments: @const mp *d@ = pointers to MP head of destination
+ * @const mp *x, *y@ = pointers to MP heads of operands
+ *
+ * Returns: ---
+ *
+ * Use: Performs unsigned MP addition.
+ */
+
+void mp_uadd(mp *d, const mp *x, const mp *y)
+{
+ mpd c;
+ mpw *v;
+ const mpw *vx, *vy;
+ const mpw *vxl, *vyl;
+
+ /* --- Some trivial initialization --- */
+
+ if (d != x && d != y)
+ MP_BURN(d);
+ MP_ENSURE(d, (x->len > y->len ? x->len : y->len) + 1);
+ vx = x->v; vxl = vx + x->len;
+ vy = y->v; vyl = vy + y->len;
+ v = d->v;
+ c = 0;
+
+ /* --- Start on the work --- */
+
+ while (vx < vxl || vy < vyl) {
+ if (vx < vxl) c += *vx++;
+ if (vy < vyl) c += *vy++;
+ *v++ = c & MPW_MAX;
+ c >>= MPW_BITS;
+ }
+ if (c)
+ *v++ = c & MPW_MAX;
+
+ /* --- Tidy up --- */
+
+ d->len = v - d->v;
+ d->f = 0;
+ if (x->f & MPF_BURN || y->f & MPF_BURN)
+ MP_PARANOID(d);
+ MP_NORM(d);
+}
+
+/* --- @mp_usub@ --- *
+ *
+ * Arguments: @const mp *d@ = pointers to MP head of destination
+ * @const mp *x, *y@ = pointers to MP heads of operands
+ *
+ * Returns: ---
+ *
+ * Use: Performs unsigned MP subtraction.
+ */
+
+void mp_usub(mp *d, const mp *x, const mp *y)
+{
+ mpd c;
+ mpw *v;
+ const mpw *vx, *vy;
+ const mpw *vxl, *vyl;
+
+ /* --- Some trivial initialization --- */
+
+ if (d != x && d != y)
+ MP_BURN(d);
+ MP_ENSURE(d, x->len);
+ vx = x->v; vxl = vx + x->len;
+ vy = y->v; vyl = vy + y->len;
+ v = d->v;
+ c = 0;
+
+ /* --- Start on the work --- */
+
+ while (vx < vxl) {
+ c += *vx++;
+ if (vy < vyl) c -= *vy++;
+ *v++ = c & MPW_MAX;
+ if (c & ~MPW_MAX)
+ c = ~0ul;
+ else
+ c = 0;
+ }
+
+ /* --- Tidy up --- */
+
+ d->len = v - d->v;
+ d->f = 0;
+ if (x->f & MPF_BURN || y->f & MPF_BURN)
+ MP_PARANOID(d);
+ MP_NORM(d);
+}
+
+/* --- @mp_ucmp@ --- *
+ *
+ * Arguments: @const mp *x, *y@ = pointers to MP heads of operands
+ *
+ * Returns: Less than, equal to, or greater than zero.
+ *
+ * Use: Performs unsigned MP comparison.
+ */
+
+int mp_ucmp(const mp *x, const mp *y)
+{
+ int i;
+ mpw a, b;
+
+ /* --- Decide which to examine --- */
+
+ if (x->len > y->len)
+ i = x->len;
+ else
+ i = y->len;
+
+ /* --- Loop through the data --- */
+
+ while (i > 0) {
+ i--;
+ a = (i < x->len ? x->v[i] : 0);
+ b = (i < y->len ? y->v[i] : 0);
+ if (a < b)
+ return (-1);
+ else if (a > b)
+ return (1);
+ }
+
+ /* --- Finished --- */
+
+ return (0);
+}
+
+/*----- Multiplying and dividing ------------------------------------------*/
+
+/* --- @mp_umul@ --- *
+ *
+ * Arguments: @mp *d@ = pointer to MP head of destination
+ * @const mp *x, *y@ = pointes to MP heads of operands
+ *
+ * Returns: ---
+ *
+ * Use: Performs unsigned MP multiplication.
+ */
+
+void mp_umul(mp *d, const mp *x, const mp *y)
+{
+ mpd c, f;
+ mpw *v = 0, *vbase;
+ const mpw *vx, *vy;
+ const mpw *vxl, *vyl;
+
+ /* --- Check for special cases --- */
+
+ if (mp_ucmp(x, MP_ZERO) == 0 || mp_ucmp(y, MP_ZERO) == 0) {
+ mp_copy(d, MP_ZERO);
+ return;
+ }
+
+ /* --- Some trivial initialization --- */
+
+ MP_BURN(d);
+ MP_ENSURE(d, x->len + y->len);
+ vxl = x->v + x->len;
+ vyl = y->v + y->len;
+ vbase = d->v;
+ memset(v, 0, (x->len + y->len) * sizeof(mpw));
+
+ /* --- Main loop --- */
+
+ for (vx = x->v; vx < vxl; vx++) {
+ c = 0;
+ f = *vx;
+ v = vbase++;
+ for (vy = y->v; vy < vyl; vy++) {
+ c += *v + f * *vy;
+ *v++ = c & MPW_MAX;
+ c >>= MPW_BITS;
+ }
+ *v++ = c & MPW_MAX;
+ }
+
+ /* --- Tidying up --- */
+
+ d->len = v - d->v;
+ d->f = 0;
+ if (x->f & MPF_BURN || y->f & MPF_BURN)
+ MP_PARANOID(d);
+ MP_NORM(d);
+}
+
+/* --- @mp_udiv@ --- *
+ *
+ * Arguments: @mp *q, *r@ = pointers to MP heads for quotient, remainder
+ * @const mp *x, *y@ = pointers to MP heads for operands
+ *
+ * Returns: ---
+ *
+ * Use: Performs unsigned MP division.
+ */
+
+void mp_udiv(mp *q, mp *r, const mp *x, const mp *y)
+{
+ size_t n = x->len, t = y->len;
+ const mpw *vy, *ovy;
+ mpw *vx, *vq, *vxl, *va, *vb;
+ mpw yt, ytt;
+ mpd yd;
+ mp nx = MP_INIT, ny = MP_INIT, nq = MP_INIT;
+ mp tt = MP_INIT;
+ unsigned int shift;
+
+ /* --- Fiddle with some pointers --- */
+
+ if (!r)
+ r = &nx;
+ if (!q)
+ q = &nq;
+
+ /* --- Find the top word in @y@ --- */
+
+ vy = y->v;
+ for (;;) {
+ if (!t)
+ THROW(EXC_FAIL, "mp_udiv detected divide-by-zero");
+ if ((yt = vy[t - 1]) != 0)
+ break;
+ t--;
+ }
+
+ /* --- Check for a zero dividend --- */
+
+ if (mp_ucmp(x, MP_ZERO)) {
+ if (q) mp_copy(q, MP_ZERO);
+ if (r) mp_copy(r, MP_ZERO);
+ return;
+ }
+
+ /* --- Test for some other trivial cases --- */
+
+ {
+ int i = mp_ucmp(x, y);
+ if (i < 0) {
+ if (r) mp_copy(r, x);
+ if (q) mp_copy(q, MP_ZERO);
+ return;
+ } else if (i == 0) {
+ if (r) mp_copy(r, MP_ZERO);
+ if (q) mp_copy(q, MP_ONE);
+ return;
+ }
+ }
+
+ /* --- Normalize the divisor --- *
+ *
+ * Cheat. The original algorithm wants two-word values at least, so I just
+ * shift everything up by a word if necessary.
+ */
+
+ shift = 0;
+ while (yt < MPW_MAX / 2) {
+ yt <<= 1;
+ shift++;
+ }
+ if (t <= 1)
+ shift += MPW_BITS;
+ mp_lsl(r, x, shift);
+ mp_lsl(&ny, y, shift);
+
+ n = r->len;
+ t = ny.len;
+ ytt = ny.v[t - 2];
+ yd = ((mpd)yt << MPW_BITS) | (mpd)ytt;
+
+ /* --- Initialize the quotient --- */
+
+ MP_ENSURE(q, n - t + 1);
+ vq = q->v + n - t;
+ memset(vq, 0, (n - t) * sizeof(mpw));
+
+ /* --- Shift the divisor up to match the dividend --- */
+
+ mp_lsl(&ny, (n - t) * MPW_BITS);
+ ovy = ny.v;
+
+ /* --- Get the most significant quotient digit --- *
+ *
+ * Because of the normalization, this should only happen once.
+ */
+
+ while (mp_ucmp(x, y) >= 0) {
+ mp_usub(x, x, y);
+ (*vq)++;
+ }
+
+ /* --- Now do the main loop --- */
+
+ vx = x->v + n;
+ vxl = x->v + t;
+
+ while (vx > vxl) {
+ mpw xi, xii, xiii;
+ mpd qi;
+ mpd xd, yhi, ylo;
+
+ /* --- Fetch the top words from @x@ --- */
+
+ vx--;
+ xi = vx[0];
+ xii = vx[-1];
+ xiii = vx[-2];
+ xd = ((mpd)xi << MPW_BITS) | (mpd)xii;
+
+ /* --- Get an approximation for @qi@ --- */
+
+ if (xi == yt)
+ qi = MPW_MAX;
+ else
+ qi = xd / yt;
+
+ /* --- Work out how close the approximation is --- *
+ *
+ * This is more than a little ugly.
+ */
+
+ yhi = (mpd)yt * qi;
+ ylo = (mpd)ytt * qi;
+ yhi += ylo >> MPW_BITS;
+ ylo &= MPW_MAX;
+
+ /* --- Now fix the approximation --- *
+ *
+ * Again, the normalization helps; this is never done more than twice.
+ */
+
+ while (!(yhi <= xd && ylo <= xiii)) {
+ qi--;
+ yhi -= yt;
+ if (ylo < ytt)
+ yhi--;
+ ylo = (ylo - ytt) & MPW_MAX;
+ }
+
+ /* --- Subtract off a goodly big chunk --- */
+
+
+}
+
+/*----- Test rig ----------------------------------------------------------*/
+
+#ifdef TEST_RIG
+
+#include <stdio.h>
+#include "dstr.h"
+#include "testrig.h"
+
+/* --- Loading and storing numbers --- *
+ *
+ * The most reliable way I can think of for doing this is to convert both
+ * numbers (the MP and the original hexgorp) into binary text, and compare.
+ * This ought to be reliable, and it's sufficiently different from what the
+ * actual load and store routines are doing not to have any common bugs.
+ */
+
+static void mpbindump(const mp *x, char *p)
+{
+ mp_bitscan sc;
+ for (mp_mkbitscan(&sc, x); mp_bstep(&sc); )
+ *p++ = '0' + MP_BIT(&sc);
+ *p++ = 0;
+}
+
+static void bindumpl(const octet *q, size_t sz, char *p)
+{
+ unsigned w;
+ int bits = 0;
+
+ while (sz) {
+ w = *q++;
+ for (bits = 8; bits > 0; bits--) {
+ *p++ = '0' + (w & 1);
+ w >>= 1;
+ }
+ sz--;
+ }
+ *p++ = 0;
+}
+
+static void bindumpb(const octet *q, size_t sz, char *p)
+{
+ unsigned w;
+ int bits = 0;
+
+ q += sz;
+ while (sz) {
+ w = *--q;
+ for (bits = 8; bits > 0; bits--) {
+ *p++ = '0' + (w & 1);
+ w >>= 1;
+ }
+ sz--;
+ }
+ *p++ = 0;
+}
+
+static int bincmp(const char *p, const char *q)
+{
+ for (;;) {
+ if (!*p && !*q)
+ return (0);
+ else if (!*p && *q == '0')
+ q++;
+ else if (*p == '0' && !*q)
+ p++;
+ else if (*p == *q)
+ p++, q++;
+ else
+ return (-1);
+ }
+}
+
+static int lscheck(const char *reason, int w, dstr *d, mp *x,
+ const char *bufa, const char *bufb)
+{
+ if (bincmp(bufa, bufb)) {
+ printf("\nmismatch in %s (width = %i):\n"
+ "\tvalue = ", reason, w);
+ type_hex.dump(d, stdout);
+ printf("\n\tmp = ");
+ mp_dump(x, stdout);
+ printf("\n\texpected = %s\n"
+ "\tcalculated = %s\n",
+ bufb, bufa);
+ return (1);
+ }
+ return (0);
+}
+
+static int loadstore(dstr *d)
+{
+ octet *p = (octet *)d[0].buf;
+ size_t sz = d[0].len;
+ char bufa[1024], bufb[1024];
+ octet bufc[64];
+ mp x;
+ int i;
+ int ok = 1;
+
+ mp_wmax = 0x7ful;
+ for (i = 8; ok && i <= 32; i++) {
+ mpw_bits = i;
+ mpw_max = (mp_wmax << 1) + 1;
+
+ mp_create(&x); mp_loadl(&x, p, sz);
+ mpbindump(&x, bufa); bindumpl(p, sz, bufb);
+ if (lscheck("mp_loadl", i, d, &x, bufa, bufb)) ok = 0;
+ mp_storeb(&x, bufc, sizeof(bufc));
+ bindumpb(bufc, sizeof(bufc), bufa);
+ if (lscheck("mp_storeb", i, d, &x, bufa, bufb)) ok = 0;
+ mp_destroy(&x);
+
+ mp_create(&x); mp_loadb(&x, p, sz);
+ mpbindump(&x, bufa); bindumpb(p, sz, bufb);
+ if (lscheck("mp_loadb", i, d, &x, bufa, bufb)) ok = 0;
+ mp_storel(&x, bufc, sizeof(bufc));
+ bindumpl(bufc, sizeof(bufc), bufa);
+ if (lscheck("mp_storel", i, d, &x, bufa, bufb)) ok = 0;
+ mp_destroy(&x);
+ }
+
+ mpw_max = 0xffff;
+ mpw_bits = 16;
+ return (ok);
+}
+
+/* --- Comparison test --- */
+
+static int compare(dstr *d)
+{
+ mp x, y;
+ int r, s;
+ int ok = 1;
+
+ mp_create(&x); mp_create(&y);
+ mp_loadb(&x, (octet *)d[0].buf, d[0].len);
+ mp_loadb(&y, (octet *)d[1].buf, d[1].len);
+ r = *(int *)d[2].buf;
+ s = mp_ucmp(&x, &y);
+
+ if (r != s) {
+ ok = 0;
+ printf("\nfailed compare:"
+ "\n\tx = ");
+ type_hex.dump(&d[0], stdout);
+ printf("\n\ty = ");
+ type_hex.dump(&d[1], stdout);
+ printf("\n\texpected %i; found %i\n", r, s);
+ }
+
+ return (ok);
+}
+
+/* --- Addition and subtraction test --- */
+
+static int addsub(dstr *d)
+{
+ mp t, x, y, z;
+ int ok = 1;
+
+ mp_create(&t); mp_create(&x); mp_create(&y); mp_create(&z);
+ mp_loadb(&x, (octet *)d[0].buf, d[0].len);
+ mp_loadb(&y, (octet *)d[1].buf, d[1].len);
+ mp_loadb(&z, (octet *)d[2].buf, d[2].len);
+
+ mp_uadd(&t, &x, &y);
+ if (mp_ucmp(&t, &z)) {
+ ok = 0;
+ printf("\nfailed add:");
+ printf("\n\tx = "); type_hex.dump(&d[0], stdout);
+ printf("\n\ty = "); type_hex.dump(&d[1], stdout);
+ printf("\n\tz = "); type_hex.dump(&d[2], stdout);
+ fputc('\n', stdout);
+ }
+
+ mp_usub(&t, &z, &x);
+ if (mp_ucmp(&t, &y)) {
+ ok = 0;
+ printf("\nfailed subtract:");
+ printf("\n\tz = "); type_hex.dump(&d[2], stdout);
+ printf("\n\tx = "); type_hex.dump(&d[0], stdout);
+ printf("\n\ty = "); type_hex.dump(&d[1], stdout);
+ fputc('\n', stdout);
+ }
+
+ return (ok);
+}
+
+/* --- Shifting --- */
+
+static int shift(dstr *d)
+{
+ char bufa[1024], bufb[1024];
+ mp x, y;
+ int n = *(int *)d[1].buf;
+ char *p;
+ int i;
+ int ok = 1;
+
+ mp_create(&x);
+ mp_create(&y);
+
+ mp_loadb(&x, (octet *)d[0].buf, d[0].len);
+ p = bufa;
+ for (i = 0; i < n; i++)
+ *p++ = '0';
+ mpbindump(&x, p);
+
+ mp_lsl(&y, &x, n);
+ mpbindump(&y, bufb);
+ if (lscheck("lsl", n, d, &x, bufb, bufa))
+ ok = 0;
+
+ mp_lsr(&y, &x, n);
+ mpbindump(&y, bufb);
+ if (lscheck("lsr", n, d, &x, bufb, bufa + 2 * n))
+ ok = 0;
+
+ return (ok);
+}
+
+/* --- Test driver stub --- */
+
+static test_chunk mp__defs[] = {
+ { "mp-loadstore", loadstore, { &type_hex, 0 } },
+ { "mp-cmp", compare, { &type_hex, &type_hex, &type_int, 0 } },
+ { "mp-addsub", addsub, { &type_hex, &type_hex, &type_hex, 0 } },
+ { "mp-shift", shift, { &type_hex, &type_int, 0 } },
+ { 0, 0, { 0 } }
+};
+
+int main(int argc, char *argv[])
+{
+ test_run(argc, argv, mp__defs, SRCDIR"/tests/mp");
+ return (0);
+}
+
+#endif
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#endif
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: mp.h,v 1.1 1999/09/03 08:41:12 mdw Exp $
+ *
+ * Multiprecision arithmetic
+ *
+ * (c) 1999 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: mp.h,v $
+ * Revision 1.1 1999/09/03 08:41:12 mdw
+ * Initial import.
+ *
+ */
+
+#ifndef MP_H
+#define MP_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef MPTYPES_H
+# include "mptypes.h"
+#endif
+
+#ifndef MPX_H
+# include "mpx.h"
+#endif
+
+#ifndef MPSCAN_H
+# include "mpscan.h"
+#endif
+
+/*----- Data structures ---------------------------------------------------*/
+
+typedef struct mp {
+ mpw *v; /* Vector of words */
+ unsigned f; /* Various flags */
+ size_t sz; /* Size allocated to word vector */
+ size_t len; /* Length of current word vector */
+} mp;
+
+enum {
+ MPF_SIGN = 1, /* Sign bit */
+ MPF_BURN = 2 /* Burn word vector after use */
+};
+
+typedef struct mp_bitscan {
+ const mp *x; /* Pointer to target MP */
+ size_t i; /* Index into MP vector */
+ mpw w; /* Current value being examined */
+ unsigned bits; /* Number of bits left in @w@ */
+} mp_bitscan;
+
+/*----- External variables ------------------------------------------------*/
+
+extern mp mp_std;
+
+#define MP_ZERO (mp_std + 0)
+#define MP_ONE (mp_std + 1)
+#define MP_TWO (mp_std + 2)
+#define MP_THREE (mp_std + 3)
+#define MP_FOUR (mp_std + 4)
+#define MP_FIVE (mp_std + 5)
+#define MP_TEN (mp_std + 6)
+#define MP_MONE (mp_std + 7)
+
+/*----- Memory allocation and low-level fiddling --------------------------*/
+
+/* --- @mp_create@ --- *
+ *
+ * Arguments @mp *x@ = pointer to MP head
+ *
+ * Returns: ---
+ *
+ * Use: Initializes an MP ready for use. The initial value is zero.
+ */
+
+#define MP_INIT { 0, 0, 0, 0 }
+
+extern void mp_create(mp */*x*/);
+
+/* --- @MP_BURN@ --- *
+ *
+ * Arguments: @x@ = pointer to MP head
+ *
+ * Use: Burns the contents of the MP, if it contains sensitive data.
+ */
+
+#define MP_BURN(x) do { \
+ mp *_y = (x) \
+ if (_y->v && _y->f & mpf_burn) { \
+ memset(_y->v, 0, _y->sz * sizeof(mpw)); \
+ _y->f &= ~MPF_BURN; \
+ } \
+} while (0)
+
+/* --- @mp_free@ --- *
+ *
+ * Arguments: @mp *x@ = pointer to MP head
+ *
+ * Returns: ---
+ *
+ * Use: Releases the memory used by an MP.
+ */
+
+#define MP_DESTROY(x) do { \
+ mp *_x = (x); \
+ MP_BURN(_x); \
+ if (_x->v) \
+ free(_x->v); \
+ _x->v = 0; \
+ _x->f = 0; \
+ _x->sz = 0; \
+ _x->len = 0; \
+} while (0)
+
+extern void mp_free(mp */*x*/);
+
+/* --- @MP_ENSURE@ --- *
+ *
+ * Arguments: @x@ = pointer to MP head
+ * @len@ = length required (in words)
+ *
+ * Use: Ensures that the MP has enough memory to store a @len@-word
+ * value.
+ */
+
+#define MP_ENSURE(x, len) do { \
+ mp *_x = (x); \
+ size_t _len = (len); \
+ if (_x->sz < _len) \
+ mp_resize(_x, _len); \
+} while (0)
+
+/* --- @mp_resize@ --- *
+ *
+ * Arguments: @mp *x@ = pointer to MP head
+ * @size_t sz@ = size required (in words)
+ *
+ * Returns: ---
+ *
+ * Use: Resizes the MP so that its word vector has space for
+ * exactly @sz@ words.
+ */
+
+extern void mp_resize(mp */*x*/, size_t /*sz*/);
+
+/* --- @mp_norm@ --- *
+ *
+ * Arguments: @mp *x@ = pointer to MP head
+ *
+ * Returns: ---
+ *
+ * Use: `Normalizes' an MP. Fixes the @len@ field so that it's
+ * correct. Assumes that @len@ is either already correct or
+ * too large.
+ */
+
+#define MP_NORM(x) do { \
+ mp *_y = (x); \
+ MPX_LEN(_y->len, _y->v, _y->len); \
+} while (0)
+
+extern void mp_norm(mp */*x*/);
+
+/* --- @mp_dump@ --- *
+ *
+ * Arguments: @mp *x@ = pointer to MP head
+ * @FILE *fp@ = pointer to stream to write on
+ *
+ * Returns: ---
+ *
+ * Use: Dumps an MP to a stream.
+ */
+
+extern void mp_dump(mp */*x*/, FILE */*fp*/);
+
+/* --- @MP_PARANOID@ --- *
+ *
+ * Arguments: @x@ = pointer to MP head
+ *
+ * Use: Marks the MP as containing sensitive data which should be
+ * burnt when no longer required.
+ */
+
+#define MP_PARANOID(x) ((x)->f |= MPF_BURN)
+
+/* --- @mp_copy@ --- *
+ *
+ * Arguments: @mp *d@ = pointer to MP head for destination
+ * @const mp *s@ = pointer to MP head for source
+ *
+ * Returns: ---
+ *
+ * Use: Copies an MP.
+ */
+
+extern void mp_copy(mp */*d*/, const mp */*s*/);
+
+/* --- @mp_bits@ --- *
+ *
+ * Arguments: @mp *x@ = pointer to MP head
+ *
+ * Returns: Length of the number in bits.
+ *
+ * Use: Calculates the number of bits required to represent a number.
+ * The number must be normalized.
+ */
+
+unsigned long mp_bits(mp */*x*/);
+
+/* --- @mp_octets@ --- *
+ *
+ * Arguments: @mp *x@ = pointer to MP head
+ *
+ * Returns: Length of number in octets.
+ *
+ * Use: Calculates the number of octets required to represent a
+ * number. The number must be normalized.
+ */
+
+extern size_t mp_octets(mp */*x*/);
+
+/*----- Loading and storing as binary data --------------------------------*/
+
+/* --- @mp_storel@ --- *
+ *
+ * Arguments: @mp *x@ = pointer to MP head
+ * @octet *p@ = pointer to octet array
+ * @size_t sz@ = size of octet array
+ *
+ * Returns: ---
+ *
+ * Use: Stores an MP in an octet array, least significant octet
+ * first. High-end octets are silently discarded if there
+ * isn't enough space for them.
+ */
+
+extern void mp_storel(mp */*x*/, octet */*p*/, size_t /*sz*/);
+
+/* --- @mp_loadl@ --- *
+ *
+ * Arguments: @mp *x@ = pointer to MP head
+ * @const octet *p@ = pointer to octet array
+ * @size_t sz@ = size of octet array
+ *
+ * Returns: ---
+ *
+ * Use: Loads an MP in an octet array, least significant octet
+ * first.
+ */
+
+extern void mp_loadl(mp */*x*/, const octet */*p*/, size_t /*sz*/);
+
+/* --- @mp_storeb@ --- *
+ *
+ * Arguments: @mp *x@ = pointer to MP head
+ * @octet *p@ = pointer to octet array
+ * @size_t sz@ = size of octet array
+ *
+ * Returns: ---
+ *
+ * Use: Stores an MP in an octet array, most significant octet
+ * first. High-end octets are silently discarded if there
+ * isn't enough space for them.
+ */
+
+extern void mp_storeb(mp */*x*/, octet */*p*/, size_t /*sz*/);
+
+/* --- @mp_loadb@ --- *
+ *
+ * Arguments: @mp *x@ = pointer to MP head
+ * @const octet *p@ = pointer to octet array
+ * @size_t sz@ = size of octet array
+ *
+ * Returns: ---
+ *
+ * Use: Loads an MP in an octet array, most significant octet
+ * first.
+ */
+
+extern void mp_loadb(mp */*x*/, const octet */*p*/, size_t /*sz*/);
+
+/*----- Iterating through bits --------------------------------------------*/
+
+/* --- @mp_mkbitscan@ --- *
+ *
+ * Arguments: @mp_bitscan *sc@ = pointer to bitscan object
+ * @const mp *x@ = pointer to MP head
+ *
+ * Returns: ---
+ *
+ * Use: Initializes a bitscan object.
+ */
+
+extern void mp_mkbitscan(mp_bitscan */*sc*/, const mp */*x*/);
+
+/* --- @mp_bstep@ --- *
+ *
+ * Arguments: @mp_bitscan *sc@ = pointer to bitscanner object
+ *
+ * Returns: Nonzero if there is another bit to read.
+ *
+ * Use: Steps on to the next bit, and tells the caller whether one
+ * exists.
+ */
+
+extern int mp_bstep(mp_bitscan */*sc*/);
+
+/* --- @mp_bit@ --- *
+ *
+ * Arguments: @const mp_bitscan *sc@ = pointer to bitscanner
+ *
+ * Returns: Current bit value.
+ *
+ * Use: Returns the value of the current bit.
+ */
+
+#define MP_BIT(sc) ((sc)->w & 1)
+
+extern int mp_bit(const mp_bitscan */*sc*/);
+
+/*----- Shifting ----------------------------------------------------------*/
+
+/* --- @mp_lsl@ --- *
+ *
+ * Arguments: @mp *d@ = pointer to MP head of destination
+ * @const mp *x@ = pointer to MP head of source
+ * @size_t n@ = number of bits to shift
+ *
+ * Returns: ---
+ *
+ * Use: Shifts a number left by a given number of bit positions.
+ */
+
+extern void mp_lsl(mp */*d*/, const mp */*x*/, size_t /*n*/);
+
+/* --- @mp_lsr@ --- *
+ *
+ * Arguments: @mp *d@ = pointer to MP head of destination
+ * @const mp *x@ = pointer to MP head of source
+ * @size_t n@ = number of bits to shift
+ *
+ * Returns: ---
+ *
+ * Use: Shifts a number right by a given number of bit positions.
+ */
+
+extern void mp_lsr(mp */*d*/, const mp */*x*/, size_t /*n*/);
+
+/*----- Unsigned arithmetic -----------------------------------------------*/
+
+/* --- @mp_uadd@ --- *
+ *
+ * Arguments: @const mp *d@ = pointers to MP head of destination
+ * @const mp *x, *y@ = pointers to MP heads of operands
+ *
+ * Returns: ---
+ *
+ * Use: Performs unsigned MP addition.
+ */
+
+extern void mp_uadd(mp */*d*/, const mp */*x*/, const mp */*y*/);
+
+/* --- @mp_usub@ --- *
+ *
+ * Arguments: @const mp *d@ = pointers to MP head of destination
+ * @const mp *x, *y@ = pointers to MP heads of operands
+ *
+ * Returns: ---
+ *
+ * Use: Performs unsigned MP subtraction.
+ */
+
+extern void mp_usub(mp */*d*/, const mp */*x*/, const mp */*y*/);
+
+/* --- @mp_ucmp@ --- *
+ *
+ * Arguments: @const mp *x, *y@ = pointers to MP heads of operands
+ *
+ * Returns: Less than, equal to, or greater than zero.
+ *
+ * Use: Performs unsigned MP comparison.
+ */
+
+#define MP_UCMP(x, op, y) (mp_ucmp((x), (y)) op 0)
+
+extern int mp_ucmp(const mp */*x*/, const mp */*y*/);
+
+/* --- @mp_umul@ --- *
+ *
+ * Arguments: @mp *d@ = pointer to MP head of destination
+ * @const mp *x, *y@ = pointes to MP heads of operands
+ *
+ * Returns: ---
+ *
+ * Use: Performs unsigned MP multiplication.
+ */
+
+extern void mp_umul(mp */*d*/, const mp */*x*/, const mp */*y*/);
+
+/* --- @mp_udiv@ --- *
+ *
+ * Arguments: @mp *q, *r@ = pointers to MP heads for quotient, remainder
+ * @const mp *x, *y@ = pointers to MP heads for operands
+ *
+ * Returns: ---
+ *
+ * Use: Performs unsigned MP division.
+ */
+
+extern void mp_udiv(mp */*q*/, mp */*r*/, const mp */*x*/, const mp */*y*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: mpscan.c,v 1.1 1999/09/03 08:41:12 mdw Exp $
+ *
+ * Sequential bit scan of multiprecision integers
+ *
+ * (c) 1999 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: mpscan.c,v $
+ * Revision 1.1 1999/09/03 08:41:12 mdw
+ * Initial import.
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+/*----- Data structures ---------------------------------------------------*/
+
+/*----- Static variables --------------------------------------------------*/
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @mpscan_initx@ --- *
+ *
+ * Arguments: @mpscan *m@ = pointer to bitscanner structure
+ * @const mpw *v@ = vector of words to scan
+ * @size_t len@ = length of vector in words
+ *
+ * Returns: ---
+ *
+ * Use: Initializes a bitscanner from a low-level vector-and-length
+ * representation of an integer. Initially no bit is ready; you
+ * must call @mpscan_step@ before anything useful will come
+ * out.
+ */
+
+void mpscan_initx(mpscan *m, const mpw *v, size_t len)
+{
+ MPSCAN_INITX(m, v, len);
+}
+
+/* --- @mpscan_step@ --- *
+ *
+ * Arguments: @mpscan *m@ = pointer to bitscanner
+ *
+ * Returns: Nonzero if there is another bit to read.
+ *
+ * Use: Steps on to the next bit in the integer. The macro version
+ * evaluates its argument multiple times.
+ */
+
+int mpscan_step(mpscan *m) { return (MPSCAN_STEP(m)); }
+
+/* --- @mpscan_bit@ --- *
+ *
+ * Arguments: @const mpscan *m@ = pointer to bitscanner
+ *
+ * Returns: The value of the current bit.
+ *
+ * Use: Reads the value of the current bit looked at by a
+ * bitscanner.
+ */
+
+int mpscan_bit(const mpscan *m) { return (MPSCAN_BIT(m)); }
+
+/*----- That's all, folks -------------------------------------------------*/
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: mpscan.h,v 1.1 1999/09/03 08:41:12 mdw Exp $
+ *
+ * Sequential bit scan of multiprecision integers
+ *
+ * (c) 1999 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: mpscan.h,v $
+ * Revision 1.1 1999/09/03 08:41:12 mdw
+ * Initial import.
+ *
+ */
+
+#ifndef MPSCAN_H
+#define MPSCAN_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#ifndef MPTYPES_H
+# include "mptypes.h"
+#endif
+
+/*----- Data structures ---------------------------------------------------*/
+
+typedef struct mpscan {
+ const mpw *v; /* Vector of words to scan */
+ mpw w; /* Current word to scan */
+ int bits; /* Number of bits left in @w@ */
+ size_t len; /* Length of the vector in words */
+} mpscan;
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @mpscan_initx@ --- *
+ *
+ * Arguments: @mpscan *m@ = pointer to bitscanner structure
+ * @const mpw *v@ = vector of words to scan
+ * @size_t len@ = length of vector in words
+ *
+ * Returns: ---
+ *
+ * Use: Initializes a bitscanner from a low-level vector-and-length
+ * representation of an integer. Initially no bit is ready; you
+ * must call @mpscan_step@ before anything useful will come
+ * out.
+ */
+
+#define MPSCAN_INITX(m_, v_, len_) do { \
+ mpscan *_m = (m_); \
+ _m->v = (v_); \
+ _m->len = (len_); \
+ _m->bits = 0; \
+} while (0)
+
+extern void mpscan_initx(mpscan */*m*/, const mpw */*v*/, size_t /*len*/);
+
+/* --- @mpscan_step@ --- *
+ *
+ * Arguments: @mpscan *m@ = pointer to bitscanner
+ *
+ * Returns: Nonzero if there is another bit to read.
+ *
+ * Use: Steps on to the next bit in the integer. The macro version
+ * evaluates its argument multiple times.
+ */
+
+#define MPSCAN_STEP(m) \
+ ((m)->bits ? ((m)->w >>= 1, \
+ (m)->bits--, 1) : \
+ (m)->len ? ((m)->len--, \
+ (m)->w = *(m)->v++, \
+ (m)->bits = MP_WBITS - 1, 1) : \
+ 0)
+
+extern int mpscan_step(mpscan */*m*/);
+
+/* --- @mpscan_bit@ --- *
+ *
+ * Arguments: @const mpscan *m@ = pointer to bitscanner
+ *
+ * Returns: The value of the current bit.
+ *
+ * Use: Reads the value of the current bit looked at by a
+ * bitscanner.
+ */
+
+#define MPSCAN_BIT(m) ((m)->w & 1)
+
+extern int mpscan_bit(const mpscan */*m*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: mptypes.h,v 1.1 1999/09/03 08:41:12 mdw Exp $
+ *
+ * Types for multiprecision arithmetic
+ *
+ * (c) 1999 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: mptypes.h,v $
+ * Revision 1.1 1999/09/03 08:41:12 mdw
+ * Initial import.
+ *
+ */
+
+#ifndef MPTYPES_H
+#define MPTYPES_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <limits.h>
+#include <stddef.h>
+
+#include <mLib/bits.h>
+
+/*----- Important types ---------------------------------------------------*/
+
+/* --- Choose word and doubleword types --- *
+ *
+ * The types I need, and their properties, are as follows:
+ *
+ * * @mpw@ is the radix in which all the arithmetic is actually performed.
+ * It must be an unsigned type that is efficient on the host's hardware.
+ * @MPW_MAX@ is the largest value of type @mpw@ I'll use. (Although
+ * there may be bigger values available, I'll not use them.) @MPW_BITS@
+ * is the number of bits required to represent @MPW_MAX@.
+ *
+ * * @mpd@ must be twice as large as @mpw@: I must be able to multiply any
+ * two @mpw@ values and end up with an @mpd@ as the result. @MPD_MAX@ is
+ * the largest value of type @mpd@ I'll use, and @MPD_BITS@ is the number
+ * of bits required to represent it.
+ *
+ * The algorithm used to choose these types is:
+ *
+ * * Try to use @unsigned int@ as @mpw@ and @unsigned long@ as @mpd@. If
+ * @unsigned long@ looks to small to do this, try to use @unsigned long
+ * long@, if it exists.
+ *
+ * * If that's not good enough, then fall back to @unsigned short@ as @mpw@
+ * and choose one of @unsigned int@, @unsigned long@ or @unsigned long
+ * long@ (in decreasing order of preference) as @mpd@.
+ *
+ * * If that doesn't work either, choose @unsigned int@ as both, and use
+ * half its width only as @mpw@.
+ */
+
+#ifndef MP_TEST
+
+/* --- Hack for GCC until it catches up with C9X --- *
+ *
+ * GCC uses bogus names for the @long long@ minimum and maximum values in its
+ * <limits.h> file. This little hack makes the proper portable C9X names
+ * work as well.
+ */
+
+#if defined(ULONG_LONG_MAX) && !defined(ULLONG_MAX)
+# define LLONG_MIN LONG_LONG_MIN
+# define LLONG_MAX LONG_LONG_MAX
+# define ULLONG_MAX ULONG_LONG_MAX
+#endif
+
+/* --- Decide on the actual types to use --- *
+ *
+ * The division trick here makes sure that one type is twice another without
+ * the risk of overflowing the arithmetic provided by the preprocessor.
+ */
+
+#if ULONG_MAX / UINT_MAX >= UINT_MAX
+ typedef unsigned int mpw;
+ typedef unsigned long mpd;
+# define MPW_MAX UINT_MAX
+#elif ULLONG_MAX / UINT_MAX >= UINT_MAX
+ typedef unsigned int mpw;
+ typedef unsigned long long mpd;
+# define MPW_MAX UINT_MAX
+#elif UINT_MAX / USHRT_MAX >= USHRT_MAX
+ typedef unsigned short mpw;
+ typedef unsigned int mpd;
+# define MPW_MAX USHRT_MAX
+#elif ULONG_MAX / USHRT_MAX >= USHRT_MAX
+ typedef unsigned short mpw;
+ typedef unsigned long mpd;
+# define MPW_MAX USHRT_MAX
+#elif ULLONG_MAX / USHRT_MAX >= USHRT_MAX
+ typedef unsigned short mpw;
+ typedef unsigned long long mpd;
+# define MPW_MAX USHRT_MAX
+#else
+ typedef unsigned int mpw;
+ typedef unsigned int mpd;
+# define MPD_MAX UINT_MAX
+#endif
+
+/* --- Fix a value for @MPD_MAX@ --- *
+ *
+ * This will then be the target for finding the bit widths and things.
+ */
+
+#ifdef MPW_MAX
+# define MPD_MAX ((MPW_MAX + 1) * MPW_MAX + MW_WMAX)
+#endif
+
+/* --- Find the width of @MPD_MAX@ in bits --- *
+ *
+ * It must be at least 16 bits wide, because the smallest type I bother to
+ * try is @unsigned short@. I only bother testing for up to 64 bits, and in
+ * power-of-two chunks, because I don't care about efficiency on more bizarre
+ * systems.
+ */
+
+#if MPD_MAX <= 0xfffffffff
+# if MPD_MAX == 0xffffffff
+# define MPD_BITS 32
+# elif MPD_MAX >= 0x0fffffff
+# define MPD_BITS 28
+# elif MPD_MAX >= 0x00ffffff
+# define MPD_BITS 24
+# elif MPD_MAX >= 0x000fffff
+# define MPD_BITS 20
+# elif MPD_MAX >= 0x0000ffff
+# define MPD_BITS 16
+# else
+# error "Abject failure deciding on type `mpw'"
+#else
+# if MPD_MAX / 0xffffffff < 0xffffffff
+# define MPD_BITS 32
+# else
+# define MPD_BITS 64 /* Slightly dodgy */
+#endif
+
+/* --- Now sort out the other magical values --- */
+
+#undef MPD_MAX
+#undef MPW_MAX
+
+#define MPW_BITS (MPD_BITS / 2)
+#define MPD_MAX (((1 << (MPD_BITS - 1)) - 1) * 2 + 1)
+#define MPW_MAX ((1 << MPW_BITS) - 1)
+
+#endif
+
+/*----- Macros for coercion and masking -----------------------------------*/
+
+/* --- @MPW@ --- *
+ *
+ * Arguments: @x@ = an unsigned value
+ *
+ * Use: Expands to the value of @x@ masked and typecast to a
+ * multiprecision integer word.
+ */
+
+#define MPW(x) ((mpw)((x) & MPW_MAX))
+
+/* --- @MPWS@ --- *
+ *
+ * Arguments: @n@ = number of words
+ *
+ * Use: Expands to the number of bytes occupied by a given number of
+ * words.
+ */
+
+#define MPWS(n) ((n) * sizeof(mpw))
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: mpx.c,v 1.1 1999/09/03 08:41:12 mdw Exp $
+ *
+ * Low-level multiprecision arithmetic
+ *
+ * (c) 1999 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: mpx.c,v $
+ * Revision 1.1 1999/09/03 08:41:12 mdw
+ * Initial import.
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <mLib/bits.h>
+
+#include "mptypes.h"
+#include "mpx.h"
+
+/*----- Loading and storing -----------------------------------------------*/
+
+/* --- @mpx_storel@ --- *
+ *
+ * Arguments: @const mpw *v, *vl@ = base and limit of source vector
+ * @octet *p@ = pointer to octet array
+ * @size_t sz@ = size of octet array
+ *
+ * Returns: ---
+ *
+ * Use: Stores an MP in an octet array, least significant octet
+ * first. High-end octets are silently discarded if there
+ * isn't enough space for them.
+ */
+
+void mpx_storel(const mpw *v, const mpw *vl, octet *p, size_t sz)
+{
+ mpw n, w = 0;
+ octet *q = p + sz;
+ unsigned bits = 0;
+
+ while (p < q) {
+ if (bits < 8) {
+ if (v >= vl) {
+ *p++ = U8(w);
+ break;
+ }
+ n = *v++;
+ *p++ = U8(w | n << bits);
+ w = n >> (8 - bits);
+ bits += MPW_BITS - 8;
+ } else {
+ *p++ = U8(w);
+ w >>= 8;
+ bits -= 8;
+ }
+ }
+ memset(p, 0, q - p);
+}
+
+/* --- @mpx_loadl@ --- *
+ *
+ * Arguments: @mpw *v, *vl@ = base and limit of destination vector
+ * @const octet *p@ = pointer to octet array
+ * @size_t sz@ = size of octet array
+ *
+ * Returns: ---
+ *
+ * Use: Loads an MP in an octet array, least significant octet
+ * first. High-end octets are ignored if there isn't enough
+ * space for them.
+ */
+
+void mpx_loadl(mpw *v, const mpw *vl, const octet *p, size_t sz)
+{
+ unsigned n;
+ const octet *q = p + sz;
+ unsigned bits = 0;
+
+ if (v >= vl)
+ return;
+ while (p < q) {
+ n = U8(*p++);
+ w |= n << bits;
+ bits += 8;
+ if (bits >= MPW_BITS) {
+ *v++ = MPW(w);
+ w = n >> (MPW_BITS - bits + 8);
+ bits -= MPW_BITS;
+ if (v >= vl)
+ return;
+ }
+ }
+ *v++ = w;
+ MPX_ZERO(v, vl);
+}
+
+/* --- @mpx_storeb@ --- *
+ *
+ * Arguments: @const mpw *v, *vl@ = base and limit of source vector
+ * @octet *p@ = pointer to octet array
+ * @size_t sz@ = size of octet array
+ *
+ * Returns: ---
+ *
+ * Use: Stores an MP in an octet array, most significant octet
+ * first. High-end octets are silently discarded if there
+ * isn't enough space for them.
+ */
+
+void mpx_storeb(const mpw *v, const mpw *vl, octet *p, size_t sz);
+{
+ mpw n, w = 0;
+ octet *q = p + sz;
+ unsigned bits = 0;
+
+ while (q > p) {
+ if (bits < 8) {
+ if (v >= vl) {
+ *--q = U8(w);
+ break;
+ }
+ n = *v++;
+ *--q = U8(w | n << bits);
+ w = n >> (8 - bits);
+ bits += MPW_BITS - 8;
+ } else {
+ *--q = U8(w);
+ w >>= 8;
+ bits -= 8;
+ }
+ }
+ memset(p, 0, q - p);
+}
+
+/* --- @mpx_loadb@ --- *
+ *
+ * Arguments: @mpw *v, *vl@ = base and limit of destination vector
+ * @const octet *p@ = pointer to octet array
+ * @size_t sz@ = size of octet array
+ *
+ * Returns: ---
+ *
+ * Use: Loads an MP in an octet array, most significant octet
+ * first. High-end octets are ignored if there isn't enough
+ * space for them.
+ */
+
+void mpx_loadb(mpw *v, const mpw *vl, const octet *p, size_t sz)
+{
+ unsigned n;
+ const octet *q = p + sz;
+ unsigned bits = 0;
+
+ if (v >= vl)
+ return;
+ while (q > p) {
+ n = U8(*--q);
+ w |= n << bits;
+ bits += 8;
+ if (bits >= MPW_BITS) {
+ *v++ = MPW(w);
+ w = n >> (MPW_BITS - bits + 8);
+ bits -= MPW_BITS;
+ if (v >= vl)
+ return;
+ }
+ }
+ *v++ = w;
+ MPX_ZERO(v, vl);
+}
+
+/*----- Logical shifting --------------------------------------------------*/
+
+/* --- @mpx_lsl@ --- *
+ *
+ * Arguments: @mpw *dv, *dvl@ = destination vector base and limit
+ * @const mpw *av, *avl@ = source vector base and limit
+ * @size_t n@ = number of bit positions to shift by
+ *
+ * Returns: ---
+ *
+ * Use: Performs a logical shift left operation on an integer.
+ */
+
+void mpx_lsl(mpw *dv, mpw *dvl, const mpw *av, const mpw *avl, size_t n)
+{
+ size_t nw;
+ unsigned nb;
+
+ /* --- Trivial special case --- */
+
+ if (n == 0)
+ MPX_COPY(dv, dvl, av, avl);
+
+ /* --- Single bit shifting --- */
+
+ else if (n == 1) {
+ mpw w = 0;
+ while (av < avl) {
+ mpw t;
+ if (dv >= dvl)
+ goto done;
+ t = *av++;
+ *dv++ = MPW((t << 1) | w);
+ w = t >> (MPW_BITS - 1);
+ }
+ if (dv >= dvl)
+ goto done;
+ *dv++ = MPW(w);
+ MPX_ZERO(dv, dvl);
+ }
+
+ /* --- Break out word and bit shifts for more sophisticated work --- */
+
+ nw = n / MPW_BITS;
+ nb = n % MPW_BITS;
+
+ /* --- Handle a shift by a multiple of the word size --- */
+
+ if (nb == 0) {
+ MPX_COPY(dv + nw, dvl, av, avl);
+ memset(dv, 0, MPWS(nw));
+ }
+
+ /* --- And finally the difficult case --- */
+
+ else {
+ mpw w;
+ size_t nr = MPW_BITS - nb;
+
+ if (dv + nw >= dvl) {
+ MPX_ZERO(dv, dvl);
+ goto done;
+ }
+ memset(dv, 0, MPWS(nw));
+ dv += nw;
+ w = *av++;
+
+ while (av < avl) {
+ mpw t;
+ if (dv >= dvl)
+ goto done;
+ t = *av++;
+ *dv++ = MPW((w >> nr) | (t << nb));
+ w = t;
+ }
+
+ if (dv < dvl) {
+ *dv++ = MPW(w >> nr);
+ MPX_ZERO(dv, dvl);
+ }
+ }
+
+done:;
+}
+
+/* --- @mpx_lsr@ --- *
+ *
+ * Arguments: @mpw *dv, *dvl@ = destination vector base and limit
+ * @const mpw *av, *avl@ = source vector base and limit
+ * @size_t n@ = number of bit positions to shift by
+ *
+ * Returns: ---
+ *
+ * Use: Performs a logical shift right operation on an integer.
+ */
+
+void mpx_lsr(mpw *dv, mpw *dvl, const mpw *av, const mpw *avl, size_t n)
+{
+ size_t nw;
+ unsigned nb;
+
+ /* --- Trivial special case --- */
+
+ if (n == 0)
+ MPX_COPY(dv, dvl, av, avl);
+
+ /* --- Single bit shifting --- */
+
+ else if (n == 1) {
+ mpw w = *av++ >> 1;
+ while (av < avl) {
+ mpw t;
+ if (dv >= dvl)
+ goto done;
+ t = *av++;
+ *dv++ = MPW((t << (MPW_BITS - 1)) | w);
+ w = t >> 1;
+ }
+ if (dv >= dvl)
+ goto done;
+ *dv++ = MPW(w);
+ MPX_ZERO(dv, dvl);
+ }
+
+ /* --- Break out word and bit shifts for more sophisticated work --- */
+
+ nw = n / MPW_BITS;
+ nb = n % MPW_BITS;
+
+ /* --- Handle a shift by a multiple of the word size --- */
+
+ if (nb == 0)
+ MPX_COPY(dv, dvl, av + nw, avl);
+
+ /* --- And finally the difficult case --- */
+
+ else {
+ mpw w;
+ size_t nr = MPW_BITS - nb;
+
+ av += nw;
+ w = *av++;
+ while (av < avl) {
+ mpw t;
+ if (dv >= dvl)
+ goto done;
+ t = *av++;
+ *dv++ = MPW((w >> nb) | (t << nr));
+ w = t;
+ }
+ if (dv < dvl) {
+ *dv++ = MPW(w >> nb);
+ MPX_ZERO(dv, dvl);
+ }
+ }
+
+done:;
+}
+
+/*----- Unsigned arithmetic -----------------------------------------------*/
+
+/* --- @mpx_ucmp@ --- *
+ *
+ * Arguments: @const mpw *av, *avl@ = first argument vector base and limit
+ * @const mpw *bv, *bvl@ = second argument vector base and limit
+ *
+ * Returns: Less than, equal to, or greater than zero depending on
+ * whether @a@ is less than, equal to or greater than @b@,
+ * respectively.
+ *
+ * Use: Performs an unsigned integer comparison.
+ */
+
+int mpx_ucmp(const mpw *av, const mpw *avl, const mpw *bv, const mpw *bvl)
+{
+ MPX_SHRINK(av, avl);
+ MPX_SHRINK(bv, bvl);
+
+ if (avl - av > bvl - bv)
+ return (+1);
+ else if (avl - av < bvl - bv)
+ return (-1);
+ else while (avl > av) {
+ mpw a = *--avl, b = *--bvl;
+ if (a > b)
+ return (+1);
+ else if (a < b)
+ return (-1);
+ }
+ return (0);
+}
+
+/* --- @mpx_uadd@ --- *
+ *
+ * Arguments: @mpw *dv, *dvl@ = destination vector base and limit
+ * @const mpw *av, *avl@ = first addend vector base and limit
+ * @const mpw *bv, *bvl@ = second addend vector base and limit
+ *
+ * Returns: ---
+ *
+ * Use: Performs unsigned integer addition. If the result overflows
+ * the destination vector, high-order bits are discarded. This
+ * means that two's complement addition happens more or less for
+ * free, although that's more a side-effect than anything else.
+ * The result vector may be equal to either or both source
+ * vectors, but may not otherwise overlap them.
+ */
+
+void mpx_uadd(mpw *dv, mpw *dvl, const mpw *av, const mpw *avl,
+ const mpw *bv, const mpw *bvl)
+{
+ mpw c = 0;
+
+ while (av < avl || bv < bvl) {
+ mpw a, b;
+ mpd x;
+ if (dv >= dvl)
+ return;
+ a = (av < avl) ? *av++ : 0;
+ b = (bv < bvl) ? *bv++ : 0;
+ x = (mpd)a + (mpd)b + c;
+ *dv++ = MPW(x);
+ c = x >> MPW_BITS;
+ }
+ if (dv < dvl) {
+ *dv++ = c;
+ MPX_ZERO(dv, dvl);
+ }
+}
+
+/* --- @mpx_usub@ --- *
+ *
+ * Arguments: @mpw *dv, *dvl@ = destination vector base and limit
+ * @const mpw *av, *avl@ = first argument vector base and limit
+ * @const mpw *bv, *bvl@ = second argument vector base and limit
+ *
+ * Returns: ---
+ *
+ * Use: Performs unsigned integer subtraction. If the result
+ * overflows the destination vector, high-order bits are
+ * discarded. This means that two's complement subtraction
+ * happens more or less for free, althuogh that's more a side-
+ * effect than anything else. The result vector may be equal to
+ * either or both source vectors, but may not otherwise overlap
+ * them.
+ */
+
+void mpx_usub(mpw *dv, mpw *dvl, const mpw *av, const mpw *avl,
+ const mpw *bv, const mpw *bvl)
+{
+ mpw c = 0;
+
+ while (av < avl || bv < bvl) {
+ mpw a, b;
+ mpd x;
+ if (dv >= dvl)
+ return;
+ a = (av < avl) ? *av++ : 0;
+ b = (bv < bvl) ? *bv++ : 0;
+ x = (mpd)a - (mpd)b + c;
+ *dv++ = MPW(x);
+ if (c >> MPW_BITS)
+ c = MPW(~0u);
+ }
+ c = c ? ~0u : 0;
+ while (dv < dvl)
+ *dv++ = c
+}
+
+/* --- @mpx_umul@ --- *
+ *
+ * Arguments: @mpw *dv, *dvl@ = destination vector base and limit
+ * @const mpw *av, *avl@ = multiplicand vector base and limit
+ * @const mpw *bv, *bvl@ = multiplier vector base and limit
+ *
+ * Returns: ---
+ *
+ * Use: Performs unsigned integer multiplication. If the result
+ * overflows the desination vector, high-order bits are
+ * discarded. The result vector may not overlap the argument
+ * vectors in any way.
+ */
+
+void mpx_umul(mpw *dv, mpw *dvl, const mpw *av, const mpw *avl,
+ const mpw *bv, const mpw *bvl)
+{
+ /* --- This is probably worthwhile on a multiply --- */
+
+ MPX_SHRINK(av, avl);
+ MPX_SHRINK(bv, bvl);
+
+ /* --- Deal with a multiply by zero --- */
+
+ if (bv == bvl) {
+ MPX_COPY(dv, dvl, bv, bvl);
+ return;
+ }
+
+ /* --- Do the initial multiply and initialize the accumulator --- */
+
+ MPX_UMULN(dv, dvl, av, avl, *bv++);
+
+ /* --- Do the remaining multiply/accumulates --- */
+
+ while (bv < bvl) {
+ mpw m = *bv++;
+ mpw c = ;
+ const mpw *avv = av;
+ mpw *dvv = ++dv;
+
+ while (avv < avl) {
+ mpd x;
+ if (dvv >= dvl)
+ goto next;
+ x = *dvv + m * *av++ + c;
+ *dv++ = MPW(x);
+ c = x >> MPW_BITS;
+ }
+ if (dvv < dvl)
+ *dvv++ = MPW(c);
+ next:;
+ }
+}
+
+/* --- @mpx_udiv@ --- *
+ *
+ * Arguments: @mpw *qv, *qvl@ = quotient vector base and limit
+ * @mpw *rv, *rvl@ = dividend/remainder vector base and limit
+ * @const mpw *dv, *dvl@ = divisor vector base and limit
+ *
+ * Returns: ---
+ *
+ * Use: Performs unsigned integer division. If the result overflows
+ * the quotient vector, high-order bits are discarded. (Clearly
+ * the remainder vector can't overflow.) The various vectors
+ * may not overlap in any way. Yes, I know it's a bit odd
+ * requiring the dividend to be in the result position but it
+ * does make some sense really. The remainder must have
+ * headroom for at least two extra words.
+ */
+
+void mpx_udiv(mpw *qv, mpw *qvl, mpw *rv, mpw *rvl,
+ const mpw *dv, const mpw *dvl)
+{
+ mpw spare[2];
+ unsigned norm = 0;
+ size_t scale;
+ mpw d, dd;
+
+ /* --- Initialize the quotient --- */
+
+ MPX_ZERO(qv, qvl);
+
+ /* --- Normalize the divisor --- *
+ *
+ * The algorithm requires that the divisor be at least two digits long.
+ * This is easy to fix.
+ */
+
+ MPX_SHRINK(dv, dvl);
+
+ assert(((void)"division by zero in mpx_udiv", dv < dvl));
+
+ d = dvl[-1];
+ if (dv + 1 == dvl) {
+ spare[0] = 0;
+ spare[1] = d;
+ dv = spare;
+ dvl = spare + 2;
+ norm += MPW_BITS;
+ }
+
+ while (d < MPW_MAX / 2) {
+ d <<= 1;
+ norm += 1;
+ }
+ dd = dvl[-2];
+
+ /* --- Normalize the dividend/remainder to match --- */
+
+ mpx_lsl(rv, rvl, rv, rvl, norm);
+ MPX_SHRINK(rv, rvl);
+
+ /* --- Work out the relative scales --- */
+
+ {
+ size_t rvn = rvl - rv;
+ size_t dvn = dvn - dv;
+
+ /* --- If the divisor is clearly larger, notice this --- */
+
+ if (dvn > rvn) {
+ mpx_lsr(rv, rvl, rv, rvl, norm);
+ return;
+ }
+
+ scale = rvn - dvn;
+ }
+
+ /* --- Calculate the most significant quotient digit --- *
+ *
+ * Because the divisor has its top bit set, this can only happen once. The
+ * pointer arithmetic is a little contorted, to make sure that the
+ * behaviour is defined.
+ */
+
+ if (MPX_UCMP(rv + scale, rvl, >=, dv, dvl)) {
+ mpx_usub(rv + scale, rvl, rv + scale, rvl, dv, dvl);
+ if (qvl - qv > scale)
+ qv[scale] = 1;
+ }
+
+ /* --- Now for the main loop --- */
+
+ {
+ mpw *rvv;
+ mpw r;
+
+ scale--;
+ rvv = rvl - 2;
+ r = rvv[1];
+
+ while (scale) {
+ mpw q, rr;
+
+ /* --- Get an estimate for the next quotient digit --- */
+
+ rr = *rvv--;
+ if (r == d)
+ q = MPW_MAX;
+ else {
+ mpd rx = (r << MPW_BITS) | rr;
+ q = MPW(rx / d);
+ }
+
+ /* --- Refine the estimate --- */
+
+ {
+ mpd yh = (mpd)d * q;
+ mpd yl = (mpd)dd * q;
+
+}
+
+/*----- That's all, folks -------------------------------------------------*/
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: mpx.h,v 1.1 1999/09/03 08:41:12 mdw Exp $
+ *
+ * Low level multiprecision arithmetic
+ *
+ * (c) 1999 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: mpx.h,v $
+ * Revision 1.1 1999/09/03 08:41:12 mdw
+ * Initial import.
+ *
+ */
+
+#ifndef MPX_H
+#define MPX_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*----- The idea ----------------------------------------------------------*
+ *
+ * This file provides functions and macros which work on vectors of words as
+ * unsigned multiprecision integers. The interface works in terms of base
+ * and limit pointers (i.e., a pointer to the start of a vector, and a
+ * pointer just past its end) rather than base pointer and length, because
+ * that requires more arithmetic and state to work on.
+ *
+ * The interfaces are slightly bizarre in other ways. Try to use the
+ * higher-level functions where you can: they're rather better designed to
+ * actually be friendly and useful.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <string.h>
+
+#ifndef MPTYPES_H
+# include "mptypes.h"
+#endif
+
+/*----- General manipulation ----------------------------------------------*/
+
+/* --- @MPX_SHRINK@ --- *
+ *
+ * Arguments: @const mpw *v@ = pointer to vector of words
+ * @const mpw *vl@ = (updated) current limit of vector
+ *
+ * Use: Shrinks down the limit of a multiprecision integer vector.
+ */
+
+#define MPX_SHRINK(v, vl) do { \
+ const mpw *_v = (v), *_vl = (vl); \
+ while (_vl > _v && *--_vl) \
+ ; \
+ (vl) = _vl; \
+} while (0)
+
+/* --- @MPX_BITS@ --- *
+ *
+ * Arguments: @unsigned long b@ = result variable
+ * @const mpw *v@ = pointer to array of words
+ * @const mpw *vl@ = limit of vector (from @MPX_SHRINK@)
+ *
+ * Use: Calculates the number of bits in a multiprecision value.
+ */
+
+#define MPX_BITS(b, v, vl) do { \
+ const mpw *_v = (v), *_vl = (vl); \
+ if (_v == _vl) \
+ (b) = 0; \
+ else { \
+ unsigned long _b = MPW_BITS * (_vl - _v - 1) + 1; \
+ mpw _w = _vl[-1]; \
+ unsigned _k = MPW_BITS / 2; \
+ while (_k) { \
+ if (_w >> _k) { \
+ _w >>= _k; \
+ _b += _k; \
+ } \
+ _k >>= 1; \
+ } \
+ (b) = _b; \
+ } \
+} while (0)
+
+/* --- @MPX_OCTETS@ --- *
+ *
+ * Arguments: @size_t o@ = result variable
+ * @const mpw *v@ = pointer to array of words
+ * @size_t len@ = length of the array (from @MPX_LEN@)
+ *
+ * Use: Calculates the number of octets in a multiprecision value.
+ */
+
+#define MPX_OCTETS(o, v, len) do { \
+ const mpw *_v = (v), *_vl = (vl); \
+ if (_v == _vl) \
+ (o) = 0; \
+ else { \
+ _size_t _o = (MPW_BITS / 8) * (_vl - _v - 1); \
+ mpw _w = _vl[-1]; \
+ unsigned _k = MPW_BITS / 2; \
+ while (_k > 3) { \
+ if (_w >> _k) { \
+ _w >>= _k; \
+ _o += _k - 3; \
+ } \
+ _k >>= 1; \
+ } \
+ if (_w) \
+ _o++; \
+ (o) = _o; \
+ } \
+} while (0)
+
+/* --- @MPX_COPY@ --- *
+ *
+ * Arguments: @dv, dvl@ = destination vector base and limit
+ * @av, avl@ = source vector base and limit
+ *
+ * Use: Copies a multiprecision integer.
+ */
+
+#define MPX_COPY(dv, dvl, av, dvl) do { \
+ mpw *_dv = (dv); \
+ size_t _dn = (dvl) - _dv; \
+ const mpw *_av = (av); \
+ size_t _an = (avl) - _av; \
+ if (_av == _dv) { \
+ if (_dvl > _avl) \
+ memset(_avl, 0, MPWS(_dn - _an)); \
+ } else if (_an >= _dn) \
+ memmove(_dv, _av, MPWS(_dn)); \
+ else { \
+ memmove(_dv, _av, MPWS(_an)); \
+ memset(_dv + _an, 0, MPWS(_dn - _an)); \
+ } \
+} while (0)
+
+/* --- @MPX_ZERO@ --- *
+ *
+ * Arguments: @v, vl@ = base and limit of vector to clear
+ *
+ * Use: Zeroes the area between the two vector pointers.
+ */
+
+#define MPX_ZERO(v, vl) { \
+ mpw *_v = (v), *_vl = (vl); \
+ memset(_v, 0, MPWS(_vl - _v)); \
+} while (0)
+
+/*----- Loading and storing -----------------------------------------------*/
+
+/* --- @mpx_storel@ --- *
+ *
+ * Arguments: @const mpw *v, *vl@ = base and limit of source vector
+ * @octet *p@ = pointer to octet array
+ * @size_t sz@ = size of octet array
+ *
+ * Returns: ---
+ *
+ * Use: Stores an MP in an octet array, least significant octet
+ * first. High-end octets are silently discarded if there
+ * isn't enough space for them.
+ */
+
+extern void mpx_storel(const mpw */*v*/, const mpw */*vl*/,
+ octet */*p*/, size_t /*sz*/);
+
+/* --- @mpx_loadl@ --- *
+ *
+ * Arguments: @mpw *v, *vl@ = base and limit of destination vector
+ * @const octet *p@ = pointer to octet array
+ * @size_t sz@ = size of octet array
+ *
+ * Returns: ---
+ *
+ * Use: Loads an MP in an octet array, least significant octet
+ * first. High-end octets are ignored if there isn't enough
+ * space for them.
+ */
+
+extern void mpx_loadl(mpw */*v*/, mpw */*vl*/,
+ const octet */*p*/, size_t /*sz*/);
+
+/* --- @mpx_storeb@ --- *
+ *
+ * Arguments: @const mpw *v, *vl@ = base and limit of source vector
+ * @octet *p@ = pointer to octet array
+ * @size_t sz@ = size of octet array
+ *
+ * Returns: ---
+ *
+ * Use: Stores an MP in an octet array, most significant octet
+ * first. High-end octets are silently discarded if there
+ * isn't enough space for them.
+ */
+
+extern void mpx_storeb(const mpw */*v*/, const mpw */*vl*/,
+ octet */*p*/, size_t /*sz*/);
+
+/* --- @mpx_loadb@ --- *
+ *
+ * Arguments: @mpw *v, *vl@ = base and limit of destination vector
+ * @const octet *p@ = pointer to octet array
+ * @size_t sz@ = size of octet array
+ *
+ * Returns: ---
+ *
+ * Use: Loads an MP in an octet array, most significant octet
+ * first. High-end octets are ignored if there isn't enough
+ * space for them.
+ */
+
+extern void mpx_loadb(mpw */*v*/, mpw */*vl*/,
+ const octet */*p*/, size_t /*sz*/);
+
+/*----- Logical shifting --------------------------------------------------*/
+
+/* --- @mpx_lsl@ --- *
+ *
+ * Arguments: @mpw *dv, *dvl@ = destination vector base and limit
+ * @const mpw *av, *avl@ = source vector base and limit
+ * @size_t n@ = number of bit positions to shift by
+ *
+ * Returns: ---
+ *
+ * Use: Performs a logical shift left operation on an integer.
+ */
+
+extern void mpx_lsl(mpw */*dv*/, mpw */*dvl*/,
+ const mpw */*av*/, const mpw */*avl*/,
+ size_t /*n*/);
+
+/* --- @mpx_lsr@ --- *
+ *
+ * Arguments: @mpw *dv, *dvl@ = destination vector base and limit
+ * @const mpw *av, *avl@ = source vector base and limit
+ * @size_t n@ = number of bit positions to shift by
+ *
+ * Returns: ---
+ *
+ * Use: Performs a logical shift right operation on an integer.
+ */
+
+extern void mpx_lsr(mpw */*dv*/, mpw */*dvl*/,
+ const mpw */*av*/, const mpw */*avl*/,
+ size_t /*n*/);
+
+/*----- Unsigned arithmetic -----------------------------------------------*/
+
+/* --- @mpx_ucmp@ --- *
+ *
+ * Arguments: @const mpw *av, *avl@ = first argument vector base and limit
+ * @const mpw *bv, *bvl@ = second argument vector base and limit
+ *
+ * Returns: Less than, equal to, or greater than zero depending on
+ * whether @a@ is less than, equal to or greater than @b@,
+ * respectively.
+ *
+ * Use: Performs an unsigned integer comparison.
+ */
+
+#define MPX_UCMP(av, avl, op, dv, dvl) \
+ (mpx_ucmp((av), (avl), (dv), (dvl)) op 0)
+
+extern int mpx_ucmp(const mpw */*av*/, const mpw */*avl*/,
+ const mpw */*bv*/, const mpw */*bvl*/);
+
+/* --- @mpx_uadd@ --- *
+ *
+ * Arguments: @mpw *dv, *dvl@ = destination vector base and limit
+ * @const mpw *av, *avl@ = first addend vector base and limit
+ * @const mpw *bv, *bvl@ = second addend vector base and limit
+ *
+ * Returns: ---
+ *
+ * Use: Performs unsigned integer addition. If the result overflows
+ * the destination vector, high-order bits are discarded. This
+ * means that two's complement addition happens more or less for
+ * free, although that's more a side-effect than anything else.
+ * The result vector may be equal to either or both source
+ * vectors, but may not otherwise overlap them.
+ */
+
+extern void mpx_uadd(mpw */*dv*/, mpw */*dvl*/,
+ const mpw */*av*/, const mpw */*avl*/,
+ const mpw */*bv*/, const mpw */*bvl*/);
+
+/* --- @mpx_usub@ --- *
+ *
+ * Arguments: @mpw *dv, *dvl@ = destination vector base and limit
+ * @const mpw *av, *avl@ = first argument vector base and limit
+ * @const mpw *bv, *bvl@ = second argument vector base and limit
+ *
+ * Returns: ---
+ *
+ * Use: Performs unsigned integer subtraction. If the result
+ * overflows the destination vector, high-order bits are
+ * discarded. This means that two's complement subtraction
+ * happens more or less for free, althuogh that's more a side-
+ * effect than anything else. The result vector may be equal to
+ * either or both source vectors, but may not otherwise overlap
+ * them.
+ */
+
+extern void mpx_usub(mpw */*dv*/, mpw */*dvl*/,
+ const mpw */*av*/, const mpw */*avl*/,
+ const mpw */*bv*/, const mpw */*bvl*/);
+
+/* --- @MPX_UMULN@ --- *
+ *
+ * Arguments: @dv, dvl@ = destination vector base and limit
+ * @av, avl@ = multiplicand vector base and limit
+ * @m@ = multiplier
+ *
+ * Use: Multiplies a multiprecision integer by a single-word value.
+ * The destination and source may be equal. The destination
+ * is completely cleared after use.
+ */
+
+#define MPX_UMULN(dv, dvl, av, avl, m) do { \
+ mpw *_dv = (dv), *_dvl = (dvl); \
+ const mpw *_av = (av), *_avl = (avl); \
+ mpw _c = 0; \
+ mpd _m = (m); \
+ \
+ while (_av < _avl) { \
+ mpd _x; \
+ if (_dv >= _dvl) \
+ break; \
+ _x = _m * *_av++ + c; \
+ *_dv++ = MPW(_x); \
+ _c = _x >> MPW_BITS; \
+ } \
+ if (_dv < _dvl) { \
+ *_dv++ = MPW(_c); \
+ MPX_ZERO(_dv, _dvl); \
+ } \
+} while (0)
+
+/* --- @MPX_UMLAN@ --- *
+ *
+ * Arguments: @dv, dvl@ = destination/accumulator vector base and limit
+ * @av, avl@ = multiplicand vector base and limit
+ * @m@ = multiplier
+ *
+ * Use: Multiplies a multiprecision integer by a single-word value
+ * and adds the result to an accumulator.
+ */
+
+#define MPX_UMLAN(dv, dvl, av, avl, m) do { \
+ mpw *_dv = (dv), *_dvl = (dvl); \
+ const mpw *_av = (av), *_avl = (avl); \
+ mpw _c = 0; \
+ mpd _m = (m); \
+ \
+ while (_av < _avl) { \
+ mpd _x; \
+ if (_dv >= _dvl) \
+ break; \
+ _x = *_dv + _m * *_av++ + _c; \
+ *_dv++ = MPW(_x); \
+ _c = _x >> MPW_BITS; \
+ } \
+ if (_dv < _dvl) { \
+ *_dv++ = MPW(_c); \
+ MPX_ZERO(_dv, _dvl); \
+ } \
+} while (0)
+
+/* --- @mpx_umul@ --- *
+ *
+ * Arguments: @mpw *dv, *dvl@ = destination vector base and limit
+ * @const mpw *av, *avl@ = multiplicand vector base and limit
+ * @const mpw *bv, *bvl@ = multiplier vector base and limit
+ *
+ * Returns: ---
+ *
+ * Use: Performs unsigned integer multiplication. If the result
+ * overflows the desination vector, high-order bits are
+ * discarded. The result vector may not overlap the argument
+ * vectors in any way.
+ */
+
+extern void mpx_umul(mpw */*dv*/, mpw */*dvl*/,
+ const mpw */*av*/, const mpw */*avl*/,
+ const mpw */*bv*/, const mpw */*bvl*/);
+
+/* --- @mpx_udiv@ --- *
+ *
+ * Arguments: @mpw *qv, *qvl@ = quotient vector base and limit
+ * @mpw *rv, *rvl@ = dividend/remainder vector base and limit
+ * @const mpw *dv, *dvl@ = divisor vector base and limit
+ *
+ * Returns: ---
+ *
+ * Use: Performs unsigned integer division. If the result overflows
+ * the quotient vector, high-order bits are discarded. (Clearly
+ * the remainder vector can't overflow.) The various vectors
+ * may not overlap in any way. Yes, I know it's a bit odd
+ * requiring the dividend to be in the result position but it
+ * does make some sense really.
+ */
+
+extern void mpx_udiv(mpw */*qv*/, mpw */*qvl*/, mpw */*rv*/, mpw */*rvl*/,
+ const mpw */*dv*/, const mpw */*dvl*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: noise.c,v 1.1 1999/09/03 08:41:12 mdw Exp $
+ *
+ * Acquisition of environmental noise (Unix specific)
+ *
+ * (c) 1998 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: noise.c,v $
+ * Revision 1.1 1999/09/03 08:41:12 mdw
+ * Initial import.
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#ifdef HAVE_SETGROUPS
+# include <grp.h>
+#endif
+
+#include <mLib/bits.h>
+#include <mLib/tv.h>
+
+#include "noise.h"
+#include "paranoia.h"
+#include "rand.h"
+
+/*----- Magical numbers ---------------------------------------------------*/
+
+#define NOISE_KIDLIFE 100000 /* @noise_filter@ child lifetime */
+#define MILLION 1000000 /* One million */
+
+/*----- Noise source definition -------------------------------------------*/
+
+rand_source noise_source = { noise_acquire, noise_timer };
+
+/*----- Static variables --------------------------------------------------*/
+
+/* --- Timer differences --- */
+
+static unsigned long noise_last; /* Last time recorded */
+static unsigned long noise_diff; /* Last first order difference */
+
+/* --- Setuid program handling --- */
+
+static uid_t noise_uid; /* Uid to set to spawn processes */
+static gid_t noise_gid; /* Gid to set to spawn processes */
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @bitcount@ --- *
+ *
+ * Arguments: @unsigned long x@ = a word containing bits
+ *
+ * Returns: The number of bits set in the word.
+ */
+
+static int bitcount(unsigned long x)
+{
+ char ctab[] = { 0, 1, 1, 2, 1, 2, 2, 3,
+ 1, 2, 2, 3, 2, 3, 3, 4 };
+ int count = 0;
+ while (x) {
+ count += ctab[x & 0xfu];
+ x >>= 4;
+ }
+ return (count);
+}
+
+/* --- @timer@ --- *
+ *
+ * Arguments: @rand_pool *r@ = pointer to randomness pool
+ * @struct timeval *tv@ = pointer to time block
+ *
+ * Returns: Nonzer if some randomness was contributed.
+ *
+ * Use: Low-level timer contributor.
+ */
+
+static int timer(rand_pool *r, struct timeval *tv)
+{
+ unsigned long x, d, dd;
+ int de, dde;
+ int ret;
+
+ x = tv->tv_usec + MILLION * tv->tv_sec;
+ d = x ^ noise_last;
+ dd = d ^ noise_diff;
+ noise_diff = d;
+ de = bitcount(d);
+ dde = bitcount(dd);
+ rand_add(r, tv, sizeof(*tv), de <= dde ? de : dde);
+ ret = (de || dde);
+ BURN(tv); x = d = dd = de = dde = 0;
+ return (ret);
+}
+
+/* --- @noise_timer@ --- *
+ *
+ * Arguments: @rand_pool *r@ = pointer to a randomness pool
+ *
+ * Returns: Nonzero if some randomness was contributed.
+ *
+ * Use: Contributes the current time to the randomness pool.
+ * A guess at the number of useful bits contributed is made,
+ * based on first and second order bit differences. This isn't
+ * ever-so reliable, but it's better than nothing.
+ */
+
+int noise_timer(rand_pool *r)
+{
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+ return (timer(r, &tv));
+}
+
+/* --- @noise_devrandom@ --- *
+ *
+ * Arguments: @rand_pool *r@ = pointer to a randomness pool
+ *
+ * Returns: Nonzero if some randomness was contributed.
+ *
+ * Use: Attempts to obtain some randomness from the system entropy
+ * pool. All bits from the device are assumed to be good.
+ */
+
+int noise_devrandom(rand_pool *r)
+{
+ int fd;
+ octet buf[RAND_POOLSZ];
+ ssize_t len;
+ int ret = 0;
+
+ /* --- Be nice to other clients of the random device --- *
+ *
+ * Attempt to open the device nonblockingly. If that works, take up to
+ * one bufferful and then close again. If there's no data to be read,
+ * then that's tough and we go away again, on the grounds that the device
+ * needs to get some more entropy from somewhere.
+ */
+
+ if ((fd = open("/dev/random", O_RDONLY | O_NONBLOCK)) >= 0) {
+ if ((len = read(fd, buf, sizeof(buf))) > 0) {
+ rand_add(r, buf, len, len * 8);
+ BURN(buf);
+ ret = 1;
+ }
+ close(fd);
+ }
+ noise_timer(r);
+ return (ret);
+}
+
+/* --- @noise_setid@ --- *
+ *
+ * Arguments: @uid_t uid@ = uid to set
+ * @gid_t gid@ = gid to set
+ *
+ * Returns: ---
+ *
+ * Use: Sets the user and group ids to be used by @noise_filter@
+ * when running child processes. This is useful to avoid
+ * giving shell commands (even carefully written ones) undue
+ * privileges.
+ */
+
+void noise_setid(uid_t uid, gid_t gid)
+{
+ noise_uid = uid;
+ noise_gid = gid;
+}
+
+/* --- @noise_filter@ --- *
+ *
+ * Arguments: @rand_pool *r@ = pointer to a randomness pool
+ * @int good@ = number of good bits per 1024 bits
+ * @const char *c@ = shell command to run
+ *
+ * Returns: Nonzero if some randomness was contributed.
+ *
+ * Use: Attempts to execute a shell command, and dump it into the
+ * randomness pool. A very rough estimate of the number of
+ * good bits is made, based on the size of the command's output.
+ * This function calls @waitpid@, so be careful. Before execing
+ * the command, the process uid and gid are set to the values
+ * given to @noise_setid@, and an attempt is made to reset the
+ * list of supplementary groups. The environment passed to
+ * the command has been severly lobotimized. If the command
+ * fails to complete within a short time period, it is killed.
+ * Paranoid use of close-on-exec flags for file descriptors is
+ * recommended.
+ */
+
+int noise_filter(rand_pool *r, int good, const char *c)
+{
+ char buf[4096];
+ pid_t kid;
+ int fd[2];
+ struct timeval dead;
+ int ret = 0;
+ const char *env[] = {
+ "PATH=/bin:/usr/bin:/sbin:/usr/sbin:/etc",
+ 0
+ };
+
+ /* --- Remember when this business started --- */
+
+ gettimeofday(&dead, 0);
+ timer(r, &dead);
+
+ /* --- Create a pipe --- */
+
+ if (pipe(fd))
+ return (ret);
+
+ /* --- Fork a child off --- */
+
+ kid = fork();
+ if (kid < 0) {
+ close(fd[0]);
+ close(fd[1]);
+ return (ret);
+ }
+
+ /* --- Handle the child end of the deal --- */
+
+ fflush(0);
+ if (kid == 0) {
+ int f;
+
+ /* --- Set the pipe as standard output, close standard input --- */
+
+ close(0); close(1); close(2);
+
+ if (fd[1] != 1) {
+ if (dup2(fd[1], 1) < 0) _exit(127);
+ close(fd[1]);
+ }
+
+ if ((f = open("/dev/null", O_RDONLY)) != 0 ||
+ (f = open("/dev/null", O_WRONLY)) != 2)
+ _exit(127);
+
+ /* --- Play games with uids --- */
+
+ if (noise_gid != NOISE_NOSETGID) {
+ setgid(noise_gid);
+ setegid(noise_gid);
+#ifdef HAVE_SETGROUPS
+ setgroups(1, &noise_gid);
+#endif
+ }
+
+ if (noise_uid != NOISE_NOSETUID) {
+ setuid(noise_uid);
+ seteuid(noise_uid);
+ }
+
+ /* --- Start the process up --- */
+
+ execle("/bin/sh", "-c", c, (char *)0, env);
+ _exit(127);
+ }
+
+ /* --- Sort out my end of the deal --- */
+
+ close(fd[1]);
+
+ /* --- Decide on the deadline --- */
+
+ TV_ADDL(&dead, &dead, 0, NOISE_KIDLIFE);
+
+ /* --- Now read, and think --- */
+
+ for (;;) {
+ struct timeval now, diff;
+ fd_set rd;
+
+ gettimeofday(&now, 0);
+ timer(r, &now);
+ if (TV_CMP(&now, >, &dead))
+ break;
+ TV_SUB(&diff, &dead, &now);
+
+ FD_ZERO(&rd);
+ FD_SET(fd[0], &rd);
+
+ if (select(fd[0] + 1, &rd, 0, 0, &diff) < 0)
+ break;
+ if (FD_ISSET(fd[0], &rd)) {
+ ssize_t sz;
+ int goodbits;
+
+ if ((sz = read(fd[0], buf, sizeof(buf))) <= 0)
+ break;
+ goodbits = (sz * good) / 128;
+ rand_add(r, buf, sz, goodbits);
+ ret = 1;
+ }
+ }
+
+ /* --- We've finished with it: kill the child process --- *
+ *
+ * This is morally questionable. On the other hand, I don't want to be
+ * held up in the @waitpid@ call if I can possibly help it. Maybe a
+ * double-fork is worth doing here.
+ */
+
+ close(fd[0]);
+ BURN(buf);
+ noise_timer(r);
+ kill(kid, SIGKILL);
+ waitpid(kid, 0, 0);
+ return (ret);
+}
+
+/* --- @noise_acquire@ --- *
+ *
+ * Arguments: @rand_pool *r@ = pointer to a randomness pool
+ *
+ * Returns: ---
+ *
+ * Use: Acquires some randomness from somewhere.
+ */
+
+void noise_acquire(rand_pool *r)
+{
+ if (!noise_devrandom(r)) {
+
+ /* --- Output of `ps' --- *
+ *
+ * This is a hopefully cheap way of getting a bit of noise. I'm guessing
+ * the good bit ratio based on about 90 bytes per line of output, and
+ * each line containing maybe 12 bits worth of interesting data. (Some
+ * quick experiments with gzip seem to bear this idea out.) So, 12 good
+ * bits per 90 bytes of output gives slightly more than 17 good bits per
+ * 1024 bits of output. So I'll be a pessimist and say 16 bits.
+ */
+
+ (void)
+ (noise_filter(r, 16, "ps alxww") ||
+ noise_filter(r, 16, "ps -elf"));
+
+ /* --- Output of `netstat' --- *
+ *
+ * Another possibly cheap way of getting noise. My output has about
+ * 72 bytes per line of output. My wild guesses are telling me that
+ * there are probably only about four good bits per line (gzip tells
+ * me there's six, but I want to underestimate). Four bits per 72 bytes
+ * is 7 good bits per 1024 bits of output. Pessimist that I am, I'll
+ * call it six.
+ */
+
+ noise_filter(r, 6, "netstat -n");
+ }
+}
+
+/*----- That's all, folks -------------------------------------------------*/
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: noise.h,v 1.1 1999/09/03 08:41:12 mdw Exp $
+ *
+ * Acquisition of environmental noise (Unix specific)
+ *
+ * (c) 1998 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: noise.h,v $
+ * Revision 1.1 1999/09/03 08:41:12 mdw
+ * Initial import.
+ *
+ */
+
+#ifndef NOISE_H
+#define NOISE_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <sys/types.h>
+
+#ifndef RAND_H
+# include "rand.h"
+#endif
+
+/*----- Noise source definition -------------------------------------------*/
+
+extern rand_source noise_source;
+
+/*----- Magic numbers -----------------------------------------------------*/
+
+#define NOISE_NOSETUID ((uid_t)-1)
+#define NOISE_NOSETGID ((gid_t)-1)
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @noise_timer@ --- *
+ *
+ * Arguments: @rand_pool *r@ = pointer to a randomness pool
+ *
+ * Returns: Nonzero if some randomness was contributed.
+ *
+ * Use: Contributes the current time to the randomness pool.
+ * A guess at the number of useful bits contributed is made,
+ * based on first and second order bit differences. This isn't
+ * ever-so reliable, but it's better than nothing.
+ */
+
+extern int noise_timer(rand_pool */*r*/);
+
+/* --- @noise_devrandom@ --- *
+ *
+ * Arguments: @rand_pool *r@ = pointer to a randomness pool
+ *
+ * Returns: Nonzero if some randomness was contributed.
+ *
+ * Use: Attempts to obtain some randomness from the system entropy
+ * pool. All bits from the device are assumed to be good.
+ */
+
+extern int noise_devrandom(rand_pool */*r*/);
+
+/* --- @noise_setid@ --- *
+ *
+ * Arguments: @uid_t uid@ = uid to set
+ * @gid_t gid@ = gid to set
+ *
+ * Returns: ---
+ *
+ * Use: Sets the user and group ids to be used by @noise_filter@
+ * when running child processes. This is useful to avoid
+ * giving shell commands (even carefully written ones) undue
+ * privileges.
+ */
+
+extern void noise_setid(uid_t /*uid*/, gid_t /*gid*/);
+
+/* --- @noise_filter@ --- *
+ *
+ * Arguments: @rand_pool *r@ = pointer to a randomness pool
+ * @int good@ = number of good bits per 1024 bits
+ * @const char *c@ = shell command to run
+ *
+ * Returns: Nonzero if some randomness was contributed.
+ *
+ * Use: Attempts to execute a shell command, and dump it into the
+ * randomness pool. A very rough estimate of the number of
+ * good bits is made, based on the size of the command's output.
+ * This function calls @waitpid@, so be careful. Before execing
+ * the command, the process uid and gid are set to the values
+ * given to @noise_setid@, and an attempt is made to reset the
+ * list of supplementary groups. The environment passed to
+ * the command has been severly lobotimized. If the command
+ * fails to complete within a short time period, it is killed.
+ * Paranoid use of close-on-exec flags for file descriptors is
+ * recommended.
+ */
+
+extern int noise_filter(rand_pool */*r*/, int /*good*/, const char */*c*/);
+
+/* --- @noise_acquire@ --- *
+ *
+ * Arguments: @rand_pool *r@ = pointer to a randomness pool
+ *
+ * Returns: ---
+ *
+ * Use: Acquires some randomness from somewhere.
+ */
+
+extern void noise_acquire(rand_pool */*r*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: ofb.h,v 1.1 1999/09/03 08:41:12 mdw Exp $
+ *
+ * Output feedback for block ciphers
+ *
+ * (c) 1999 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: ofb.h,v $
+ * Revision 1.1 1999/09/03 08:41:12 mdw
+ * Initial import.
+ *
+ */
+
+#ifndef OFB_H
+#define OFB_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <string.h>
+
+#include <mLib/bits.h>
+
+#ifndef BLKC_H
+# include "blkc.h"
+#endif
+
+#ifndef PARANOIA_H
+# include "paranoia.h"
+#endif
+
+/*----- Macros ------------------------------------------------------------*/
+
+/* --- @OFB_DECL@ --- *
+ *
+ * Arguments: @PRE@, @pre@ = prefixes for block cipher definitions
+ *
+ * Use: Makes declarations for output feedback mode.
+ */
+
+#define OFB_DECL(PRE, pre) \
+ \
+typedef struct pre ## _ofbctx { \
+ pre ## _ctx ctx; /* Underlying cipher context */ \
+ int off; /* Current offset in buffer */ \
+ octet iv[PRE ## _BLKSZ]; /* Output buffer and IV */ \
+} pre ## _ofbctx; \
+ \
+extern void pre ## _ofbgetiv(const pre ## _ofbctx */*ctx*/, \
+ void */*iv*/); \
+ \
+extern void pre ## _ofbsetiv(pre ## _ofbctx */*ctx*/, \
+ const void */*iv*/); \
+ \
+extern void pre ## _ofbbdry(pre ## _ofbctx */*ctx*/); \
+ \
+extern void pre ## _ofbsetkey(pre ## _ofbctx */*ctx*/, \
+ const pre ## _ctx */*k*/); \
+ \
+extern void pre ## _ofbinit(pre ## _ofbctx */*ctx*/, \
+ const void */*key*/, size_t /*sz*/, \
+ const void */*iv*/); \
+ \
+extern void pre ## _ofbencrypt(pre ## _ofbctx */*ctx*/, \
+ const void */*src*/, void */*dest*/, \
+ size_t /*sz*/);
+
+/* --- @OFB_DEF@ --- *
+ *
+ * Arguments: @PRE@, @pre@ = prefixes for the underlying block cipher
+ *
+ * Use: Creates definitions for output feedback mode.
+ */
+
+#define OFB_DEF(PRE, pre) \
+ \
+/* --- @pre_ofbgetiv@ --- * \
+ * \
+ * Arguments: @const pre_ofbctx *ctx@ = pointer to OFB context block \
+ * @void *iv#@ = pointer to output data block \
+ * \
+ * Returns: --- \
+ * \
+ * Use: Reads the currently set IV. Reading and setting an IV \
+ * is not transparent to the cipher. It will add a `step' \
+ * which must be matched by a similar operation during \
+ * decryption. \
+ */ \
+ \
+void pre ## _ofbgetiv(const pre ## _ofbctx *ctx, void *iv) \
+{ \
+ octet *p = iv; \
+ int off = ctx->off; \
+ int rest = PRE ## _BLKSZ - off; \
+ memcpy(p, ctx->iv + off, rest); \
+ memcpy(p + rest, ctx->iv, off); \
+} \
+ \
+/* --- @pre_ofbsetiv@ --- * \
+ * \
+ * Arguments: @pre_ofbctx *ctx@ = pointer to OFB context block \
+ * @cnost void *iv@ = pointer to IV to set \
+ * \
+ * Returns: --- \
+ * \
+ * Use: Sets the IV to use for subsequent encryption. \
+ */ \
+ \
+void pre ## _ofbsetiv(pre ## _ofbctx *ctx, const void *iv) \
+{ \
+ uint32 niv[PRE ## _BLKSZ / 4]; \
+ BLKC_LOAD(PRE, niv, iv); \
+ pre ## _eblk(&ctx->ctx, niv, niv); \
+ BLKC_STORE(PRE, ctx->iv, niv); \
+ ctx->off = 0; \
+} \
+ \
+/* --- @pre_ofbbdry@ --- * \
+ * \
+ * Arguments: @pre_ofbctx *ctx@ = pointer to OFB context block \
+ * \
+ * Returns: --- \
+ * \
+ * Use: Inserts a boundary during encryption. Successful \
+ * decryption must place a similar boundary. \
+ */ \
+ \
+void pre ## _ofbbdry(pre ## _ofbctx *ctx) \
+{ \
+ octet iv[PRE ## _BLKSZ]; \
+ pre ## _ofbgetiv(ctx, iv); \
+ pre ## _ofbsetiv(ctx, iv); \
+ BURN(iv); \
+} \
+ \
+/* --- @pre_ofbsetkey@ --- * \
+ * \
+ * Arguments: @pre_ofbctx *ctx@ = pointer to OFB context block \
+ * @const pre_ctx *k@ = pointer to cipher context \
+ * \
+ * Returns: --- \
+ * \
+ * Use: Sets the OFB context to use a different cipher key. \
+ */ \
+ \
+void pre ## _ofbsetkey(pre ## _ofbctx *ctx, const pre ## _ctx *k) \
+{ \
+ ctx->ctx = *k; \
+} \
+ \
+/* --- @pre_ofbinit@ --- * \
+ * \
+ * Arguments: @pre_ofbctx *ctx@ = pointer to cipher context \
+ * @const void *key@ = pointer to the key buffer \
+ * @size_t sz@ = size of the key \
+ * @const void *iv@ = pointer to initialization vector \
+ * \
+ * Returns: --- \
+ * \
+ * Use: Initializes a OFB context ready for use. You should \
+ * ensure that the IV chosen is unique: reusing an IV will \
+ * compromise the security of the entire plaintext. This \
+ * is equivalent to calls to @pre_init@, @pre_ofbsetkey@ \
+ * and @pre_ofbsetiv@. \
+ */ \
+ \
+void pre ## _ofbinit(pre ## _ofbctx *ctx, \
+ const void *key, size_t sz, \
+ const void *iv) \
+{ \
+ static octet zero[PRE ## _BLKSZ] = { 0 }; \
+ pre ## _init(&ctx->ctx, key, sz); \
+ pre ## _ofbsetiv(ctx, iv ? iv : zero); \
+} \
+ \
+/* --- @pre_ofbencrypt@ --- * \
+ * \
+ * Arguments: @pre_ofbctx *ctx@ = pointer to OFB context block \
+ * @const void *src@ = pointer to source data \
+ * @void *dest@ = pointer to destination data \
+ * @size_t sz@ = size of block to be encrypted \
+ * \
+ * Returns: --- \
+ * \
+ * Use: Encrypts or decrypts a block with a block cipher in OFB \
+ * mode: encryption and decryption are the same in OFB. \
+ * The destination may be null to just churn the feedback \
+ * round for a bit. The source may be null to use the \
+ * cipher as a random data generator. \
+ */ \
+ \
+void pre ## _ofbencrypt(pre ## _ofbctx *ctx, \
+ const void *src, void *dest, \
+ size_t sz) \
+{ \
+ const octet *s = src; \
+ octet *d = dest; \
+ int off = ctx->off; \
+ \
+ /* --- Empty blocks are trivial --- */ \
+ \
+ if (!sz) \
+ return; \
+ \
+ /* --- If I can deal with the block from my buffer, do that --- */ \
+ \
+ if (sz < PRE ## _BLKSZ - off) \
+ goto small; \
+ \
+ /* --- Finish off what's left in my buffer --- */ \
+ \
+ if (!d) \
+ sz -= off; \
+ else { \
+ while (off < PRE ## _BLKSZ) { \
+ register octet x = s ? *s++ : 0; \
+ *d++ = ctx->iv[off++] ^ x; \
+ sz--; \
+ } \
+ } \
+ \
+ /* --- Main encryption loop --- */ \
+ \
+ { \
+ uint32 iv[PRE ## _BLKSZ / 4]; \
+ BLKC_LOAD(PRE, iv, ctx->iv); \
+ \
+ for (;;) { \
+ pre ## _eblk(&ctx->ctx, iv, iv); \
+ if (sz < PRE ## _BLKSZ) \
+ break; \
+ if (d) { \
+ if (!s) \
+ BLKC_STORE(PRE, d, iv); \
+ else { \
+ uint32 x[PRE ## _BLKSZ / 4]; \
+ BLKC_LOAD(PRE, x, s); \
+ BLKC_XSTORE(PRE, d, iv, x); \
+ s += PRE ## _BLKSZ; \
+ } \
+ d += PRE ## _BLKSZ; \
+ } \
+ sz -= PRE ## _BLKSZ; \
+ } \
+ \
+ BLKC_STORE(PRE, ctx->iv, iv); \
+ off = 0; \
+ } \
+ \
+ /* --- Tidying up the tail end --- */ \
+ \
+ if (sz) { \
+ small: \
+ if (!d) \
+ off += sz; \
+ else do { \
+ register octet x = s ? *s++ : 0; \
+ *d++ = ctx->iv[off++] ^ x; \
+ sz--; \
+ } while (sz); \
+ } \
+ \
+ /* --- Done --- */ \
+ \
+ ctx->off = off; \
+ return; \
+} \
+ \
+OFB_TEST(PRE, pre)
+
+/*----- Test rig ----------------------------------------------------------*/
+
+#ifdef TEST_RIG
+
+#include <stdio.h>
+
+#include "daftstory.h"
+
+/* --- @OFB_TEST@ --- *
+ *
+ * Arguments: @PRE@, @pre@ = prefixes for block cipher definitions
+ *
+ * Use: Standard test rig for OFB functions.
+ */
+
+#define OFB_TEST(PRE, pre) \
+ \
+/* --- Initial plaintext for the test --- */ \
+ \
+static const octet text[] = TEXT; \
+ \
+/* --- Key and IV to use --- */ \
+ \
+static const octet key[] = KEY; \
+static const octet iv[] = IV; \
+ \
+/* --- Buffers for encryption and decryption output --- */ \
+ \
+static octet ct[sizeof(text)]; \
+static octet pt[sizeof(text)]; \
+ \
+static void hexdump(const octet *p, size_t sz) \
+{ \
+ const octet *q = p + sz; \
+ for (sz = 0; p < q; p++, sz++) { \
+ printf("%02x", *p); \
+ if ((sz + 1) % PRE ## _BLKSZ == 0) \
+ putchar(':'); \
+ } \
+} \
+ \
+int main(void) \
+{ \
+ size_t sz = 0, rest; \
+ pre ## _ofbctx ctx; \
+ int status = 0; \
+ int done = 0; \
+ pre ## _ctx k; \
+ \
+ size_t keysz = PRE ## _KEYSZ ? \
+ PRE ## _KEYSZ : strlen((const char *)key); \
+ \
+ fputs(#pre "-ofb: ", stdout); \
+ \
+ pre ## _init(&k, key, keysz); \
+ pre ## _ofbsetkey(&ctx, &k); \
+ \
+ while (sz <= sizeof(text)) { \
+ rest = sizeof(text) - sz; \
+ memcpy(ct, text, sizeof(text)); \
+ pre ## _ofbsetiv(&ctx, iv); \
+ pre ## _ofbencrypt(&ctx, ct, ct, sz); \
+ pre ## _ofbencrypt(&ctx, ct + sz, ct + sz, rest); \
+ memcpy(pt, ct, sizeof(text)); \
+ pre ## _ofbsetiv(&ctx, iv); \
+ pre ## _ofbencrypt(&ctx, pt, pt, rest); \
+ pre ## _ofbencrypt(&ctx, pt + rest, pt + rest, sz); \
+ if (memcmp(pt, text, sizeof(text)) == 0) { \
+ done++; \
+ if (sizeof(text) < 40 || done % 8 == 0) \
+ fputc('.', stdout); \
+ if (done % 480 == 0) \
+ fputs("\n\t", stdout); \
+ fflush(stdout); \
+ } else { \
+ printf("\nError (sz = %lu)\n", (unsigned long)sz); \
+ status = 1; \
+ printf("\tplaintext = "); hexdump(text, sz); \
+ printf(", "); hexdump(text + sz, rest); \
+ fputc('\n', stdout); \
+ printf("\tciphertext = "); hexdump(ct, sz); \
+ printf(", "); hexdump(ct + sz, rest); \
+ fputc('\n', stdout); \
+ printf("\trecovered text = "); hexdump(pt, sz); \
+ printf(", "); hexdump(pt + sz, rest); \
+ fputc('\n', stdout); \
+ fputc('\n', stdout); \
+ } \
+ if (sz < 63) \
+ sz++; \
+ else \
+ sz += 9; \
+ } \
+ \
+ fputs(status ? " failed\n" : " ok\n", stdout); \
+ return (status); \
+}
+
+#else
+# define OFB_TEST(PRE, pre)
+#endif
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
--- /dev/null
+rand.aux
+rand.dvi
+rand.log
+rand.toc
--- /dev/null
+%%% -*-latex-*-
+%%%
+%%% $Id: rand.tex,v 1.1 1999/09/03 08:41:13 mdw Exp $
+%%%
+%%% Description of Catacomb's random number generator
+%%%
+%%% (c) 1999 Straylight/Edgeware
+%%%
+
+%%%----- Licensing notice ---------------------------------------------------
+%%%
+%%% This file is part of Catacomb.
+%%%
+%%% Catacomb is free software; you can redistribute it and/or modify
+%%% it under the terms of the GNU Library General Public License as
+%%% published by the Free Software Foundation; either version 2 of the
+%%% License, or (at your option) any later version.
+%%%
+%%% Catacomb 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 Library General Public License for more details.
+%%%
+%%% You should have received a copy of the GNU Library General Public
+%%% License along with Catacomb; if not, write to the Free
+%%% Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+%%% MA 02111-1307, USA.
+
+%%%----- Revision history ---------------------------------------------------
+%%%
+%%% $Log: rand.tex,v $
+%%% Revision 1.1 1999/09/03 08:41:13 mdw
+%%% Initial import.
+%%%
+
+%%%----- Header -------------------------------------------------------------
+
+\documentclass[a4paper, article, 10pt, notitlepage, numbering]{strayman}
+\usepackage[palatino, helvetica, courier, maths=cmr]{mdwfonts}
+\usepackage{mdwtab, mathenv}
+\usepackage[T1]{fontenc}
+\usepackage{cmtt, url}
+\usepackage[tpic, all]{xy}
+\usepackage{mathbbol}
+% \usepackage{crypto}
+
+\def\mdw{{\normalfont[{\bfseries\itshape mdw}]}}
+\urlstyle{tt}
+\def\email{\begingroup\urlstyle{rm}\Url}
+\urldef\myemail\email{mdw@nsict.org}
+\def\Z{\mathbb{Z}}
+\let\assign\leftarrow
+\let\xor\oplus
+\let\bigxor\bigoplus
+
+\title{The Catacomb random number generator}
+\author{Mark Wooding, \myemail}
+
+%%%----- The main document --------------------------------------------------
+
+\begin{document}
+
+\maketitle
+
+\begin{abstract}
+ The author describes the random number generator used in the
+ Straylight/\-Edgeware `Catacomb' library. While the generator is
+ superficially similar to (for example) the Linux and OpenBSD random number
+ generators, it introduces a number of its own innovations which improve
+ both security and performance.
+
+ The Catacomb generator uses an optional secret key, which can provide
+ additional security against forward state compromise extension. It uses a
+ catastrophic reseeding operation to prevent a compromise yielding
+ information about past generator states. This operation works on
+ arbitrary-sized blocks of data, so the generator's output buffer can be
+ large. This minimizes the effect of the reseeding overhead.
+\end{abstract}
+
+\tableofcontents
+
+
+\section{The one-way transformation}
+
+The most novel part of the generator\footnote{I believe this construction to
+be novel. If I'm wrong, let me know.} is the one-way transformation which is
+used to allow pooled input data to affect the output buffer.
+
+Let $H$ be some collision-resistant hash function, and let $E_k$ be a
+symmetric cipher with key $k$. Then I can define the one-way transformation
+$T$ by
+\[ T(x) = E_{H(x)}(x) \]
+
+I believe, although formal proof seems difficult, that an adversary in
+posession of $T(x)$ and a portion of the original $x$ cannot reconstruct the
+remainder of $x$ without breaking one of the cryptographic primitives (which
+I assume is `difficult') or performing an exhaustive search of one of: the
+space of the unknown portion of $x$, the range of the hash function $H$, or
+the keyspace of the cipher $E$.
+
+A similar feat of cryptanalysis or exhaustive search seems necessary to work
+in a forwards direction: given partial knowledge of both $x$ and $T(x)$, the
+adversary cannot work out the remainder of either without trying every
+possibility for one or the other unknown portions, or working through the
+hash- or keyspace.
+
+A keyed version of $T$ may be defined, given a keyed hash (or MAC) $H_k$:
+\[ T_k(x) = E_{H_k(x)}(x) \]
+If this is done, the adversary cannot work forwards even with \emph{complete}
+knowledge of $B$, or performing one of the obvious exhaustive searches.
+
+
+\section{Description of the generator}
+
+The generator is divided into two parts: an \emph{input pool} which
+accumulates random input data from the environment, and an \emph{output
+buffer} which contains data to be passed to clients of the generator on
+request.
+
+New information is contributed to the generator by mixing it with the input
+pool, using a mixing function derived from the Linux random number generator
+\cite{linux:devrandom}. The mixing function views the input pool as eight
+parallel shift registers. Input data is added one octet at a time. Each bit
+of an input octet is mixed with a different shift register.
+
+Formally, let $I$ be the input pool, with size $n_I$ bytes; let $P(x) = a_0 +
+a_1 x + a_2 x^2 + \cdots + a_{n_I} x^{n_I}$ be a primitive polynomial in
+$\mathrm{GF}(2^{n_I})$ with degree $n_I$; let $i$ be an integer such that $0
+\le i < n_I$, and $r$ be an integer such that $0 \le r < 8$; and let $x$ be
+an input byte. The result of mixing $x$ with the pool $I$ is calculated as
+follows:
+\begin{eqlines*}
+ \begin{spliteqn*}
+ I'[8j + b] =
+ \begin{cases}
+ x\bigl[(r + b) \bmod 8\bigr] \xor
+ \bigxor_{0 \le k < n_I}
+ a_k I\bigl[8\bigl((j + k) \bmod n_I\bigr) + b\bigr] & if $i = j$ \\
+ I[j + b] & otherwise
+ \end{cases} \\
+ \textrm{for all integers $j$ and $b$ where $0 \le j < n_I$ and
+ $0 \le b < 8$}
+ \end{spliteqn*}
+ \\
+ I \assign I' \qquad
+ i \assign (i + 1) \bmod n_I \qquad
+ r \assign (r + 5) \bmod 8
+\end{eqlines*}
+Initially, $i$ and $r$ are both zero. The use of 8-bit bytes above is
+arbitrary.
+
+Newly added data doesn't affect the output buffer until a `gating' operation
+is performed. This uses the one-way transformation described earlier over
+the entire generator state.
+
+Data requested by clients of the generator is read from the output buffer
+$O$. Initially the buffer contains zeroes.
+
+\begin{thebibliography}{99}
+
+\bibitem{cp:rand}
+ J.~Kelsey, B.~Schneier, D.~Wagner, and C.~Hall, ``Cryptographic Attacks on
+ Pseudorandom Number Generators'', \emph{Fast Software Encryption, Fifth
+ International Workshop Proceedings (March 1998)}, Springer-Verlag, 1998,
+ pp. 168--188, \url{http://www.counterpane.com/pseudorandom_number.html}
+
+\bibitem{linux:devrandom}
+ T.~Ts'o, ``A string random number generator'', Linux sources,
+ \path{drivers/char/random.c}.
+
+\bibitem{mdw:devrandom}
+ M.~Wooding, ``Linux \path{/dev/random} generator security'', Usenet article
+ posted to \mtt{sci.crypt}, July 1998.
+
+\end{thebibliography}
+
+%%%----- That's all, folks --------------------------------------------------
+
+\end{document}
\ No newline at end of file
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: paranoia.h,v 1.1 1999/09/03 08:41:12 mdw Exp $
+ *
+ * Macros and functions for cryptographic paranoia
+ *
+ * (c) 1998 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: paranoia.h,v $
+ * Revision 1.1 1999/09/03 08:41:12 mdw
+ * Initial import.
+ *
+ */
+
+#ifndef PARANOIA_H
+#define PARANOIA_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <string.h>
+
+/*----- Macros ------------------------------------------------------------*/
+
+#define BURN(x) (memset(&(x), 0, sizeof(x)))
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: rand.c,v 1.1 1999/09/03 08:41:12 mdw Exp $
+ *
+ * Secure random number generator
+ *
+ * (c) 1998 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: rand.c,v $
+ * Revision 1.1 1999/09/03 08:41:12 mdw
+ * Initial import.
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stdio.h>
+#include <string.h>
+
+#include <mLib/bits.h>
+
+#include "blowfish-cbc.h"
+#include "paranoia.h"
+#include "rand.h"
+#include "rmd160.h"
+#include "rmd160-hmac.h"
+
+/*----- Static variables --------------------------------------------------*/
+
+static rand_pool pool; /* Default random pool */
+
+/*----- Macros ------------------------------------------------------------*/
+
+#define RAND_RESOLVE(r) do { \
+ if ((r) == RAND_GLOBAL) \
+ (r) = &pool; \
+} while (0)
+
+#define TIMER(r) do { \
+ if ((r)->s && (r)->s->timer) \
+ (r)->s->timer(r); \
+} while (0)
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @rand_init@ --- *
+ *
+ * Arguments: @rand_pool *r@ = pointer to a randomness pool
+ *
+ * Returns: ---
+ *
+ * Use: Initializes a randomness pool. The pool doesn't start out
+ * very random: that's your job to sort out.
+ */
+
+void rand_init(rand_pool *r)
+{
+ RAND_RESOLVE(r);
+ memset(r->pool, 0, sizeof(r->pool));
+ memset(r->buf, 0, sizeof(r->buf));
+ r->i = 0;
+ r->irot = 0;
+ r->ibits = r->obits = 0;
+ r->o = RAND_SECSZ;
+ r->s = 0;
+ rmd160_hmac(&r->k, 0, 0);
+ rand_gate(r);
+}
+
+/* --- @rand_noisesrc@ --- *
+ *
+ * Arguments: @rand_pool *r@ = pointer to a randomness pool
+ * @const rand_source *s@ = pointer to source definition
+ *
+ * Returns: ---
+ *
+ * Use: Sets a noise source for a randomness pool. When the pool's
+ * estimate of good random bits falls to zero, the @getnoise@
+ * function is called, passing the pool handle as an argument.
+ * It is expected to increase the number of good bits by at
+ * least one, because it'll be called over and over again until
+ * there are enough bits to satisfy the caller. The @timer@
+ * function is called frequently throughout the generator's
+ * operation.
+ */
+
+void rand_noisesrc(rand_pool *r, const rand_source *s)
+{
+ RAND_RESOLVE(r);
+ r->s = s;
+}
+
+/* --- @rand_key@ --- *
+ *
+ * Arguments: @rand_pool *r@ = pointer to a randomness pool
+ * @const void *k@ = pointer to key data
+ * @size_t sz@ = size of key data
+ *
+ * Returns: ---
+ *
+ * Use: Sets the secret key for a randomness pool. The key is used
+ * when mixing in new random bits.
+ */
+
+void rand_key(rand_pool *r, const void *k, size_t sz)
+{
+ RAND_RESOLVE(r);
+ rmd160_hmac(&r->k, k, sz);
+}
+
+/* --- @rand_add@ --- *
+ *
+ * Arguments: @rand_pool *r@ = pointer to a randomness pool
+ * @const void *p@ = pointer a buffer of data to add
+ * @size_t sz@ = size of the data buffer
+ * @unsigned goodbits@ = number of good bits estimated in buffer
+ *
+ * Returns: ---
+ *
+ * Use: Mixes the data in the buffer with the contents of the
+ * pool. The estimate of the number of good bits is added to
+ * the pool's own count. The mixing operation is not
+ * cryptographically strong. However, data in the input pool
+ * isn't output directly, only through the one-way gating
+ * operation, so that shouldn't matter.
+ */
+
+void rand_add(rand_pool *r, const void *p, size_t sz, unsigned goodbits)
+{
+ const octet *c = p;
+ int i, rot, mid;
+
+#if RAND_POOLSZ != 1279
+# error Polynomial in rand_add is out of date. Fix it.
+#endif
+
+ RAND_RESOLVE(r);
+
+ i = r->i; rot = r->irot; mid = i + 418;
+ if (mid >= RAND_POOLSZ) mid -= RAND_POOLSZ;
+
+ while (sz) {
+ octet o = *c++;
+ r->pool[i] ^= (ROL8(o, rot) ^ r->pool[mid]);
+ rot = (rot + 5) & 7;
+ i++; if (i >= RAND_POOLSZ) i -= RAND_POOLSZ;
+ mid++; if (mid >= RAND_POOLSZ) mid -= RAND_POOLSZ;
+ sz--;
+ }
+
+ r->i = i;
+ r->irot = rot;
+ r->ibits += goodbits;
+ if (r->ibits > RAND_IBITS)
+ r->ibits = RAND_IBITS;
+}
+
+/* --- @rand_goodbits@ --- *
+ *
+ * Arguments: @rand_pool *r@ = pointer to a randomness pool
+ *
+ * Returns: Estimate of the number of good bits remaining in the pool.
+ */
+
+unsigned rand_goodbits(rand_pool *r)
+{
+ RAND_RESOLVE(r);
+ return (r->ibits + r->obits);
+}
+
+/* --- @rand_gate@ --- *
+ *
+ * Arguments: @rand_pool *r@ = pointer to a randomness pool
+ *
+ * Returns: ---
+ *
+ * Use: Mixes up the entire state of the generator in a nonreversible
+ * way.
+ */
+
+void rand_gate(rand_pool *r)
+{
+ octet mac[RMD160_HASHSZ];
+
+ RAND_RESOLVE(r);
+ TIMER(r);
+
+ /* --- Hash up all the data in the pool --- */
+
+ {
+ rmd160_macctx mc;
+
+ rmd160_macinit(&mc, &r->k);
+ rmd160_mac(&mc, r->pool, sizeof(r->pool));
+ rmd160_mac(&mc, r->buf, sizeof(r->buf));
+ rmd160_macdone(&mc, mac);
+ BURN(mc);
+ }
+
+ /* --- Now mangle all of the data based on the hash --- */
+
+ {
+ blowfish_cbcctx bc;
+
+ blowfish_cbcinit(&bc, mac, sizeof(mac), 0);
+ blowfish_cbcencrypt(&bc, r->pool, r->pool, sizeof(r->pool));
+ blowfish_cbcencrypt(&bc, r->buf, r->buf, sizeof(r->buf));
+ BURN(bc);
+ }
+
+ /* --- Reset the various state variables --- */
+
+ r->o = RAND_SECSZ;
+ r->obits += r->ibits;
+ if (r->obits > RAND_OBITS) {
+ r->ibits = r->obits - r->ibits;
+ r->obits = RAND_OBITS;
+ } else
+ r->ibits = 0;
+ TIMER(r);
+}
+
+/* --- @rand_stretch@ --- *
+ *
+ * Arguments: @rand_pool *r@ = pointer to a randomness pool
+ *
+ * Returns: ---
+ *
+ * Use: Stretches the contents of the output buffer by transforming
+ * it in a nonreversible way. This doesn't add any entropy
+ * worth speaking about, but it works well enough when the
+ * caller doesn't care about that sort of thing.
+ */
+
+void rand_stretch(rand_pool *r)
+{
+ octet mac[RMD160_HASHSZ];
+
+ RAND_RESOLVE(r);
+ TIMER(r);
+
+ /* --- Hash up all the data in the buffer --- */
+
+ {
+ rmd160_macctx mc;
+
+ rmd160_macinit(&mc, &r->k);
+ rmd160_mac(&mc, r->pool, sizeof(r->pool));
+ rmd160_mac(&mc, r->buf, sizeof(r->buf));
+ rmd160_macdone(&mc, mac);
+ BURN(mc);
+ }
+
+ /* --- Now mangle the buffer based on that hash --- */
+
+ {
+ blowfish_cbcctx bc;
+
+ blowfish_cbcinit(&bc, mac, sizeof(mac), 0);
+ blowfish_cbcencrypt(&bc, r->buf, r->buf, sizeof(r->buf));
+ BURN(bc);
+ }
+
+ /* --- Reset the various state variables --- */
+
+ r->o = RAND_SECSZ;
+ TIMER(r);
+}
+
+/* --- @rand_get@ --- *
+ *
+ * Arguments: @rand_pool *r@ = pointer to a randomness pool
+ * @void *p@ = pointer to output buffer
+ * @size_t sz@ = size of output buffer
+ *
+ * Returns: ---
+ *
+ * Use: Gets random data from the pool. The pool's contents can't be
+ * determined from the output of this function; nor can the
+ * output data be determined from a knowledge of the data input
+ * to the pool wihtout also having knowledge of the secret key.
+ * The good bits counter is decremented, although no special
+ * action is taken if it reaches zero.
+ */
+
+void rand_get(rand_pool *r, void *p, size_t sz)
+{
+ octet *o = p;
+
+ RAND_RESOLVE(r);
+ TIMER(r);
+
+ if (!sz)
+ return;
+ for (;;) {
+ if (r->o + sz <= RAND_BUFSZ) {
+ memcpy(o, r->buf + r->o, sz);
+ r->o += sz;
+ break;
+ } else {
+ size_t chunk = RAND_BUFSZ - r->o;
+ if (chunk) {
+ memcpy(o, r->buf + r->o, chunk);
+ sz -= chunk;
+ o += chunk;
+ }
+ rand_stretch(r);
+ }
+ }
+
+ if (r->obits > sz * 8)
+ r->obits -= sz * 8;
+ else
+ r->obits = 0;
+}
+
+/* --- @rand_getgood@ --- *
+ *
+ * Arguments: @rand_pool *r@ = pointer to a randomness pool
+ * @void *p@ = pointer to output buffer
+ * @size_t sz@ = size of output buffer
+ *
+ * Returns: ---
+ *
+ * Use: Gets random data from the pool. The pool's contents can't be
+ * determined from the output of this function; nor can the
+ * output data be determined from a knowledge of the data input
+ * to the pool wihtout also having knowledge of the secret key.
+ * If a noise source is attached to the pool in question, it is
+ * called to replenish the supply of good bits in the pool;
+ * otherwise this call is equivalent to @rand_get@.
+ */
+
+void rand_getgood(rand_pool *r, void *p, size_t sz)
+{
+ octet *o = p;
+
+ RAND_RESOLVE(r);
+
+ if (!sz)
+ return;
+ if (!r->s || !r->s->getnoise) {
+ rand_get(r, p, sz);
+ return;
+ }
+ TIMER(r);
+
+ while (sz) {
+ size_t chunk = sz;
+
+ if (chunk * 8 > r->obits) {
+ if (chunk * 8 > r->ibits + r->obits)
+ do r->s->getnoise(r); while (r->ibits + r->obits < 128);
+ rand_gate(r);
+ if (chunk * 8 > r->obits)
+ chunk = r->obits / 8;
+ }
+
+ if (chunk + r->o > RAND_BUFSZ)
+ chunk = RAND_BUFSZ - r->o;
+
+ memcpy(o, r->buf + r->o, chunk);
+ r->obits -= chunk * 8;
+ o += chunk;
+ sz -= chunk;
+ }
+}
+
+/*----- That's all, folks -------------------------------------------------*/
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: rand.h,v 1.1 1999/09/03 08:41:12 mdw Exp $
+ *
+ * Secure random number generator
+ *
+ * (c) 1999 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: rand.h,v $
+ * Revision 1.1 1999/09/03 08:41:12 mdw
+ * Initial import.
+ *
+ */
+
+/*----- Notes on the random number generator ------------------------------*
+ *
+ * The algorithm is one of the author's own devising. It may therefore be
+ * worth a certain amount of skepticism. However, I've thought about this
+ * method for over a year before actually considering it worth implementing.
+ * With a little bit of luck, it should have received some peer review by the
+ * time this code is actually properly released, and it'll be worth a bit
+ * more confidence. My earlier generator was very similar in structure to
+ * the Linux /dev/random device. This generator is intended to address
+ * concerns I expressed about the Linux generator in a Usenet article to
+ * sci.crypt.
+ *
+ * The generator is divided into two parts: an input pool and an outpu
+ * buffer. New random data is placed into the pool in the way described
+ * below, which is shamelessly stolen from the Linux /dev/random generator.
+ * The only interaction that the pool has on the output buffer is through the
+ * keyed `gating' operation, which mixes up and redistributes all of the
+ * generator's state in an irreversible manner. Random bytes, when
+ * requested, are extracted from the output buffer in a linear fashion.
+ *
+ * The input pool is best seen as being eight shift registers in parallel.
+ * Data is added to the pool one octet at a time. Each bit of a new octet is
+ * added to a different shift register, by adding it (mod 2) with other bits
+ * according to the coefficients of a primitive polynomial. Each new byte is
+ * rotated before being added into the pool, in a half-hearted attempt to
+ * protect against biases in the input data (e.g., top bits being clear on
+ * ASCII text).
+ *
+ * The gating operation takes a keyed hash of the entire generator state,
+ * uses it as the key for a symmetric cipher, and encrypts the state. The
+ * key is then discarded. The result is that every ouptut bit of the
+ * operation depends in a complex way on every input bit, but the operation
+ * cannot be reversed.
+ *
+ * As an added wrinkle, 160 bits of the output buffer are never actually
+ * output. They are used in the gating operation only, as an extra item that
+ * an adversary has to guess before predicting generator output.
+ */
+
+#ifndef RAND_H
+#define RAND_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <stddef.h>
+
+#include "rmd160-hmac.h"
+
+/*----- Magic numbers -----------------------------------------------------*/
+
+#define RAND_POOLSZ 1279 /* Input pool size in bytes */
+#define RAND_BUFSZ 1024 /* Output buffer size in bytes */
+#define RAND_SECSZ 20 /* Secret octets in output buffer */
+
+#define RAND_IBITS (RAND_POOLSZ * 8)
+#define RAND_OBITS (RAND_BUFSZ * 8)
+
+/*----- Data structures ---------------------------------------------------*/
+
+/* --- A random number generator pool --- */
+
+typedef struct rand_pool {
+ octet pool[RAND_POOLSZ]; /* Actual contents of the pool */
+ unsigned i; /* Current index into pool */
+ unsigned irot; /* Current rotation applied */
+ unsigned ibits; /* Number of good bits in pool */
+ octet buf[RAND_BUFSZ]; /* Random octet output buffer */
+ unsigned o; /* Current index into buffer */
+ unsigned obits; /* Number of good bits in buffer */
+ rmd160_mackey k; /* Secret key for this pool */
+ const struct rand_source *s; /* System-specific noise source */
+} rand_pool;
+
+#define RAND_GLOBAL ((rand_pool *)0) /* The global randomness pool */
+
+/* --- A noise source --- */
+
+typedef struct rand_source {
+ void (*getnoise)(rand_pool */*r*/); /* Acquire more noise */
+ int (*timer)(rand_pool */*r*/); /* Get noise from current time */
+} rand_source;
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @rand_init@ --- *
+ *
+ * Arguments: @rand_pool *r@ = pointer to a randomness pool
+ *
+ * Returns: ---
+ *
+ * Use: Initializes a randomness pool. The pool doesn't start out
+ * very random: that's your job to sort out.
+ */
+
+extern void rand_init(rand_pool */*r*/);
+
+/* --- @rand_noisesrc@ --- *
+ *
+ * Arguments: @rand_pool *r@ = pointer to a randomness pool
+ * @const rand_source *s@ = pointer to source definition
+ *
+ * Returns: ---
+ *
+ * Use: Sets a noise source for a randomness pool. When the pool's
+ * estimate of good random bits falls to zero, the @getnoise@
+ * function is called, passing the pool handle as an argument.
+ * It is expected to increase the number of good bits by at
+ * least one, because it'll be called over and over again until
+ * there are enough bits to satisfy the caller. The @timer@
+ * function is called frequently throughout the generator's
+ * operation.
+ */
+
+extern void rand_noisesrc(rand_pool */*r*/, const rand_source */*s*/);
+
+/* --- @rand_key@ --- *
+ *
+ * Arguments: @rand_pool *r@ = pointer to a randomness pool
+ * @const void *k@ = pointer to key data
+ * @size_t sz@ = size of key data
+ *
+ * Returns: ---
+ *
+ * Use: Sets the secret key for a randomness pool. The key is used
+ * when mixing in new random bits.
+ */
+
+extern void rand_key(rand_pool */*r*/, const void */*k*/, size_t /*sz*/);
+
+/* --- @rand_add@ --- *
+ *
+ * Arguments: @rand_pool *r@ = pointer to a randomness pool
+ * @const void *p@ = pointer a buffer of data to add
+ * @size_t sz@ = size of the data buffer
+ * @unsigned goodbits@ = number of good bits estimated in buffer
+ *
+ * Returns: ---
+ *
+ * Use: Mixes the data in the buffer with the contents of the
+ * pool. The estimate of the number of good bits is added to
+ * the pool's own count. The mixing operation is not
+ * cryptographically strong. However, data in the input pool
+ * isn't output directly, only through the one-way gating
+ * operation, so that shouldn't matter.
+ */
+
+extern void rand_add(rand_pool */*r*/,
+ const void */*p*/, size_t /*sz*/,
+ unsigned /*goodbits*/);
+
+/* --- @rand_goodbits@ --- *
+ *
+ * Arguments: @rand_pool *r@ = pointer to a randomness pool
+ *
+ * Returns: Estimate of the number of good bits remaining in the pool.
+ */
+
+extern unsigned rand_goodbits(rand_pool */*r*/);
+
+/* --- @rand_gate@ --- *
+ *
+ * Arguments: @rand_pool *r@ = pointer to a randomness pool
+ *
+ * Returns: ---
+ *
+ * Use: Mixes up the entire state of the generator in a nonreversible
+ * way.
+ */
+
+extern void rand_gate(rand_pool */*r*/);
+
+/* --- @rand_stretch@ --- *
+ *
+ * Arguments: @rand_pool *r@ = pointer to a randomness pool
+ *
+ * Returns: ---
+ *
+ * Use: Stretches the contents of the output buffer by transforming
+ * it in a nonreversible way. This doesn't add any entropy
+ * worth speaking about, but it works well enough when the
+ * caller doesn't care about that sort of thing.
+ */
+
+extern void rand_stretch(rand_pool */*r*/);
+
+/* --- @rand_get@ --- *
+ *
+ * Arguments: @rand_pool *r@ = pointer to a randomness pool
+ * @void *p@ = pointer to output buffer
+ * @size_t sz@ = size of output buffer
+ *
+ * Returns: ---
+ *
+ * Use: Gets random data from the pool. The pool's contents can't be
+ * determined from the output of this function; nor can the
+ * output data be determined from a knowledge of the data input
+ * to the pool wihtout also having knowledge of the secret key.
+ * The good bits counter is decremented, although no special
+ * action is taken if it reaches zero.
+ */
+
+extern void rand_get(rand_pool */*r*/, void */*p*/, size_t /*sz*/);
+
+/* --- @rand_getgood@ --- *
+ *
+ * Arguments: @rand_pool *r@ = pointer to a randomness pool
+ * @void *p@ = pointer to output buffer
+ * @size_t sz@ = size of output buffer
+ *
+ * Returns: ---
+ *
+ * Use: Gets random data from the pool. The pool's contents can't be
+ * determined from the output of this function; nor can the
+ * output data be determined from a knowledge of the data input
+ * to the pool wihtout also having knowledge of the secret key.
+ * If a noise source is attached to the pool in question, it is
+ * called to replenish the supply of good bits in the pool;
+ * otherwise this call is equivalent to @rand_get@.
+ */
+
+extern void rand_getgood(rand_pool */*r*/, void */*p*/, size_t /*sz*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: rc4.c,v 1.1 1999/09/03 08:41:12 mdw Exp $
+ *
+ * The alleged RC4 stream cipher
+ *
+ * (c) 1999 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: rc4.c,v $
+ * Revision 1.1 1999/09/03 08:41:12 mdw
+ * Initial import.
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <assert.h>
+#include <stdio.h>
+
+#include <mLib/bits.h>
+
+#include "rc4.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @rc4_init@ --- *
+ *
+ * Arguments: @rc4_ctx *ctx@ = pointer to context to initialize
+ * @const void *k@ = pointer to key data to use
+ * @size_t sz@ = size of the key data
+ *
+ * Returns: ---
+ *
+ * Use: Initializes an RC4 context ready for use.
+ */
+
+void rc4_init(rc4_ctx *ctx, const void *k, size_t sz)
+{
+ unsigned i, j;
+ const octet *p = k, *q = p + sz;
+
+ assert(((void)"RC4 does not support zero length keys", sz != 0));
+
+ for (i = 0; i < 256; i++)
+ ctx->s[i] = i;
+ ctx->f = 0;
+ ctx->i = ctx->j = 0;
+
+ for (i = j = 0; i < 256; i++) {
+ unsigned si = ctx->s[i];
+ j = (j + si + *p++) & 0xff;
+ ctx->s[i] = ctx->s[j];
+ ctx->s[j] = si;
+ if (p == q)
+ p = k;
+ }
+
+#ifdef notdef
+ for (i = 0; i < 256; i += 16) {
+ printf("%3d :", i);
+ for (j = i; j < i + 16; j++)
+ printf(" %02x", ctx->s[j]);
+ putchar('\n');
+ }
+#endif
+}
+
+/* --- @rc4_encrypt@ --- *
+ *
+ * Arguments: @rc4_ctx *ctx@ = pointer to context to use
+ * @const void *src@ = pointer to the source block
+ * @void *dest@ = pointer to the destination block
+ * @size_t sz@ = size of the block
+ *
+ * Returns: ---
+ *
+ * Use: Encrypts or decrypts a block of data. The destination may
+ * be null to just grind the generator around for a while. It's
+ * recommended that you say `@rc4_encrypt(&ctx, 0, 0, 1024)@'
+ * after initializing a new context, to prevent keystream
+ * guessing attacks. The source may be null to just extract a
+ * big lump of data from the generator.
+ */
+
+void rc4_encrypt(rc4_ctx *ctx, const void *src, void *dest, size_t sz)
+{
+ const octet *s = src;
+ octet *d = dest;
+
+ if (!d)
+ RC4_OPEN(ctx, while (sz) { unsigned x; RC4_BYTE(x); sz--; });
+ else if (!s)
+ RC4_OPEN(ctx, while (sz) { RC4_BYTE(*d++); sz--; });
+ else
+ RC4_OPEN(ctx,
+ while (sz) { unsigned x; RC4_BYTE(x); *d++ = *s++ ^ x; sz--; });
+}
+
+/*----- Test rig ----------------------------------------------------------*/
+
+#ifdef TEST_RIG
+
+#include <stdio.h>
+#include <string.h>
+
+#include <mLib/quis.h>
+#include <mLib/testrig.h>
+
+static int v_encrypt(dstr *v)
+{
+ rc4_ctx ctx;
+ dstr d = DSTR_INIT;
+ int ok = 1;
+
+ rc4_init(&ctx, v[0].buf, v[0].len);
+ dstr_ensure(&d, v[1].len);
+ d.len = v[1].len;
+ rc4_encrypt(&ctx, v[1].buf, d.buf, d.len);
+
+ if (memcmp(v[2].buf, d.buf, d.len) != 0) {
+ ok = 0;
+ printf("\nfail encryption:"
+ "\n\tkey = ");
+ type_hex.dump(&v[0], stdout);
+ printf("\n\tplaintext = "); type_hex.dump(&v[1], stdout);
+ printf("\n\texpected = "); type_hex.dump(&v[2], stdout);
+ printf("\n\tcalculated = "); type_hex.dump(&d, stdout);
+ putchar('\n');
+ }
+
+ return (ok);
+}
+
+static int v_generate(dstr *v)
+{
+ rc4_ctx ctx;
+ dstr d = DSTR_INIT;
+ int ok = 1;
+
+ rc4_init(&ctx, v[0].buf, v[0].len);
+ rc4_encrypt(&ctx, 0, 0, *(int *)v[1].buf);
+ dstr_ensure(&d, v[2].len);
+ d.len = v[2].len;
+ rc4_encrypt(&ctx, 0, d.buf, d.len);
+
+ if (memcmp(v[2].buf, d.buf, d.len) != 0) {
+ ok = 0;
+ printf("\nfail generation:"
+ "\n\tkey = ");
+ type_hex.dump(&v[0], stdout);
+ printf("\n\tskip len = %i", *(int *)v[1].buf);
+ printf("\n\texpected = "); type_hex.dump(&v[2], stdout);
+ printf("\n\tcalculated = "); type_hex.dump(&d, stdout);
+ putchar('\n');
+ }
+
+ return (ok);
+}
+
+static test_chunk defs[] = {
+ { "rc4-encrypt", v_encrypt, { &type_hex, &type_hex, &type_hex, 0 } },
+ { "rc4-generate", v_generate, { &type_hex, &type_int, &type_hex, 0 } },
+ { 0, 0, { 0 } }
+};
+
+int main(int argc, char *argv[])
+{
+ test_run(argc, argv, defs, SRCDIR"/tests/rc4");
+ return (0);
+}
+
+#endif
+
+/*----- That's all, folks -------------------------------------------------*/
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: rc4.h,v 1.1 1999/09/03 08:41:12 mdw Exp $
+ *
+ * The alleged RC4 stream cipher
+ *
+ * (c) 1999 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: rc4.h,v $
+ * Revision 1.1 1999/09/03 08:41:12 mdw
+ * Initial import.
+ *
+ */
+
+/*----- Notes on RC4 ------------------------------------------------------*
+ *
+ * RC4 is a stream cipher desgigned by Ron Rivest. For a while RC4 was a
+ * trade secret of RSA Data Security, Inc., but somehow source code for a
+ * cipher which interworks with RC4 was posted to the Cypherpunks mailing
+ * list.
+ */
+
+#ifndef RC4_H
+#define RC4_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <assert.h>
+
+#include <mLib/bits.h>
+
+/*----- Data structures ---------------------------------------------------*/
+
+typedef struct rc4_ctx {
+ unsigned i, j; /* Indices into the @S@ table */
+ unsigned f; /* Flags word */
+ octet s[256]; /* The ever-changing @S@ table */
+} rc4_ctx;
+
+#define RC4F_OPEN 1u
+
+/*----- Macros ------------------------------------------------------------*/
+
+/* --- @RC4_OPEN@ --- *
+ *
+ * Arguments: @ctx@ = pointer to an RC4 context
+ * @guts@ = code to perform within the RC4 context
+ *
+ * Use: Performs some code within an RC4 context. Some of the
+ * parameters are extracted from the context and held in local
+ * variables for speed. Multiple calls to @RC4_BYTE@ may be
+ * made within the open context. A context must only be
+ * opened once at a time.
+ */
+
+#define RC4_OPEN(ctx, guts) do { \
+ unsigned _rc4_i = (ctx)->i; \
+ unsigned _rc4_j = (ctx)->j; \
+ octet *_rc4_s = (ctx)->s; \
+ \
+ assert(((void)"RC4 context may only be opened once at a time", \
+ ((ctx)->f & RC4F_OPEN) == 0)); \
+ (ctx)->f |= RC4F_OPEN; \
+ \
+ guts \
+ \
+ (ctx)->f &= ~RC4F_OPEN; \
+ (ctx)->i = _rc4_i; \
+ (ctx)->j = _rc4_j; \
+} while (0)
+
+/* --- @RC4_BYTE@ --- *
+ *
+ * Arguments: @x@ = output variable to set
+ *
+ * Use: Extracts an octet from the lexically innermost open RC4
+ * context and places it in the variable @x@.
+ */
+
+#define RC4_BYTE(x) do { \
+ unsigned _si, _sj; \
+ _rc4_i = (_rc4_i + 1) & 0xff; \
+ _si = _rc4_s[_rc4_i]; \
+ _rc4_j = (_rc4_j + _si) & 0xff; \
+ _sj = _rc4_s[_rc4_j]; \
+ _rc4_s[_rc4_i] = _sj; \
+ _rc4_s[_rc4_j] = _si; \
+ (x) = _rc4_s[(_si + _sj) & 0xff]; \
+} while (0)
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @rc4_init@ --- *
+ *
+ * Arguments: @rc4_ctx *ctx@ = pointer to context to initialize
+ * @const void *k@ = pointer to key data to use
+ * @size_t sz@ = size of the key data
+ *
+ * Returns: ---
+ *
+ * Use: Initializes an RC4 context ready for use.
+ */
+
+extern void rc4_init(rc4_ctx */*ctx*/, const void */*k*/, size_t /*sz*/);
+
+/* --- @rc4_encrypt@ --- *
+ *
+ * Arguments: @rc4_ctx *ctx@ = pointer to context to use
+ * @const void *src@ = pointer to the source block
+ * @void *dest@ = pointer to the destination block
+ * @size_t sz@ = size of the block
+ *
+ * Returns: ---
+ *
+ * Use: Encrypts or decrypts a block of data. The destination may
+ * be null to just grind the generator around for a while. It's
+ * recommended that you say `@rc4_encrypt(&ctx, 0, 0, 1024)@'
+ * after initializing a new context, to prevent keystream
+ * guessing attacks. The source may be null to just extract a
+ * big lump of data from the generator.
+ */
+
+extern void rc4_encrypt(rc4_ctx */*ctx*/,
+ const void */*src*/, void */*dest*/,
+ size_t /*sz*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: rc5.c,v 1.1 1999/09/03 08:41:12 mdw Exp $
+ *
+ * The RC5-32/12 block cipher
+ *
+ * (c) 1999 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: rc5.c,v $
+ * Revision 1.1 1999/09/03 08:41:12 mdw
+ * Initial import.
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <mLib/alloc.h>
+#include <mLib/bits.h>
+
+#include "blkc.h"
+#include "rc5.h"
+
+/*----- Internal magical constants ----------------------------------------*/
+
+#define RC5_ROUNDS 12
+
+#define T ((RC5_ROUNDS + 1) * 2)
+#define P 0xb7e15163
+#define Q 0x9e3779b9
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @rc5_init@ --- *
+ *
+ * Arguments: @rc5_ctx *k@ = pointer to a key block
+ * @const void *sbuf@ = pointer to key material
+ * @size_t sz@ = size of the key material
+ *
+ * Returns: ---
+ *
+ * Use: Initializes an RC5 key block.
+ */
+
+void rc5_init(rc5_ctx *k, const void *sbuf, size_t sz)
+{
+ uint32 *l;
+ size_t w;
+
+ /* --- Set up the @L@ table --- *
+ *
+ * This is slightly unfortunately defined.
+ */
+
+ assert(((void)"RC5 does not support zero-length keys", sz != 0));
+
+ {
+ int i;
+ const octet *p = sbuf;
+
+ /* --- Create the buffer --- */
+
+ w = (sz + 3) / 4;
+ l = xmalloc(w * sizeof(uint32));
+
+ /* --- Extract the key material --- */
+
+ for (i = 0; sz > 3; i++) {
+ l[i] = LOAD32_L(p);
+ p += 4;
+ sz -= 4;
+ }
+
+ /* --- Fix up the tail end --- */
+
+ if (sz) {
+ uint32 x = U8(*p++);
+ if (sz > 1) x |= (U8(*p++) << 8);
+ if (sz > 2) x |= (U8(*p++) << 16);
+ l[i] = x;
+ }
+ }
+
+ /* --- Initialize the @S@ table --- */
+
+ {
+ int i;
+
+ k->s[0] = P;
+ for (i = 1; i < T; i++)
+ k->s[i] = k->s[i - 1] + Q;
+ }
+
+ /* --- Mix in the key --- */
+
+ {
+ int m = 3 * (w > T ? w : T);
+ int i, j, c;
+ uint32 a, b;
+
+ for (c = i = j = a = b = 0; c < m; c++) {
+ uint32 x;
+
+ x = k->s[i] + a + b;
+ k->s[i] = a = ROL32(x, 3);
+ i++; if (i >= T) i = 0;
+
+ x = l[j] + a + b;
+ l[j] = b = ROL32(x, a + b);
+ j++; if (j >= w) j = 0;
+ }
+ }
+
+ free(l);
+}
+
+/* --- @EROUND@, @DROUND@ --- */
+
+#define EROUND(x, y, k) do { \
+ uint32 _x; \
+ _x = x ^ y; x = ROL32(_x, y) + k[0]; \
+ _x = y ^ x; y = ROL32(_x, x) + k[1]; \
+ k += 2; \
+} while (0)
+
+#define DROUND(x, y, k) do { \
+ uint32 _x; \
+ k -= 2; \
+ _x = y - k[1]; y = ROR32(_x, x) ^ x; \
+ _x = x - k[0]; x = ROR32(_x, y) ^ y; \
+} while (0)
+
+/* --- @EBLK@, @DBLK@ --- */
+
+#define EBLK(a, b, c, d, k) do { \
+ uint32 _l, _r; \
+ const uint32 *_k = (k)->s; \
+ \
+ _l = (a) + _k[0]; \
+ _r = (b) + _k[1]; \
+ _k += 2; \
+ \
+ EROUND(_l, _r, _k); \
+ EROUND(_l, _r, _k); \
+ EROUND(_l, _r, _k); \
+ EROUND(_l, _r, _k); \
+ EROUND(_l, _r, _k); \
+ EROUND(_l, _r, _k); \
+ EROUND(_l, _r, _k); \
+ EROUND(_l, _r, _k); \
+ EROUND(_l, _r, _k); \
+ EROUND(_l, _r, _k); \
+ EROUND(_l, _r, _k); \
+ EROUND(_l, _r, _k); \
+ (c) = _l; \
+ (d) = _r; \
+} while (0)
+
+#define DBLK(a, b, c, d, k) do { \
+ uint32 _l, _r; \
+ const uint32 *_k = (k)->s + T; \
+ \
+ _l = (a); \
+ _r = (b); \
+ \
+ DROUND(_l, _r, _k); \
+ DROUND(_l, _r, _k); \
+ DROUND(_l, _r, _k); \
+ DROUND(_l, _r, _k); \
+ DROUND(_l, _r, _k); \
+ DROUND(_l, _r, _k); \
+ DROUND(_l, _r, _k); \
+ DROUND(_l, _r, _k); \
+ DROUND(_l, _r, _k); \
+ DROUND(_l, _r, _k); \
+ DROUND(_l, _r, _k); \
+ DROUND(_l, _r, _k); \
+ \
+ _k -= 2; \
+ (d) = _r - _k[1]; \
+ (c) = _l - _k[0]; \
+} while (0)
+
+/* --- @rc5_eblk@, @rc5_dblk@ --- *
+ *
+ * Arguments: @const rc5_ctx *k@ = pointer to RC5 context block
+ * @const uint32 s[2]@ = pointer to source block
+ * @uint32 *d[2]@ = pointer to destination block
+ *
+ * Returns: ---
+ *
+ * Use: Low level block encryption and decryption.
+ */
+
+void rc5_eblk(const rc5_ctx *k, const uint32 *s, uint32 *d)
+{
+ EBLK(s[0], s[1], d[0], d[1], k);
+}
+
+void rc5_dblk(const rc5_ctx *k, const uint32 *s, uint32 *d)
+{
+ DBLK(s[0], s[1], d[0], d[1], k);
+}
+
+/* --- Test rig --- */
+
+BLKC_TEST(RC5, rc5)
+
+/*----- That's all, folks -------------------------------------------------*/
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: rc5.h,v 1.1 1999/09/03 08:41:12 mdw Exp $
+ *
+ * The RC5-32/12 block cipher
+ *
+ * (c) 1999 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: rc5.h,v $
+ * Revision 1.1 1999/09/03 08:41:12 mdw
+ * Initial import.
+ *
+ */
+
+#ifndef RC5_H
+#define RC5_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <mLib/bits.h>
+
+/*----- Magic numbers -----------------------------------------------------*/
+
+#define RC5_ROUNDS 12
+#define RC5_KEYSZ 0
+#define RC5_BLKSZ 8
+#define RC5_CLASS (N, L, 64)
+
+/*----- Data structures ---------------------------------------------------*/
+
+typedef struct rc5_ctx {
+ uint32 s[2 * (RC5_ROUNDS + 1)];
+} rc5_ctx;
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @rc5_init@ --- *
+ *
+ * Arguments: @rc5_ctx *k@ = pointer to a key block
+ * @const void *sbuf@ = pointer to key material
+ * @size_t sz@ = size of the key material
+ *
+ * Returns: ---
+ *
+ * Use: Initializes an RC5 key block.
+ */
+
+extern void rc5_init(rc5_ctx */*k*/, const void */*sbuf*/, size_t /*sz*/);
+
+/* --- @rc5_eblk@, @rc5_dblk@ --- *
+ *
+ * Arguments: @const rc5_ctx *k@ = pointer to RC5 context block
+ * @const uint32 s[2]@ = pointer to source block
+ * @uint32 *d[2]@ = pointer to destination block
+ *
+ * Returns: ---
+ *
+ * Use: Low level block encryption and decryption.
+ */
+
+extern void rc5_eblk(const rc5_ctx */*k*/,
+ const uint32 */*s*/, uint32 */*d*/);
+extern void rc5_dblk(const rc5_ctx */*k*/,
+ const uint32 */*s*/, uint32 */*d*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: rmd160.c,v 1.1 1999/09/03 08:41:12 mdw Exp $
+ *
+ * The RIPEMD-160 message digest function
+ *
+ * (c) 1998 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: rmd160.c,v $
+ * Revision 1.1 1999/09/03 08:41:12 mdw
+ * Initial import.
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <mLib/bits.h>
+
+#include "hash.h"
+#include "rmd160.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @rmd160_compress@ --- *
+ *
+ * Arguments: @rmd160_ctx *ctx@ = pointer to context block
+ * @const void *sbuf@ = pointer to buffer of appropriate size
+ *
+ * Returns: ---
+ *
+ * Use: RIPEMD-160 compression function.
+ */
+
+void rmd160_compress(rmd160_ctx *ctx, const void *sbuf)
+{
+ uint32 a, b, c, d, e;
+ uint32 A, B, C, D, E;
+ uint32 buf[16];
+
+ /* --- Fetch the chaining variables --- */
+
+ a = A = ctx->a;
+ b = B = ctx->b;
+ c = C = ctx->c;
+ d = D = ctx->d;
+ e = E = ctx->e;
+
+ /* --- Fetch the buffer contents --- */
+
+ {
+ int i;
+ const octet *p;
+
+ for (i = 0, p = sbuf; i < 16; i++, p += 4)
+ buf[i] = LOAD32_L(p);
+ }
+
+ /* --- Definitions for round functions --- */
+
+#define F(x, y, z) ((x) ^ (y) ^ (z))
+#define G(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define H(x, y, z) (((x) | ~(y)) ^ (z))
+#define I(x, y, z) (((x) & (z)) | ((y) & ~(z)))
+#define J(x, y, z) ((x) ^ ((y) | ~(z)))
+
+#define T(v, w, x, y, z, i, r, f, k) do { \
+ uint32 _t = v + f(w, x, y) + buf[i] + k; \
+ v = ROL32(_t, r) + z; x = ROL32(x, 10); \
+} while (0)
+
+#define F1(v, w, x, y, z, i, r) T(v, w, x, y, z, i, r, F, 0x00000000)
+#define G1(v, w, x, y, z, i, r) T(v, w, x, y, z, i, r, G, 0x5a827999)
+#define H1(v, w, x, y, z, i, r) T(v, w, x, y, z, i, r, H, 0x6ed9eba1)
+#define I1(v, w, x, y, z, i, r) T(v, w, x, y, z, i, r, I, 0x8f1bbcdc)
+#define J1(v, w, x, y, z, i, r) T(v, w, x, y, z, i, r, J, 0xa953fd4e)
+
+#define F2(v, w, x, y, z, i, r) T(v, w, x, y, z, i, r, J, 0x50a28be6)
+#define G2(v, w, x, y, z, i, r) T(v, w, x, y, z, i, r, I, 0x5c4dd124)
+#define H2(v, w, x, y, z, i, r) T(v, w, x, y, z, i, r, H, 0x6d703ef3)
+#define I2(v, w, x, y, z, i, r) T(v, w, x, y, z, i, r, G, 0x7a6d76e9)
+#define J2(v, w, x, y, z, i, r) T(v, w, x, y, z, i, r, F, 0x00000000)
+
+ /* --- First the left hand side --- */
+
+ F1(a, b, c, d, e, 0, 11);
+ F1(e, a, b, c, d, 1, 14);
+ F1(d, e, a, b, c, 2, 15);
+ F1(c, d, e, a, b, 3, 12);
+ F1(b, c, d, e, a, 4, 5);
+ F1(a, b, c, d, e, 5, 8);
+ F1(e, a, b, c, d, 6, 7);
+ F1(d, e, a, b, c, 7, 9);
+ F1(c, d, e, a, b, 8, 11);
+ F1(b, c, d, e, a, 9, 13);
+ F1(a, b, c, d, e, 10, 14);
+ F1(e, a, b, c, d, 11, 15);
+ F1(d, e, a, b, c, 12, 6);
+ F1(c, d, e, a, b, 13, 7);
+ F1(b, c, d, e, a, 14, 9);
+ F1(a, b, c, d, e, 15, 8);
+
+ G1(e, a, b, c, d, 7, 7);
+ G1(d, e, a, b, c, 4, 6);
+ G1(c, d, e, a, b, 13, 8);
+ G1(b, c, d, e, a, 1, 13);
+ G1(a, b, c, d, e, 10, 11);
+ G1(e, a, b, c, d, 6, 9);
+ G1(d, e, a, b, c, 15, 7);
+ G1(c, d, e, a, b, 3, 15);
+ G1(b, c, d, e, a, 12, 7);
+ G1(a, b, c, d, e, 0, 12);
+ G1(e, a, b, c, d, 9, 15);
+ G1(d, e, a, b, c, 5, 9);
+ G1(c, d, e, a, b, 2, 11);
+ G1(b, c, d, e, a, 14, 7);
+ G1(a, b, c, d, e, 11, 13);
+ G1(e, a, b, c, d, 8, 12);
+
+ H1(d, e, a, b, c, 3, 11);
+ H1(c, d, e, a, b, 10, 13);
+ H1(b, c, d, e, a, 14, 6);
+ H1(a, b, c, d, e, 4, 7);
+ H1(e, a, b, c, d, 9, 14);
+ H1(d, e, a, b, c, 15, 9);
+ H1(c, d, e, a, b, 8, 13);
+ H1(b, c, d, e, a, 1, 15);
+ H1(a, b, c, d, e, 2, 14);
+ H1(e, a, b, c, d, 7, 8);
+ H1(d, e, a, b, c, 0, 13);
+ H1(c, d, e, a, b, 6, 6);
+ H1(b, c, d, e, a, 13, 5);
+ H1(a, b, c, d, e, 11, 12);
+ H1(e, a, b, c, d, 5, 7);
+ H1(d, e, a, b, c, 12, 5);
+
+ I1(c, d, e, a, b, 1, 11);
+ I1(b, c, d, e, a, 9, 12);
+ I1(a, b, c, d, e, 11, 14);
+ I1(e, a, b, c, d, 10, 15);
+ I1(d, e, a, b, c, 0, 14);
+ I1(c, d, e, a, b, 8, 15);
+ I1(b, c, d, e, a, 12, 9);
+ I1(a, b, c, d, e, 4, 8);
+ I1(e, a, b, c, d, 13, 9);
+ I1(d, e, a, b, c, 3, 14);
+ I1(c, d, e, a, b, 7, 5);
+ I1(b, c, d, e, a, 15, 6);
+ I1(a, b, c, d, e, 14, 8);
+ I1(e, a, b, c, d, 5, 6);
+ I1(d, e, a, b, c, 6, 5);
+ I1(c, d, e, a, b, 2, 12);
+
+ J1(b, c, d, e, a, 4, 9);
+ J1(a, b, c, d, e, 0, 15);
+ J1(e, a, b, c, d, 5, 5);
+ J1(d, e, a, b, c, 9, 11);
+ J1(c, d, e, a, b, 7, 6);
+ J1(b, c, d, e, a, 12, 8);
+ J1(a, b, c, d, e, 2, 13);
+ J1(e, a, b, c, d, 10, 12);
+ J1(d, e, a, b, c, 14, 5);
+ J1(c, d, e, a, b, 1, 12);
+ J1(b, c, d, e, a, 3, 13);
+ J1(a, b, c, d, e, 8, 14);
+ J1(e, a, b, c, d, 11, 11);
+ J1(d, e, a, b, c, 6, 8);
+ J1(c, d, e, a, b, 15, 5);
+ J1(b, c, d, e, a, 13, 6);
+
+ /* --- And then the right hand side --- */
+
+ F2(A, B, C, D, E, 5, 8);
+ F2(E, A, B, C, D, 14, 9);
+ F2(D, E, A, B, C, 7, 9);
+ F2(C, D, E, A, B, 0, 11);
+ F2(B, C, D, E, A, 9, 13);
+ F2(A, B, C, D, E, 2, 15);
+ F2(E, A, B, C, D, 11, 15);
+ F2(D, E, A, B, C, 4, 5);
+ F2(C, D, E, A, B, 13, 7);
+ F2(B, C, D, E, A, 6, 7);
+ F2(A, B, C, D, E, 15, 8);
+ F2(E, A, B, C, D, 8, 11);
+ F2(D, E, A, B, C, 1, 14);
+ F2(C, D, E, A, B, 10, 14);
+ F2(B, C, D, E, A, 3, 12);
+ F2(A, B, C, D, E, 12, 6);
+
+ G2(E, A, B, C, D, 6, 9);
+ G2(D, E, A, B, C, 11, 13);
+ G2(C, D, E, A, B, 3, 15);
+ G2(B, C, D, E, A, 7, 7);
+ G2(A, B, C, D, E, 0, 12);
+ G2(E, A, B, C, D, 13, 8);
+ G2(D, E, A, B, C, 5, 9);
+ G2(C, D, E, A, B, 10, 11);
+ G2(B, C, D, E, A, 14, 7);
+ G2(A, B, C, D, E, 15, 7);
+ G2(E, A, B, C, D, 8, 12);
+ G2(D, E, A, B, C, 12, 7);
+ G2(C, D, E, A, B, 4, 6);
+ G2(B, C, D, E, A, 9, 15);
+ G2(A, B, C, D, E, 1, 13);
+ G2(E, A, B, C, D, 2, 11);
+
+ H2(D, E, A, B, C, 15, 9);
+ H2(C, D, E, A, B, 5, 7);
+ H2(B, C, D, E, A, 1, 15);
+ H2(A, B, C, D, E, 3, 11);
+ H2(E, A, B, C, D, 7, 8);
+ H2(D, E, A, B, C, 14, 6);
+ H2(C, D, E, A, B, 6, 6);
+ H2(B, C, D, E, A, 9, 14);
+ H2(A, B, C, D, E, 11, 12);
+ H2(E, A, B, C, D, 8, 13);
+ H2(D, E, A, B, C, 12, 5);
+ H2(C, D, E, A, B, 2, 14);
+ H2(B, C, D, E, A, 10, 13);
+ H2(A, B, C, D, E, 0, 13);
+ H2(E, A, B, C, D, 4, 7);
+ H2(D, E, A, B, C, 13, 5);
+
+ I2(C, D, E, A, B, 8, 15);
+ I2(B, C, D, E, A, 6, 5);
+ I2(A, B, C, D, E, 4, 8);
+ I2(E, A, B, C, D, 1, 11);
+ I2(D, E, A, B, C, 3, 14);
+ I2(C, D, E, A, B, 11, 14);
+ I2(B, C, D, E, A, 15, 6);
+ I2(A, B, C, D, E, 0, 14);
+ I2(E, A, B, C, D, 5, 6);
+ I2(D, E, A, B, C, 12, 9);
+ I2(C, D, E, A, B, 2, 12);
+ I2(B, C, D, E, A, 13, 9);
+ I2(A, B, C, D, E, 9, 12);
+ I2(E, A, B, C, D, 7, 5);
+ I2(D, E, A, B, C, 10, 15);
+ I2(C, D, E, A, B, 14, 8);
+
+ J2(B, C, D, E, A, 12, 8);
+ J2(A, B, C, D, E, 15, 5);
+ J2(E, A, B, C, D, 10, 12);
+ J2(D, E, A, B, C, 4, 9);
+ J2(C, D, E, A, B, 1, 12);
+ J2(B, C, D, E, A, 5, 5);
+ J2(A, B, C, D, E, 8, 14);
+ J2(E, A, B, C, D, 7, 6);
+ J2(D, E, A, B, C, 6, 8);
+ J2(C, D, E, A, B, 2, 13);
+ J2(B, C, D, E, A, 13, 6);
+ J2(A, B, C, D, E, 14, 5);
+ J2(E, A, B, C, D, 0, 15);
+ J2(D, E, A, B, C, 3, 13);
+ J2(C, D, E, A, B, 9, 11);
+ J2(B, C, D, E, A, 11, 11);
+
+ /* --- Recombine the two halves --- */
+
+ {
+ uint32
+ tmp = ctx->b + c + D;
+ ctx->b = ctx->c + d + E;
+ ctx->c = ctx->d + e + A;
+ ctx->d = ctx->e + a + B;
+ ctx->e = ctx->a + b + C;
+ ctx->a = tmp;
+ }
+}
+
+/* --- @rmd160_init@ --- *
+ *
+ * Arguments: @rmd160_ctx *ctx@ = pointer to context block to initialize
+ *
+ * Returns: ---
+ *
+ * Use: Initializes a context block ready for hashing.
+ */
+
+void rmd160_init(rmd160_ctx *ctx)
+{
+ ctx->a = 0x67452301;
+ ctx->b = 0xefcdab89;
+ ctx->c = 0x98badcfe;
+ ctx->d = 0x10325476;
+ ctx->e = 0xc3d2e1f0;
+ ctx->off = 0;
+ ctx->count = 0;
+}
+
+/* --- @rmd160_set@ --- *
+ *
+ * Arguments: @rmd160_ctx *ctx@ = pointer to context block
+ * @const void *buf@ = pointer to state buffer
+ * @unsigned long count@ = current count of bytes processed
+ *
+ * Returns: ---
+ *
+ * Use: Initializes a context block from a given state. This is
+ * useful in cases where the initial hash state is meant to be
+ * secret, e.g., for NMAC and HMAC support.
+ */
+
+void rmd160_set(rmd160_ctx *ctx, const void *buf, unsigned long count)
+{
+ const octet *p = buf;
+ ctx->a = LOAD32_L(p + 0);
+ ctx->b = LOAD32_L(p + 4);
+ ctx->c = LOAD32_L(p + 8);
+ ctx->d = LOAD32_L(p + 12);
+ ctx->e = LOAD32_L(p + 16);
+ ctx->off = 0;
+ ctx->count = count;
+}
+
+/* --- @rmd160_hash@ --- *
+ *
+ * Arguments: @rmd160_ctx *ctx@ = pointer to context block
+ * @const void *buf@ = buffer of data to hash
+ * @size_t sz@ = size of buffer to hash
+ *
+ * Returns: ---
+ *
+ * Use: Hashes a buffer of data. The buffer may be of any size and
+ * alignment.
+ */
+
+void rmd160_hash(rmd160_ctx *ctx, const void *buf, size_t sz)
+{
+ HASH_BUFFER(RMD160, rmd160, ctx, buf, sz);
+}
+
+/* --- @rmd160_done@ --- *
+ *
+ * Arguments: @rmd160_ctx *ctx@ = pointer to context block
+ * @void *hash@ = pointer to output buffer
+ *
+ * Returns: ---
+ *
+ * Use: Returns the hash of the data read so far.
+ */
+
+void rmd160_done(rmd160_ctx *ctx, void *hash)
+{
+ octet *p = hash;
+ HASH_MD5STRENGTH(RMD160, rmd160, ctx);
+ STORE32_L(p + 0, ctx->a);
+ STORE32_L(p + 4, ctx->b);
+ STORE32_L(p + 8, ctx->c);
+ STORE32_L(p + 12, ctx->d);
+ STORE32_L(p + 16, ctx->e);
+}
+
+/* --- @rmd160_state@ --- *
+ *
+ * Arguments: @rmd160_ctx *ctx@ = pointer to context
+ * @void *state@ = pointer to buffer for current state
+ *
+ * Returns: Number of bytes written to the hash function so far.
+ *
+ * Use: Returns the current state of the hash function such that
+ * it can be passed to @rmd160_set@.
+ */
+
+unsigned long rmd160_state(rmd160_ctx *ctx, void *state)
+{
+ octet *p = state;
+ STORE32_L(p + 0, ctx->a);
+ STORE32_L(p + 4, ctx->b);
+ STORE32_L(p + 8, ctx->c);
+ STORE32_L(p + 12, ctx->d);
+ STORE32_L(p + 16, ctx->e);
+ return (ctx->count);
+}
+
+/* --- Test code --- */
+
+HASH_TEST(RMD160, rmd160)
+
+/*----- That's all, folks -------------------------------------------------*/
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: rmd160.h,v 1.1 1999/09/03 08:41:12 mdw Exp $
+ *
+ * The RIPEMD-160 message digest function
+ *
+ * (c) 1998 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: rmd160.h,v $
+ * Revision 1.1 1999/09/03 08:41:12 mdw
+ * Initial import.
+ *
+ */
+
+/*----- Notes on the RIPEMD-160 hash function -----------------------------*
+ *
+ * RIPEMD-160 was invented by Hans Dobbertin, Antoon Bosselaers and Bart
+ * Preneel. It's a strengthened version of the original RIPEMD hash
+ * function, fixing a vulnerability discovered by Hans Dobbertin. The
+ * RIPEMD-160 design team appears well respected in the cryptographic
+ * community. The author finds them more plausible than SHA-1, which is the
+ * best alternative hash function.
+ */
+
+#ifndef RMD160_H
+#define RMD160_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <mLib/bits.h>
+
+/*----- Magic numbers -----------------------------------------------------*/
+
+#define RMD160_BUFSZ 64
+#define RMD160_HASHSZ 20
+
+/*----- Data structures ---------------------------------------------------*/
+
+typedef struct rmd160_ctx {
+ uint32 a, b, c, d, e; /* Chaining variables */
+ unsigned long count; /* Byte count so far */
+ int off; /* Offset into buffer */
+ octet buf[RMD160_BUFSZ]; /* Accumulation buffer */
+} rmd160_ctx;
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @rmd160_compress@ --- *
+ *
+ * Arguments: @rmd160_ctx *ctx@ = pointer to context block
+ * @const void *sbuf@ = pointer to buffer of appropriate size
+ *
+ * Returns: ---
+ *
+ * Use: RIPEMD-160 compression function.
+ */
+
+extern void rmd160_compress(rmd160_ctx */*ctx*/, const void */*sbuf*/);
+
+/* --- @rmd160_init@ --- *
+ *
+ * Arguments: @rmd160_ctx *ctx@ = pointer to context block to initialize
+ *
+ * Returns: ---
+ *
+ * Use: Initializes a context block ready for hashing.
+ */
+
+extern void rmd160_init(rmd160_ctx */*ctx*/);
+
+/* --- @rmd160_set@ --- *
+ *
+ * Arguments: @rmd160_ctx *ctx@ = pointer to context block
+ * @const void *buf@ = pointer to state buffer
+ * @unsigned long count@ = current count of bytes processed
+ *
+ * Returns: ---
+ *
+ * Use: Initializes a context block from a given state. This is
+ * useful in cases where the initial hash state is meant to be
+ * secret, e.g., for NMAC and HMAC support.
+ */
+
+extern void rmd160_set(rmd160_ctx */*ctx*/,
+ const void */*buf*/, unsigned long /*count*/);
+
+/* --- @rmd160_hash@ --- *
+ *
+ * Arguments: @rmd160_ctx *ctx@ = pointer to context block
+ * @const void *buf@ = buffer of data to hash
+ * @size_t sz@ = size of buffer to hash
+ *
+ * Returns: ---
+ *
+ * Use: Hashes a buffer of data. The buffer may be of any size and
+ * alignment.
+ */
+
+extern void rmd160_hash(rmd160_ctx */*ctx*/,
+ const void */*buf*/, size_t /*sz*/);
+
+/* --- @rmd160_done@ --- *
+ *
+ * Arguments: @rmd160_ctx *ctx@ = pointer to context block
+ * @void *hash@ = pointer to output buffer
+ *
+ * Returns: ---
+ *
+ * Use: Returns the hash of the data read so far.
+ */
+
+extern void rmd160_done(rmd160_ctx */*ctx*/, void */*hash*/);
+
+/* --- @rmd160_state@ --- *
+ *
+ * Arguments: @rmd160_ctx *ctx@ = pointer to context
+ * @void *state@ = pointer to buffer for current state
+ *
+ * Returns: Number of bytes written to the hash function so far.
+ *
+ * Use: Returns the current state of the hash function such that
+ * it can be passed to @rmd160_set@.
+ */
+
+extern unsigned long rmd160_state(rmd160_ctx */*ctx*/, void */*state*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
--- /dev/null
+#! /bin/sh
+
+set -e
+mklinks
+ln -s ../mLib/build mLib
+mkaclocal
+autoheader
+m4 Makefile.m4 >Makefile.am
+autoconf
+automake
+mkdir build
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: sha.c,v 1.1 1999/09/03 08:41:12 mdw Exp $
+ *
+ * Implementation of the SHA-1 hash function
+ *
+ * (c) 1999 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: sha.c,v $
+ * Revision 1.1 1999/09/03 08:41:12 mdw
+ * Initial import.
+ *
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <mLib/bits.h>
+
+#include "hash.h"
+#include "sha.h"
+
+/*----- Main code ---------------------------------------------------------*/
+
+/* --- @sha_compress@ --- *
+ *
+ * Arguments: @sha_ctx *ctx@ = pointer to context block
+ * @const void *sbuf@ = pointer to buffer of appropriate size
+ *
+ * Returns: ---
+ *
+ * Use: SHA-1 compression function.
+ */
+
+void sha_compress(sha_ctx *ctx, const void *sbuf)
+{
+ uint32 a, b, c, d, e;
+ uint32 buf[80];
+
+ /* --- Fetch the chaining variables --- */
+
+ a = ctx->a;
+ b = ctx->b;
+ c = ctx->c;
+ d = ctx->d;
+ e = ctx->e;
+
+ /* --- Fetch and expand the buffer contents --- */
+
+ {
+ int i;
+ const octet *p;
+
+ for (i = 0, p = sbuf; i < 16; i++, p += 4)
+ buf[i] = LOAD32(p);
+ for (i = 16; i < 80; i++) {
+ uint32 x = buf[i - 3] ^ buf[i - 8] ^ buf[i - 14] ^ buf[i - 16];
+ buf[i] = ROL32(x, 1);
+ }
+ }
+
+ /* --- Definitions for round functions --- */
+
+#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
+#define G(x, y, z) ((x) ^ (y) ^ (z))
+#define H(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
+
+#define T(v, w, x, y, z, i, f, k) do { \
+ z = ROL32(v, 5) + f(w, x, y) + z + buf[i] + k; \
+ w = ROR32(w, 2); \
+} while (0)
+
+#define FF(v, w, x, y, z, i) T(v, w, x, y, z, i, F, 0x5a827999)
+#define GG(v, w, x, y, z, i) T(v, w, x, y, z, i, G, 0x6ed9eba1)
+#define HH(v, w, x, y, z, i) T(v, w, x, y, z, i, H, 0x8f1bbcdc)
+#define II(v, w, x, y, z, i) T(v, w, x, y, z, i, G, 0xca62c1d6)
+
+ /* --- The main compression function --- */
+
+ FF(a, b, c, d, e, 0);
+ FF(e, a, b, c, d, 1);
+ FF(d, e, a, b, c, 2);
+ FF(c, d, e, a, b, 3);
+ FF(b, c, d, e, a, 4);
+ FF(a, b, c, d, e, 5);
+ FF(e, a, b, c, d, 6);
+ FF(d, e, a, b, c, 7);
+ FF(c, d, e, a, b, 8);
+ FF(b, c, d, e, a, 9);
+ FF(a, b, c, d, e, 10);
+ FF(e, a, b, c, d, 11);
+ FF(d, e, a, b, c, 12);
+ FF(c, d, e, a, b, 13);
+ FF(b, c, d, e, a, 14);
+ FF(a, b, c, d, e, 15);
+ FF(e, a, b, c, d, 16);
+ FF(d, e, a, b, c, 17);
+ FF(c, d, e, a, b, 18);
+ FF(b, c, d, e, a, 19);
+
+ GG(a, b, c, d, e, 20);
+ GG(e, a, b, c, d, 21);
+ GG(d, e, a, b, c, 22);
+ GG(c, d, e, a, b, 23);
+ GG(b, c, d, e, a, 24);
+ GG(a, b, c, d, e, 25);
+ GG(e, a, b, c, d, 26);
+ GG(d, e, a, b, c, 27);
+ GG(c, d, e, a, b, 28);
+ GG(b, c, d, e, a, 29);
+ GG(a, b, c, d, e, 30);
+ GG(e, a, b, c, d, 31);
+ GG(d, e, a, b, c, 32);
+ GG(c, d, e, a, b, 33);
+ GG(b, c, d, e, a, 34);
+ GG(a, b, c, d, e, 35);
+ GG(e, a, b, c, d, 36);
+ GG(d, e, a, b, c, 37);
+ GG(c, d, e, a, b, 38);
+ GG(b, c, d, e, a, 39);
+
+ HH(a, b, c, d, e, 40);
+ HH(e, a, b, c, d, 41);
+ HH(d, e, a, b, c, 42);
+ HH(c, d, e, a, b, 43);
+ HH(b, c, d, e, a, 44);
+ HH(a, b, c, d, e, 45);
+ HH(e, a, b, c, d, 46);
+ HH(d, e, a, b, c, 47);
+ HH(c, d, e, a, b, 48);
+ HH(b, c, d, e, a, 49);
+ HH(a, b, c, d, e, 50);
+ HH(e, a, b, c, d, 51);
+ HH(d, e, a, b, c, 52);
+ HH(c, d, e, a, b, 53);
+ HH(b, c, d, e, a, 54);
+ HH(a, b, c, d, e, 55);
+ HH(e, a, b, c, d, 56);
+ HH(d, e, a, b, c, 57);
+ HH(c, d, e, a, b, 58);
+ HH(b, c, d, e, a, 59);
+
+ II(a, b, c, d, e, 60);
+ II(e, a, b, c, d, 61);
+ II(d, e, a, b, c, 62);
+ II(c, d, e, a, b, 63);
+ II(b, c, d, e, a, 64);
+ II(a, b, c, d, e, 65);
+ II(e, a, b, c, d, 66);
+ II(d, e, a, b, c, 67);
+ II(c, d, e, a, b, 68);
+ II(b, c, d, e, a, 69);
+ II(a, b, c, d, e, 70);
+ II(e, a, b, c, d, 71);
+ II(d, e, a, b, c, 72);
+ II(c, d, e, a, b, 73);
+ II(b, c, d, e, a, 74);
+ II(a, b, c, d, e, 75);
+ II(e, a, b, c, d, 76);
+ II(d, e, a, b, c, 77);
+ II(c, d, e, a, b, 78);
+ II(b, c, d, e, a, 79);
+
+ /* --- Update the chaining variables --- */
+
+ ctx->a += a;
+ ctx->b += b;
+ ctx->c += c;
+ ctx->d += d;
+ ctx->e += e;
+}
+
+/* --- @sha_init@ --- *
+ *
+ * Arguments: @sha_ctx *ctx@ = pointer to context block to initialize
+ *
+ * Returns: ---
+ *
+ * Use: Initializes a context block ready for hashing.
+ */
+
+void sha_init(sha_ctx *ctx)
+{
+ ctx->a = 0x67452301;
+ ctx->b = 0xefcdab89;
+ ctx->c = 0x98badcfe;
+ ctx->d = 0x10325476;
+ ctx->e = 0xc3d2e1f0;
+ ctx->off = 0;
+ ctx->count = 0;
+}
+
+/* --- @sha_set@ --- *
+ *
+ * Arguments: @sha_ctx *ctx@ = pointer to context block
+ * @const void *buf@ = pointer to state buffer
+ * @unsigned long count@ = current count of bytes processed
+ *
+ * Returns: ---
+ *
+ * Use: Initializes a context block from a given state. This is
+ * useful in cases where the initial hash state is meant to be
+ * secret, e.g., for NMAC and HMAC support.
+ */
+
+void sha_set(sha_ctx *ctx, const void *buf, unsigned long count)
+{
+ const octet *p = buf;
+ ctx->a = LOAD32(p + 0);
+ ctx->b = LOAD32(p + 4);
+ ctx->c = LOAD32(p + 8);
+ ctx->d = LOAD32(p + 12);
+ ctx->e = LOAD32(p + 16);
+ ctx->off = 0;
+ ctx->count = count;
+}
+
+/* --- @sha_hash@ --- *
+ *
+ * Arguments: @sha_ctx *ctx@ = pointer to context block
+ * @const void *buf@ = buffer of data to hash
+ * @size_t sz@ = size of buffer to hash
+ *
+ * Returns: ---
+ *
+ * Use: Hashes a buffer of data. The buffer may be of any size and
+ * alignment.
+ */
+
+void sha_hash(sha_ctx *ctx, const void *buf, size_t sz)
+{
+ HASH_BUFFER(SHA, sha, ctx, buf, sz);
+}
+
+/* --- @sha_done@ --- *
+ *
+ * Arguments: @sha_ctx *ctx@ = pointer to context block
+ * @void *hash@ = pointer to output buffer
+ *
+ * Returns: ---
+ *
+ * Use: Returns the hash of the data read so far.
+ */
+
+void sha_done(sha_ctx *ctx, void *hash)
+{
+ octet *p = hash;
+ HASH_PAD(SHA, sha, ctx, 0x80, 0, 8);
+ STORE32(ctx->buf + SHA_BUFSZ - 8, ctx->count >> 29);
+ STORE32(ctx->buf + SHA_BUFSZ - 4, ctx->count << 3);
+ sha_compress(ctx, ctx->buf);
+ STORE32(p + 0, ctx->a);
+ STORE32(p + 4, ctx->b);
+ STORE32(p + 8, ctx->c);
+ STORE32(p + 12, ctx->d);
+ STORE32(p + 16, ctx->e);
+}
+
+/* --- @sha_state@ --- *
+ *
+ * Arguments: @sha_ctx *ctx@ = pointer to context
+ * @void *state@ = pointer to buffer for current state
+ *
+ * Returns: Number of bytes written to the hash function so far.
+ *
+ * Use: Returns the current state of the hash function such that
+ * it can be passed to @sha_set@.
+ */
+
+unsigned long sha_state(sha_ctx *ctx, void *state)
+{
+ octet *p = state;
+ STORE32(p + 0, ctx->a);
+ STORE32(p + 4, ctx->b);
+ STORE32(p + 8, ctx->c);
+ STORE32(p + 12, ctx->d);
+ STORE32(p + 16, ctx->e);
+ return (ctx->count);
+}
+
+/* --- Test code --- */
+
+HASH_TEST(SHA, sha)
+
+/*----- That's all, folks -------------------------------------------------*/
--- /dev/null
+/* -*-c-*-
+ *
+ * $Id: sha.h,v 1.1 1999/09/03 08:41:12 mdw Exp $
+ *
+ * Implementation of the SHA-1 hash function
+ *
+ * (c) 1999 Straylight/Edgeware
+ */
+
+/*----- Licensing notice --------------------------------------------------*
+ *
+ * This file is part of Catacomb.
+ *
+ * Catacomb is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * Catacomb 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 Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with Catacomb; if not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ * MA 02111-1307, USA.
+ */
+
+/*----- Revision history --------------------------------------------------*
+ *
+ * $Log: sha.h,v $
+ * Revision 1.1 1999/09/03 08:41:12 mdw
+ * Initial import.
+ *
+ */
+
+/*----- Notes on the SHA-1 hash function ----------------------------------*
+ *
+ * SHA (Secure Hash Algorithm) was designed by the NSA, for use with the
+ * Digital Signature Algorithm. It has gained wide acceptance since then,
+ * and is probably now most people's collision-resistant function of choice.
+ * The author prefers RIPEMD-160, for no particularly good reasons.
+ */
+
+#ifndef SHA_H
+#define SHA_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+/*----- Header files ------------------------------------------------------*/
+
+#include <mLib/bits.h>
+
+/*----- Magic numbers -----------------------------------------------------*/
+
+#define SHA_BUFSZ 64
+#define SHA_HASHSZ 20
+
+/*----- Data structures ---------------------------------------------------*/
+
+typedef struct sha_ctx {
+ uint32 a, b, c, d, e; /* Chaining variables */
+ unsigned long count; /* Byte count so far */
+ int off; /* Offset into buffer */
+ octet buf[SHA_BUFSZ]; /* Accumulation buffer */
+} sha_ctx;
+
+/*----- Functions provided ------------------------------------------------*/
+
+/* --- @sha_compress@ --- *
+ *
+ * Arguments: @sha_ctx *ctx@ = pointer to context block
+ * @const void *sbuf@ = pointer to buffer of appropriate size
+ *
+ * Returns: ---
+ *
+ * Use: SHA compression function.
+ */
+
+extern void sha_compress(sha_ctx */*ctx*/, const void */*sbuf*/);
+
+/* --- @sha_init@ --- *
+ *
+ * Arguments: @sha_ctx *ctx@ = pointer to context block to initialize
+ *
+ * Returns: ---
+ *
+ * Use: Initializes a context block ready for hashing.
+ */
+
+extern void sha_init(sha_ctx */*ctx*/);
+
+/* --- @sha_set@ --- *
+ *
+ * Arguments: @sha_ctx *ctx@ = pointer to context block
+ * @const void *buf@ = pointer to state buffer
+ * @unsigned long count@ = current count of bytes processed
+ *
+ * Returns: ---
+ *
+ * Use: Initializes a context block from a given state. This is
+ * useful in cases where the initial hash state is meant to be
+ * secret, e.g., for NMAC and HMAC support.
+ */
+
+extern void sha_set(sha_ctx */*ctx*/, const void */*buf*/,
+ unsigned long /*count*/);
+
+/* --- @sha_hash@ --- *
+ *
+ * Arguments: @sha_ctx *ctx@ = pointer to context block
+ * @const void *buf@ = buffer of data to hash
+ * @size_t sz@ = size of buffer to hash
+ *
+ * Returns: ---
+ *
+ * Use: Hashes a buffer of data. The buffer may be of any size and
+ * alignment.
+ */
+
+extern void sha_hash(sha_ctx */*ctx*/, const void */*buf*/, size_t /*sz*/);
+
+/* --- @sha_done@ --- *
+ *
+ * Arguments: @sha_ctx *ctx@ = pointer to context block
+ * @void *hash@ = pointer to output buffer
+ *
+ * Returns: ---
+ *
+ * Use: Returns the hash of the data read so far.
+ */
+
+extern void sha_done(sha_ctx */*ctx*/, void */*hash*/);
+
+/* --- @sha_state@ --- *
+ *
+ * Arguments: @sha_ctx *ctx@ = pointer to context
+ * @void *state@ = pointer to buffer for current state
+ *
+ * Returns: Number of bytes written to the hash function so far.
+ *
+ * Use: Returns the current state of the hash function such that
+ * it can be passed to @sha_set@.
+ */
+
+extern unsigned long sha_state(sha_ctx */*ctx*/, void */*state*/);
+
+/*----- That's all, folks -------------------------------------------------*/
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
--- /dev/null
+# Test vectors for Blowfish
+#
+# $Id: blowfish,v 1.1 1999/09/03 08:41:14 mdw Exp $
+
+# --- Main block cipher ---
+#
+# Taken from Bruce Schneier's web pages, I think...
+
+blowfish {
+ 0000000000000000 0000000000000000 4ef997456198dd78;
+ ffffffffffffffff ffffffffffffffff 51866fd5b85ecb8a;
+ 3000000000000000 1000000000000001 7d856f9a613063f2;
+ 1111111111111111 1111111111111111 2466dd878b963c9d;
+ 0123456789abcdef 1111111111111111 61f9c3802281b096;
+ 1111111111111111 0123456789abcdef 7d0cc630afda1ec7;
+ 0000000000000000 0000000000000000 4ef997456198dd78;
+ fedcba9876543210 0123456789abcdef 0aceab0fc6a0a28d;
+ 7ca110454a1a6e57 01a1d6d039776742 59c68245eb05282b;
+ 0131d9619dc1376e 5cd54ca83def57da b1b8cc0b250f09a0;
+ 07a1133e4a0b2686 0248d43806f67172 1730e5778bea1da4;
+ 3849674c2602319e 51454b582ddf440a a25e7856cf2651eb;
+ 04b915ba43feb5b6 42fd443059577fa2 353882b109ce8f1a;
+ 0113b970fd34f2ce 059b5e0851cf143a 48f4d0884c379918;
+ 0170f175468fb5e6 0756d8e0774761d2 432193b78951fc98;
+ 43297fad38e373fe 762514b829bf486a 13f04154d69d1ae5;
+ 07a7137045da2a16 3bdd119049372802 2eedda93ffd39c79;
+ 04689104c2fd3b2f 26955f6835af609a d887e0393c2da6e3;
+ 37d06bb516cb7546 164d5e404f275232 5f99d04f5b163969;
+ 1f08260d1ac2465e 6b056e18759f5cca 4a057a3b24d3977b;
+ 584023641aba6176 004bd6ef09176062 452031c1e4fada8e;
+ 025816164629b007 480d39006ee762f2 7555ae39f59b87bd;
+ 49793ebc79b3258f 437540c8698f3cfa 53c55f9cb49fc019;
+ 4fb05e1515ab73a7 072d43a077075292 7a8e7bfa937e89a3;
+ 49e95d6d4ca229bf 02fe55778117f12a cf9c5d7a4986adb5;
+ 018310dc409b26d6 1d9d5c5018f728c2 d1abb290658bc778;
+ 1c587f1c13924fef 305532286d6f295a 55cb3774d13ef201;
+ 0101010101010101 0123456789abcdef fa34ec4847b268b2;
+ 1f1f1f1f0e0e0e0e 0123456789abcdef a790795108ea3cae;
+ e0fee0fef1fef1fe 0123456789abcdef c39e072d9fac631d;
+ 0000000000000000 ffffffffffffffff 014933e0cdaff6e4;
+ ffffffffffffffff 0000000000000000 f21e9a77b71c49bc;
+ 0123456789abcdef 0000000000000000 245946885754369a;
+ fedcba9876543210 ffffffffffffffff 6b5c5a9c5d9e0a5a;
+}
+
+# --- Key schedule test ---
+#
+# From wherever the previous tests came from.
+
+blowfish-sched {
+
+ f0
+ fedcba9876543210 f9ad597c49db005e;
+
+ f0e1
+ fedcba9876543210 e91d21c1d961a6d6;
+
+ f0e1d2
+ fedcba9876543210 e9c2b70a1bc65cf3;
+
+ f0e1d2c3
+ fedcba9876543210 be1e639408640f05;
+
+ f0e1d2c3b4
+ fedcba9876543210 b39e44481bdb1e6e;
+
+ f0e1d2c3b4a5
+ fedcba9876543210 9457aa83b1928c0d;
+
+ f0e1d2c3b4a596
+ fedcba9876543210 8bb77032f960629d;
+
+ f0e1d2c3b4a59687
+ fedcba9876543210 e87a244e2cc85e82;
+
+ f0e1d2c3b4a5968778
+ fedcba9876543210 15750e7a4f4ec577;
+
+ f0e1d2c3b4a596877869
+ fedcba9876543210 122ba70b3ab64ae0;
+
+ f0e1d2c3b4a5968778695a
+ fedcba9876543210 3a833c9affc537f6;
+
+ f0e1d2c3b4a5968778695a4b
+ fedcba9876543210 9409da87a90f6bf2;
+
+ f0e1d2c3b4a5968778695a4b3c
+ fedcba9876543210 884f80625060b8b4;
+
+ f0e1d2c3b4a5968778695a4b3c2d
+ fedcba9876543210 1f85031c19e11968;
+
+ f0e1d2c3b4a5968778695a4b3c2d1e
+ fedcba9876543210 79d9373a714ca34f;
+
+ f0e1d2c3b4a5968778695a4b3c2d1e0f
+ fedcba9876543210 93142887ee3be15c;
+
+ f0e1d2c3b4a5968778695a4b3c2d1e0f00
+ fedcba9876543210 03429e838ce2d14b;
+
+ f0e1d2c3b4a5968778695a4b3c2d1e0f0011
+ fedcba9876543210 a4299e27469ff67b;
+
+ f0e1d2c3b4a5968778695a4b3c2d1e0f001122
+ fedcba9876543210 afd5aed1c1bc96a8;
+
+ f0e1d2c3b4a5968778695a4b3c2d1e0f00112233
+ fedcba9876543210 10851c0e3858da9f;
+
+ f0e1d2c3b4a5968778695a4b3c2d1e0f0011223344
+ fedcba9876543210 e6f51ed79b9db21f;
+
+ f0e1d2c3b4a5968778695a4b3c2d1e0f001122334455
+ fedcba9876543210 64a6e14afd36b46f;
+
+ f0e1d2c3b4a5968778695a4b3c2d1e0f00112233445566
+ fedcba9876543210 80c7d7d45a5479ad;
+
+ f0e1d2c3b4a5968778695a4b3c2d1e0f0011223344556677
+ fedcba9876543210 05044b62fa52d080;
+
+}
--- /dev/null
+# Test vectors for DES
+#
+# $Id: des,v 1.1 1999/09/03 08:41:14 mdw Exp $
+
+des {
+ # --- 7-byte keys ---
+
+ 00451338957377 4e6f772069732074 3fa40e8a984d4815;
+ b6c74cbf60c1fd 328da675ff5abd2c cd3e9f9b670671d1;
+
+ # --- 8-byte keys ---
+
+ 0123456789abcdef 4e6f772069732074 3fa40e8a984d4815;
+ 0022446688aaccee 4e6f772069732074 3fa40e8a984d4815;
+ 0123456789abcdef 68652074696d6520 6a271787ab8883f9;
+ 0123456789abcdef 666f7220616c6c20 893d51ec4b563b53;
+ 0123456789abcdef 0123456789abcde7 c95744256a5ed31d;
+ b763d297f70606fb 328da675ff5abd2c cd3e9f9b670671d1;
+}
--- /dev/null
+# Test vectors for double and triple DES
+#
+# $Id: des3,v 1.1 1999/09/03 08:41:14 mdw Exp $
+
+des3 {
+ # --- Some simple single-DES things ---
+
+ 00451338957377 4e6f772069732074 3fa40e8a984d4815;
+ b6c74cbf60c1fd 328da675ff5abd2c cd3e9f9b670671d1;
+
+ 0123456789abcdef 4e6f772069732074 3fa40e8a984d4815;
+ 0123456789abcdef 68652074696d6520 6a271787ab8883f9;
+ 0123456789abcdef 666f7220616c6c20 893d51ec4b563b53;
+ 0123456789abcdef 0123456789abcde7 c95744256a5ed31d;
+
+ 0045133895737700451338957377 4e6f772069732074 3fa40e8a984d4815;
+ b6c74cbf60c1fdb6c74cbf60c1fd 328da675ff5abd2c cd3e9f9b670671d1;
+
+ 0123456789abcdef0123456789abcdef 4e6f772069732074 3fa40e8a984d4815;
+ 0123456789abcdef0123456789abcdef 68652074696d6520 6a271787ab8883f9;
+ 0123456789abcdef0123456789abcdef 666f7220616c6c20 893d51ec4b563b53;
+ 0123456789abcdef0123456789abcdef 0123456789abcde7 c95744256a5ed31d;
+
+ 004513389573770045133895737700451338957377
+ 4e6f772069732074 3fa40e8a984d4815;
+ b6c74cbf60c1fdb6c74cbf60c1fdb6c74cbf60c1fd
+ 328da675ff5abd2c cd3e9f9b670671d1;
+
+ 0123456789abcdef0123456789abcdef0123456789abcdef
+ 4e6f772069732074 3fa40e8a984d4815;
+ 0123456789abcdef0123456789abcdef0123456789abcdef
+ 68652074696d6520 6a271787ab8883f9;
+ 0123456789abcdef0123456789abcdef0123456789abcdef
+ 666f7220616c6c20 893d51ec4b563b53;
+ 0123456789abcdef0123456789abcdef0123456789abcdef
+ 0123456789abcde7 c95744256a5ed31d;
+
+ # --- Genuine longer keys ---
+
+ 0123456789abcdeffedcba9876543210 0123456789abcde7 7f1d0a77826b8aff;
+ 0123456789abcdeffedcba987654321089abcdef01234567
+ 0123456789abcde7 de0b7c06ae5e0ed5;
+}
--- /dev/null
+# Test vectors for IDEA
+#
+# $Id: idea,v 1.1 1999/09/03 08:41:14 mdw Exp $
+
+# --- Thin on the ground, these are ---
+
+idea {
+ 00010002000300040005000600070008 0000000100020003 11fbed2b01986de5;
+}
--- /dev/null
+# Test vectors for MD4 hash function
+#
+# $Id: md4,v 1.1 1999/09/03 08:41:14 mdw Exp $
+
+# --- Basic hash function ---
+#
+# Test vectors from RFC1186 and some others I generated using the reference
+# implementation.
+
+md4 {
+
+ "" 31d6cfe0d16ae931b73c59d7e0c089c0;
+ "a" bde52cb31de33e46245e05fbdbd6fb24;
+ "abc" a448017aaf21d8525fc10ae87aa6729d;
+ "message digest" d9130a8164549fe818874806e1c7014b;
+ "abcdefghijklmnopqrstuvwxyz"
+ d79e1c308aa5bbcdeea8ed63df412da9;
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
+ 043f8582f241db351ce627e153e7f0e4;
+}
+
+# --- HMAC mode ---
+#
+# No test vectors available. The HMAC implementation has not been tested
+# against an external reference. However, MD4 isn't strong enough to make
+# a realistic MAC anyway, and use of md4-mac is thoroughly deprecated. The
+# HMAC code is autogenerated anyway, and ought to be reliable and correct.
+#
+# These test vectors are here to spot changes in behaviour rather than ensure
+# interoperability.
+
+md4-hmac {
+ "Hi There"
+ 0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
+ 90a79458f58f437e21f169cdba283da6;
+
+ "what do ya want for nothing?"
+ 4a656665
+ be192c588a8e914d8a59b474a828128f;
+
+ "ÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝ"
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 75e5fb6e71ca6dcdd9fca269a9a3cd9c;
+
+ "ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ"
+ 0102030405060708090a0b0c0d0e0f10111213141516171819
+ fb14cddf9efe11ad24033fc70f37bb9e;
+
+ "Test With Truncation"
+ 0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c
+ 6306262f9ba0e83f9ce3f15aafc23be8;
+
+ "Test Using Larger Than Block-Size Key - Hash Key First"
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 545b8f2577657042df628fbb98430d5f;
+
+ "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 0192f3442ad5d1ea5268306ab0d4962e;
+}
--- /dev/null
+# Test vectors for MD5 hash function
+#
+# $Id: md5,v 1.1 1999/09/03 08:41:14 mdw Exp $
+
+# --- Basic hash function ---
+#
+# Test vectors from RFC1321 and some others I generated using the reference
+# implementation.
+
+md5 {
+
+ "" d41d8cd98f00b204e9800998ecf8427e;
+ "a" 0cc175b9c0f1b6a831c399e269772661;
+ "abc" 900150983cd24fb0d6963f7d28e17f72;
+ "message digest" f96b697d7cb7938d525a2f31aaf161d0;
+ "abcdefghijklmnopqrstuvwxyz"
+ c3fcd3d76192e4007dfb496cca67e13b;
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
+ d174ab98d277d9f5a5611c2c9f419d9f;
+ "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
+ 57edf4a22be3c955ac49da2e2107b67a;
+
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+" 2b65a7ba4acd105ef2cb9adebd9f0bfa;
+
+}
+
+# --- HMAC mode ---
+#
+# Test vectors from RFC2104 and RFC2202.
+
+md5-hmac {
+
+ "Hi There"
+ 0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
+ 9294727a3638bb1c13f48ef8158bfc9d;
+
+ "what do ya want for nothing?"
+ 4a656665
+ 750c783e6ab0b503eaa86e310a5db738;
+
+ "ÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝ"
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 56be34521d144c88dbb8c733f0e8b3f6;
+
+ "ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ"
+ 0102030405060708090a0b0c0d0e0f10111213141516171819
+ 697eaf0aca3a3aea3a75164746ffaa79;
+
+ "Test With Truncation"
+ 0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c
+ 56461ef2342edc00f9bab995690efd4c;
+
+ "Test Using Larger Than Block-Size Key - Hash Key First"
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd;
+
+ "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 6f630fad67cda0ee1fb1f562db3aa53e;
+
+}
--- /dev/null
+# Test vectors for RC4
+#
+# $Id: rc4,v 1.1 1999/09/03 08:41:14 mdw Exp $
+
+# --- Note about these test vectors ---
+#
+# These test vectors come from two places: the Usenet article confirming that
+# the alleged RC4 source is interoperable with the BSAFE version, and some
+# tests I performed with the RC4-in-a-signature Perl version. Some testing
+# with the SSLeay version shows that for an all-zero key I'm compatible, but
+# with any other I'm not. Since I pass the Usenet test vectors (which I
+# found in the SSLeay sources!), and I'm compatible with at least one other
+# implementation, I'm happy that I'm in the right here.
+
+rc4-encrypt {
+ 0123456789abcdef 0123456789abcdef 75b7878099e0c596;
+ 0123456789abcdef
+ 010101010101010101010101010101010101010101
+ 7595c3e6114a09780c4ad452338e1ffd9a1be9498f;
+}
+
+rc4-generate {
+ 00 0 de188941a3375d3a8a061e67576e926d;
+ 01fe23dc45ba6798 0 643ded26ae29c15cda4f2b96d66baf2c;
+ 08192a3b4c5d6e7f 1024 abb3a32a2ba4d409752923aa4032be16;
+ 0123456789abcdef 0 7494c2e7104b0879;
+ ef012345 0 d6a141a7ec3c38dfbd61;
+}
--- /dev/null
+# Test vectors for RC5-32/12
+#
+# $Id: rc5,v 1.1 1999/09/03 08:41:14 mdw Exp $
+
+# --- Main cipher test vectors ---
+#
+# Taken from `The RC5 Encryption Algorithm' by Rivest. Important: the
+# test vectors given in the paper are given as 32-bit words, not bytes, so
+# since RC5 is little-endian they need to be swapped here.
+
+rc5 {
+ 00000000000000000000000000000000 0000000000000000 21a5dbee154b8f6d;
+ 915f4619be41b2516355a50110a9ce91 21a5dbee154b8f6d f7c013ac5b2b8952;
+ 783348e75aeb0f2fd7b169bb8dc16787 f7c013ac5b2b8952 2f42b3b70369fc92;
+ dc49db1375a5584f6485b413b5f12baf 2f42b3b70369fc92 65c178b284d197cc;
+ 5269f149d41ba0152497574d7f153125 65c178b284d197cc eb44e415da319824;
+}
--- /dev/null
+# Test vectors for RIPEMD-160
+#
+# $Id: rmd160,v 1.1 1999/09/03 08:41:14 mdw Exp $
+
+# --- Basic hash function ---
+#
+# Taken from the authors' web pages.
+
+rmd160 {
+ "" 9c1185a5c5e9fc54612808977ee8f548b2258d31;
+ "a" 0bdc9d2d256b3ee9daae347be6f4dc835a467ffe;
+ "abc" 8eb208f7e05d987a9b044a8e98c6b087f15a0bfc;
+ "message digest" 5d0689ef49d2fae572b881b123a85ffa21595f36;
+ "abcdefghijklmnopqrstuvwxyz"
+ f71c27109c692c1b56bbdceb5b9d2865b3708dbc;
+ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+ 12a053384a9c0c88e405a06c27dcf49ada62eb2b;
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
+ b0e20b6e3116640286ed3a87a5713079b21f5189;
+ "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
+ 9b752e45573d4b39f4dbd3323cab82bf63326bfb;
+
+}
+
+# --- HMAC mode ---
+#
+# Test vectors from RFC2286.
+
+rmd160-hmac {
+
+ "Hi There"
+ 0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
+ 24cb4bd67d20fc1a5d2ed7732dcc39377f0a5668;
+
+ "what do ya want for nothing?"
+ 4a656665
+ dda6c0213a485a9e24f4742064a7f033b43c4069;
+
+ "ÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝ"
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ b0b105360de759960ab4f35298e116e295d8e7c1;
+
+ "ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ"
+ 0102030405060708090a0b0c0d0e0f10111213141516171819
+ d5ca862f4d21d5e610e18b4cf1beb97a4365ecf4;
+
+ "Test With Truncation"
+ 0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c
+ 7619693978f91d90539ae786500ff3d8e0518e39;
+
+ "Test Using Larger Than Block-Size Key - Hash Key First"
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 6466ca07ac5eac29e1bd523e5ada7605b791fd8b;
+
+ "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 69ea60798d71616cce5fd0871e23754cd75d5a0a;
+
+}
\ No newline at end of file
--- /dev/null
+# Test vectors for the SHA-1 hash function
+#
+# $Id: sha,v 1.1 1999/09/03 08:41:14 mdw Exp $
+
+# --- Basic hash function ---
+#
+# These were generated using the SSLeay implementation of SHA-1.
+
+sha {
+
+ "" da39a3ee5e6b4b0d3255bfef95601890afd80709;
+ "a" 86f7e437faa5a7fce15d1ddcb9eaeaea377667b8;
+ "abc" a9993e364706816aba3e25717850c26c9cd0d89d;
+ "message digest" c12252ceda8be8994d5fa0290a47231c1d16aae3;
+ "abcdefghijklmnopqrstuvwxyz"
+ 32d10c7b8cf96570ca04ce37f2a19d84240d3a89;
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
+ 761c457bf73b14d27e9e9265c46f4b4dda11f940;
+ "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
+ 50abf5706a150990a08b2c5ea40fa0e585554732;
+
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
+" f74d36bf17ee23c46ec166a48a24da6ab999eaea;
+
+}
+
+# --- HMAC mode ---
+#
+# Test vectors from RFC2202.
+
+sha-hmac {
+
+ "Hi There"
+ 0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
+ b617318655057264e28bc0b6fb378c8ef146be00;
+
+ "what do ya want for nothing?"
+ 4a656665
+ effcdf6ae5eb2fa2d27416d5f184df9c259a7c79;
+
+ "ÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝ"
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ 125d7342b9ac11cd91a39af48aa17b4f63f175d3;
+
+ "ÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ"
+ 0102030405060708090a0b0c0d0e0f10111213141516171819
+ 4c9007f4026250c6bc8414f9bf50c86c2d7235da;
+
+ "Test With Truncation"
+ 0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c
+ 4c1a03424b55e07fe7f27be1d58bb9324a9a5a04;
+
+ "Test Using Larger Than Block-Size Key - Hash Key First"
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ aa4ae5e15272d00e95705637ce8a3b55ed402112;
+
+ "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ e8e99d0f45237d786d6bbaa7965c7808bbff1a91;
+
+}