1/*
2 * crc.c --
3 *
4 *	Implements and registers message digest generator CRC.
5 *
6 *
7 * Copyright (c) 1996 Andreas Kupries (a.kupries@westend.com)
8 * All rights reserved.
9 *
10 * Permission is hereby granted, without written agreement and without
11 * license or royalty fees, to use, copy, modify, and distribute this
12 * software and its documentation for any purpose, provided that the
13 * above copyright notice and the following two paragraphs appear in
14 * all copies of this software.
15 *
16 * IN NO EVENT SHALL I LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
17 * INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS
18 * SOFTWARE AND ITS DOCUMENTATION, EVEN IF I HAVE BEEN ADVISED OF THE
19 * POSSIBILITY OF SUCH DAMAGE.
20 *
21 * I SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND
24 * I HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
25 * ENHANCEMENTS, OR MODIFICATIONS.
26 *
27 * CVS: $Id: crc.c,v 1.4 2000/08/09 19:13:17 aku Exp $
28 */
29
30#include "transformInt.h"
31#include "crc.h"
32
33/*
34 * Generator description
35 * ---------------------
36 *
37 * The CRC algorithm is used to compute a message digest.
38 * The polynomial is taken from PGP (parts of the code too).
39 */
40
41#define DIGEST_SIZE               (CRCBYTES)
42#define CTX_TYPE                  crcword
43
44/*
45 * Declarations of internal procedures.
46 */
47
48static void MDcrc_Start     _ANSI_ARGS_ ((VOID* context));
49static void MDcrc_Update    _ANSI_ARGS_ ((VOID* context, unsigned int character));
50static void MDcrc_UpdateBuf _ANSI_ARGS_ ((VOID* context, unsigned char* buffer, int bufLen));
51static void MDcrc_Final     _ANSI_ARGS_ ((VOID* context, VOID* digest));
52
53/*
54 * Generator definition.
55 */
56
57static Trf_MessageDigestDescription mdDescription = {
58  "crc",
59  sizeof (CTX_TYPE),
60  DIGEST_SIZE,
61  MDcrc_Start,
62  MDcrc_Update,
63  MDcrc_UpdateBuf,
64  MDcrc_Final,
65  NULL
66};
67
68/*
69 * Additional declarations
70 */
71
72static crcword CrcTable [256]; /* THREADING: serialize initialization */
73
74static void
75GenCrcLookupTable _ANSI_ARGS_ ((crcword polynomial));
76
77/*
78 *------------------------------------------------------*
79 *
80 *	TrfInit_CRC --
81 *
82 *	------------------------------------------------*
83 *	Register the generator implemented in this file.
84 *	------------------------------------------------*
85 *
86 *	Sideeffects:
87 *		As of 'Trf_Register'.
88 *
89 *	Result:
90 *		A standard Tcl error code.
91 *
92 *------------------------------------------------------*
93 */
94
95int
96TrfInit_CRC (interp)
97Tcl_Interp* interp;
98{
99  GenCrcLookupTable (PRZCRC);
100
101  return Trf_RegisterMessageDigest (interp, &mdDescription);
102}
103
104/*
105 *------------------------------------------------------*
106 *
107 *	MDcrc_Start --
108 *
109 *	------------------------------------------------*
110 *	Initialize the internal state of the message
111 *	digest generator.
112 *	------------------------------------------------*
113 *
114 *	Sideeffects:
115 *		As of the called procedure.
116 *
117 *	Result:
118 *		None.
119 *
120 *------------------------------------------------------*
121 */
122
123static void
124MDcrc_Start (context)
125VOID* context;
126{
127  /* call md specific initialization here */
128
129  *((crcword*) context) = CRCINIT;
130}
131
132/*
133 *------------------------------------------------------*
134 *
135 *	MDcrc_Update --
136 *
137 *	------------------------------------------------*
138 *	Update the internal state of the message digest
139 *	generator for a single character.
140 *	------------------------------------------------*
141 *
142 *	Sideeffects:
143 *		As of the called procedure.
144 *
145 *	Result:
146 *		None.
147 *
148 *------------------------------------------------------*
149 */
150
151static void
152MDcrc_Update (context, character)
153VOID* context;
154unsigned int   character;
155{
156  /* call md specific update here */
157#define UP(ctx)   ((ctx) << 8)
158#define DOWN(ctx) ((ctx) >> CRCSHIFTS)
159
160  crcword       accu;
161  unsigned char buf = character;
162
163  accu = *((crcword*) context);
164  accu = UP (accu) ^ CrcTable [(unsigned char) (DOWN (accu)) ^ buf];
165
166  *((crcword*) context) = accu;
167
168#undef UP
169#undef DOWN
170}
171
172/*
173 *------------------------------------------------------*
174 *
175 *	MDcrc_UpdateBuf --
176 *
177 *	------------------------------------------------*
178 *	Update the internal state of the message digest
179 *	generator for a character buffer.
180 *	------------------------------------------------*
181 *
182 *	Sideeffects:
183 *		As of the called procedure.
184 *
185 *	Result:
186 *		None.
187 *
188 *------------------------------------------------------*
189 */
190
191static void
192MDcrc_UpdateBuf (context, buffer, bufLen)
193VOID* context;
194unsigned char* buffer;
195int   bufLen;
196{
197  /* call md specific update here */
198#define UP(ctx)   ((ctx) << 8)
199#define DOWN(ctx) ((ctx) >> CRCSHIFTS)
200
201  crcword accu;
202  int     i;
203
204  accu = *((crcword*) context);
205
206  for (i=0; i < bufLen; i++) {
207    accu = UP (accu) ^ CrcTable [(unsigned char) (DOWN (accu)) ^ (buffer [i])];
208  }
209
210  *((crcword*) context) = accu;
211
212#undef UP
213#undef DOWN
214}
215
216/*
217 *------------------------------------------------------*
218 *
219 *	MDcrc_Final --
220 *
221 *	------------------------------------------------*
222 *	Generate the digest from the internal state of
223 *	the message digest generator.
224 *	------------------------------------------------*
225 *
226 *	Sideeffects:
227 *		As of the called procedure.
228 *
229 *	Result:
230 *		None.
231 *
232 *------------------------------------------------------*
233 */
234
235static void
236MDcrc_Final (context, digest)
237VOID* context;
238VOID* digest;
239{
240  /* call md specific finalization here */
241
242  crcword crc = maskcrc (* ((crcword*) context));
243  char*   out = (char*) digest;
244
245  /* -*- PGP -*-, was outcrc, BIGENDIAN output */
246  /* DEPENDENT on CRCBYTES !!, only a value of 3 is supported here */
247
248  out [0] = (char) ((crc >> 16) & 0xff);
249  out [1] = (char) ((crc >>  8) & 0xff);
250  out [2] = (char) ((crc >>  0) & 0xff);
251  /* -*- PGP -*- */
252}
253
254/*
255 * Initialize lookup table for crc calculation.
256 */
257
258static void
259GenCrcLookupTable (poly)
260crcword poly;
261{
262  /* -*- PGP -*-, was 'mk_crctbl' */
263  int i;
264  crcword t, *p, *q;
265
266  TrfLock; /* THREADING: serialize initialization */
267
268  p = q = CrcTable;
269
270  *q++ = 0;
271  *q++ = poly;
272
273  for (i = 1; i < 128; i++)
274    {
275      t = *++p;
276      if (t & CRCHIBIT)
277	{
278	  t <<= 1;
279	  *q++ = t ^ poly;
280	  *q++ = t;
281	}
282      else
283	{
284	  t <<= 1;
285	  *q++ = t;
286	  *q++ = t ^ poly;
287	}
288    }
289
290  TrfUnlock;
291  /* -*- PGP -*- */
292}
293