chiark / gitweb /
Fix daft error in the comment for @gfshare_get@.
[catacomb] / hash.h
1 /* -*-c-*-
2  *
3  * $Id: hash.h,v 1.3 2000/06/17 11:23:27 mdw Exp $
4  *
5  * Generic handling for message digest functions
6  *
7  * (c) 1998 Straylight/Edgeware
8  */
9
10 /*----- Licensing notice --------------------------------------------------* 
11  *
12  * This file is part of Catacomb.
13  *
14  * Catacomb is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU Library General Public License as
16  * published by the Free Software Foundation; either version 2 of the
17  * License, or (at your option) any later version.
18  * 
19  * Catacomb is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU Library General Public License for more details.
23  * 
24  * You should have received a copy of the GNU Library General Public
25  * License along with Catacomb; if not, write to the Free
26  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
27  * MA 02111-1307, USA.
28  */
29
30 /*----- Revision history --------------------------------------------------* 
31  *
32  * $Log: hash.h,v $
33  * Revision 1.3  2000/06/17 11:23:27  mdw
34  * Portability fix for broken compilers.
35  *
36  * Revision 1.2  1999/12/10 23:16:40  mdw
37  * Split mode macros into interface and implementation.
38  *
39  * Revision 1.1  1999/09/03 08:41:12  mdw
40  * Initial import.
41  *
42  */
43
44 #ifndef CATACOMB_HASH_H
45 #define CATACOMB_HASH_H
46
47 #ifdef __cplusplus
48   extern "C" {
49 #endif
50
51 /*----- Header files ------------------------------------------------------*/
52
53 #include <string.h>
54
55 #include <mLib/bits.h>
56
57 /*----- Macros ------------------------------------------------------------*/
58
59 /* --- @HASH_BUFFER@ --- *
60  *
61  * Arguments:   @PRE@, @pre@ = prefixes for hash-specific definitions
62  *              @ictx@ = pointer to context block for the hash
63  *              @ibuf@ = pointer to input data to hash
64  *              @isz@ = size of buffer
65  *
66  * Use:         Handles buffering of input data to a hash function.  The
67  *              hash's compression function is called when the buffer is
68  *              full.  Note that the compression function can be called on
69  *              data which is at odd alignments; it is expected to cope
70  *              gracefully with this (possibly by copying the data into its
71  *              internal buffer before starting).
72  */
73
74 #define HASH_BUFFER(PRE, pre, ictx, ibuf, isz) do {                     \
75   pre##_ctx *_bctx = (ictx);                                            \
76   size_t _bsz = (isz);                                                  \
77   const octet *_bbuf = (octet *)(ibuf);                                 \
78                                                                         \
79   /* --- Add on the size done so far --- *                              \
80    *                                                                    \
81    * Messy, because trapping overflow is difficult when you don't know  \
82    * how many bits you've actually got.                                 \
83    */                                                                   \
84                                                                         \
85   {                                                                     \
86     uint32 _l = U32(_bsz);                                              \
87     uint32 _h = ((_bsz & ~MASK32) >> 16) >> 16;                         \
88     _bctx->nh += _h;                                                    \
89     _bctx->nl += _l;                                                    \
90     if (_bctx->nl < _l || _bctx->nl & ~MASK32)                          \
91       _bctx->nh++;                                                      \
92   }                                                                     \
93                                                                         \
94   /* --- Handle very small contributions --- */                         \
95                                                                         \
96   if (_bctx->off + _bsz < PRE##_BUFSZ) {                                \
97     memcpy(_bctx->buf + _bctx->off, _bbuf, _bsz);                       \
98     _bctx->off += _bsz;                                                 \
99   } else {                                                              \
100                                                                         \
101     /* --- Handle an initial partial buffer --- */                      \
102                                                                         \
103     if (_bctx->off) {                                                   \
104       size_t s = PRE##_BUFSZ - _bctx->off;                              \
105       memcpy(_bctx->buf + _bctx->off, _bbuf, s);                        \
106       pre##_compress(_bctx, _bctx->buf);                                \
107       _bsz -= s; _bbuf += s;                                            \
108     }                                                                   \
109                                                                         \
110     /* --- Do whole buffers while we can --- */                         \
111                                                                         \
112     while (_bsz >= PRE##_BUFSZ) {                                       \
113       pre##_compress(_bctx, _bbuf);                                     \
114       _bsz -= PRE##_BUFSZ; _bbuf += PRE##_BUFSZ;                        \
115     }                                                                   \
116                                                                         \
117     /* --- And wrap up at the end --- */                                \
118                                                                         \
119     if (_bsz)                                                           \
120       memcpy(_bctx->buf, _bbuf, _bsz);                                  \
121     _bctx->off = _bsz;                                                  \
122   }                                                                     \
123 } while (0)
124
125 /* --- @HASH_PAD@ --- *
126  *
127  * Arguments:   @PRE@, @pre@ = prefixes for hash-specific definitions
128  *              @ictx@ = pointer to context block for the hash
129  *              @term@ = terminator character to write following the data
130  *              @pad@ = pad character to fill with
131  *              @diff@ = size of space to leave at the end of the last block
132  *
133  * Use:         Does padding for message digest functions.
134  */
135
136 #define HASH_PAD(PRE, pre, ictx, term, pad, diff) do {                  \
137   pre##_ctx *_pctx = (ictx);                                            \
138                                                                         \
139   _pctx->buf[_pctx->off] = term;                                        \
140   _pctx->off++;                                                         \
141   if (_pctx->off > PRE##_BUFSZ - diff) {                                \
142     if (_pctx->off < PRE##_BUFSZ)                                       \
143       memset(_pctx->buf + _pctx->off, pad, PRE##_BUFSZ - _pctx->off);   \
144     pre##_compress(_pctx, _pctx->buf);                                  \
145     memset(_pctx->buf, pad, PRE##_BUFSZ - diff);                        \
146   } else                                                                \
147     memset(_pctx->buf + _pctx->off, pad,                                \
148            PRE##_BUFSZ - _pctx->off - diff);                            \
149 } while (0)
150
151 /* --- @HASH_MD5STRENGTH@ --- *
152  *
153  * Arguments:   @PRE@, @pre@ = prefixes for hash-specific definitions
154  *              @ictx@ = pointer to context block for the hash
155  *
156  * Use:         Does MD5-style MD strengthening.  The data is terminated
157  *              by a single set bit, padded with zero bits, and then a 64-
158  *              bit length is written, little-end first.
159  */
160
161 #define HASH_MD5STRENGTH(PRE, pre, ictx) do {                           \
162   pre##_ctx *_mctx = (ictx);                                            \
163   HASH_PAD(PRE, pre, _mctx, 0x80u, 0, 8);                               \
164   STORE32_L(_mctx->buf + PRE##_BUFSZ - 8, _mctx->nl << 3);              \
165   STORE32_L(_mctx->buf + PRE##_BUFSZ - 4,                               \
166             (_mctx->nl >> 29) | (_mctx->nh << 3));                      \
167   pre##_compress(_mctx, _mctx->buf);                                    \
168 } while (0)
169
170 /* --- @HASH_TEST@ --- *
171  *
172  * Arguments:   @PRE@, @pre@ = prefixes for hash-specfic definitions
173  *
174  * Use:         Standard test rig for hash functions.
175  */
176
177 #ifdef TEST_RIG
178
179 #include <mLib/quis.h>
180 #include <mLib/testrig.h>
181
182 #define HASH_TEST(PRE, pre)                                             \
183                                                                         \
184 static int verify(dstr *v)                                              \
185 {                                                                       \
186   pre##_ctx ctx;                                                        \
187   int ok = 1;                                                           \
188   int i;                                                                \
189   octet *p;                                                             \
190   int szs[] = { 1, 7, 192, -1, 0 }, *ip;                                \
191   size_t sz;                                                            \
192   dstr d;                                                               \
193                                                                         \
194   dstr_create(&d);                                                      \
195   dstr_ensure(&d, PRE##_HASHSZ);                                        \
196   d.len = PRE##_HASHSZ;                                                 \
197                                                                         \
198   for (ip = szs; *ip; ip++) {                                           \
199     i = *ip;                                                            \
200     sz = v[0].len;                                                      \
201     if (i == -1)                                                        \
202       i = sz;                                                           \
203     if (i > sz)                                                         \
204       continue;                                                         \
205     p = (octet *)v[0].buf;                                              \
206     pre##_init(&ctx);                                                   \
207     while (sz) {                                                        \
208       if (i > sz)                                                       \
209         i = sz;                                                         \
210       pre##_hash(&ctx, p, i);                                           \
211       p += i;                                                           \
212       sz -= i;                                                          \
213     }                                                                   \
214     pre##_done(&ctx, d.buf);                                            \
215     if (memcmp(d.buf, v[1].buf, PRE##_HASHSZ) != 0) {                   \
216       printf("\nfail:\n\tstep = %i\n\tinput = `%s'\n\texpected = ",     \
217              *ip, v[0].buf);                                            \
218       type_hex.dump(&v[1], stdout);                                     \
219       fputs("\n\tcomputed = ", stdout);                                 \
220       type_hex.dump(&d, stdout);                                        \
221       putchar('\n');                                                    \
222       ok = 0;                                                           \
223     }                                                                   \
224   }                                                                     \
225                                                                         \
226   dstr_destroy(&d);                                                     \
227   return (ok);                                                          \
228 }                                                                       \
229                                                                         \
230 static test_chunk defs[] = {                                            \
231   { #pre, verify, { &type_string, &type_hex, 0 } },                     \
232   { 0, 0, { 0 } }                                                       \
233 };                                                                      \
234                                                                         \
235 int main(int argc, char *argv[])                                        \
236 {                                                                       \
237   ego(argv[0]);                                                         \
238   test_run(argc, argv, defs, SRCDIR"/tests/" #pre);                     \
239   return (0);                                                           \
240 }
241
242 #else
243 #  define HASH_TEST(PRE, pre)
244 #endif
245
246 /*----- That's all, folks -------------------------------------------------*/
247
248 #ifdef __cplusplus
249   }
250 #endif
251
252 #endif