1/*
2 * rmd128.c --
3 *
4 *	Implements and registers message digest generator RIPEMD-128.
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: rmd128.c,v 1.5 2005/10/06 18:05:46 andreas_kupries Exp $
28 */
29
30#include "transformInt.h"
31#include "ripemd/rmd128.h"
32
33/*
34 * Generator description
35 * ---------------------
36 *
37 * The RIPEMD-128 alogrithm is used to compute a cryptographically strong
38 * message digest.
39 */
40
41#define DIGEST_SIZE   (16)
42/*#define CTX_TYPE                   */
43#define CONTEXT_SIZE  (16)
44#define CHUNK_SIZE    (64)
45
46typedef struct ripemd_context {
47  dword state [5];		/* state variables of ripemd-128 */
48  byte  buf   [CHUNK_SIZE];	/* buffer of 16-dword's          */
49  byte  byteCount;		/* number of bytes in buffer     */
50  dword lowc;			/* lower half of a 64bit counter */
51  dword highc;			/* upper half of a 64bit counter */
52} ripemd_context;
53
54
55/*
56 * Declarations of internal procedures.
57 */
58
59static void MDrmd128_Start     _ANSI_ARGS_ ((VOID* context));
60static void MDrmd128_Update    _ANSI_ARGS_ ((VOID* context, unsigned int character));
61static void MDrmd128_UpdateBuf _ANSI_ARGS_ ((VOID* context, unsigned char* buffer, int bufLen));
62static void MDrmd128_Final     _ANSI_ARGS_ ((VOID* context, VOID* digest));
63static void CountLength  _ANSI_ARGS_ ((ripemd_context* ctx,
64				       unsigned int    nbytes));
65
66/*
67 * Generator definition.
68 */
69
70static Trf_MessageDigestDescription mdDescription = { /* THREADING: constant, read-only => safe */
71  "ripemd128",
72  sizeof (ripemd_context),
73  DIGEST_SIZE,
74  MDrmd128_Start,
75  MDrmd128_Update,
76  MDrmd128_UpdateBuf,
77  MDrmd128_Final,
78  NULL
79};
80
81/*
82 *------------------------------------------------------*
83 *
84 *	TrfInit_RIPEMD128 --
85 *
86 *	------------------------------------------------*
87 *	Register the generator implemented in this file.
88 *	------------------------------------------------*
89 *
90 *	Sideeffects:
91 *		As of 'Trf_Register'.
92 *
93 *	Result:
94 *		A standard Tcl error code.
95 *
96 *------------------------------------------------------*
97 */
98
99int
100TrfInit_RIPEMD128 (interp)
101Tcl_Interp* interp;
102{
103  return Trf_RegisterMessageDigest (interp, &mdDescription);
104}
105
106/*
107 *------------------------------------------------------*
108 *
109 *	MDrmd128_Start --
110 *
111 *	------------------------------------------------*
112 *	Initialize the internal state of the message
113 *	digest generator.
114 *	------------------------------------------------*
115 *
116 *	Sideeffects:
117 *		As of the called procedure.
118 *
119 *	Result:
120 *		None.
121 *
122 *------------------------------------------------------*
123 */
124
125static void
126MDrmd128_Start (context)
127VOID* context;
128{
129  ripemd_context* ctx = (ripemd_context*) context;
130
131  ripemd128_MDinit (ctx->state);
132  memset (ctx->buf, '\0', CHUNK_SIZE);
133
134  ctx->byteCount = 0;
135  ctx->lowc     = 0;
136  ctx->highc    = 0;
137}
138
139/*
140 *------------------------------------------------------*
141 *
142 *	MDrmd128_Update --
143 *
144 *	------------------------------------------------*
145 *	Update the internal state of the message digest
146 *	generator for a single character.
147 *	------------------------------------------------*
148 *
149 *	Sideeffects:
150 *		As of the called procedure.
151 *
152 *	Result:
153 *		None.
154 *
155 *------------------------------------------------------*
156 */
157
158static void
159MDrmd128_Update (context, character)
160VOID* context;
161unsigned int   character;
162{
163  ripemd_context* ctx = (ripemd_context*) context;
164
165  ctx->buf [ctx->byteCount] = character;
166  ctx->byteCount ++;
167
168  if (ctx->byteCount == CHUNK_SIZE) {
169    CountLength (ctx, CHUNK_SIZE);
170
171#ifdef WORDS_BIGENDIAN
172    Trf_FlipRegisterLong (ctx->buf, CHUNK_SIZE);
173#endif
174    ripemd128_compress (ctx->state, (dword*) ctx->buf);
175    ctx->byteCount = 0;
176  }
177}
178
179/*
180 *------------------------------------------------------*
181 *
182 *	MDrmd128_UpdateBuf --
183 *
184 *	------------------------------------------------*
185 *	Update the internal state of the message digest
186 *	generator for a character buffer.
187 *	------------------------------------------------*
188 *
189 *	Sideeffects:
190 *		As of the called procedure.
191 *
192 *	Result:
193 *		None.
194 *
195 *------------------------------------------------------*
196 */
197
198static void
199MDrmd128_UpdateBuf (context, buffer, bufLen)
200VOID* context;
201unsigned char* buffer;
202int   bufLen;
203{
204  ripemd_context* ctx = (ripemd_context*) context;
205
206  if ((ctx->byteCount + bufLen) < CHUNK_SIZE) {
207    /*
208     * Not enough for full chunk. Remember incoming
209     * data and wait for another call containing more data.
210     */
211
212    memcpy ((VOID*) (ctx->buf + ctx->byteCount), (VOID*) buffer, bufLen);
213    ctx->byteCount += bufLen;
214  } else {
215    /*
216     * Complete chunk with incoming data, update digest,
217     * then use all chunks contained in the buffer. Remember
218     * an incomplete chunk and wait for further calls.
219     */
220
221    int k = CHUNK_SIZE - ctx->byteCount;
222
223    if (k < CHUNK_SIZE) {
224      memcpy ((VOID*) (ctx->buf + ctx->byteCount), (VOID*) buffer, k);
225
226      CountLength (ctx, CHUNK_SIZE);
227
228#ifdef WORDS_BIGENDIAN
229      Trf_FlipRegisterLong (ctx->buf, CHUNK_SIZE);
230#endif
231      ripemd128_compress (ctx->state, (dword*) ctx->buf);
232
233      buffer += k;
234      bufLen -= k;
235    } /* k == CHUNK_SIZE => internal buffer was empty, so skip it entirely */
236
237    while (bufLen >= CHUNK_SIZE) {
238      CountLength (ctx, CHUNK_SIZE);
239
240#ifdef WORDS_BIGENDIAN
241      Trf_FlipRegisterLong (buffer, CHUNK_SIZE);
242#endif
243      ripemd128_compress (ctx->state, (dword*) buffer);
244#ifdef WORDS_BIGENDIAN
245      Trf_FlipRegisterLong (buffer, CHUNK_SIZE);
246#endif
247
248      buffer += CHUNK_SIZE;
249      bufLen -= CHUNK_SIZE;
250    }
251
252    ctx->byteCount = bufLen;
253    if (bufLen > 0) {
254      memcpy ((VOID*) ctx->buf, (VOID*) buffer, bufLen);
255    }
256  }
257}
258
259/*
260 *------------------------------------------------------*
261 *
262 *	MDrmd128_Final --
263 *
264 *	------------------------------------------------*
265 *	Generate the digest from the internal state of
266 *	the message digest generator.
267 *	------------------------------------------------*
268 *
269 *	Sideeffects:
270 *		As of the called procedure.
271 *
272 *	Result:
273 *		None.
274 *
275 *------------------------------------------------------*
276 */
277
278static void
279MDrmd128_Final (context, digest)
280VOID* context;
281VOID* digest;
282{
283  ripemd_context* ctx = (ripemd_context*) context;
284
285  CountLength (ctx, ctx->byteCount);
286
287  ripemd128_MDfinish (ctx->state, ctx->buf, ctx->lowc, ctx->highc);
288
289  memcpy (digest, ctx->state, DIGEST_SIZE);
290#ifdef WORDS_BIGENDIAN
291  Trf_FlipRegisterLong (digest, DIGEST_SIZE);
292#endif
293}
294
295/*
296 *------------------------------------------------------*
297 *
298 *	CountLength --
299 *
300 *	------------------------------------------------*
301 *	Update the 64bit counter in the context structure
302 *	------------------------------------------------*
303 *
304 *	Sideeffects:
305 *		See above.
306 *
307 *	Result:
308 *		None.
309 *
310 *------------------------------------------------------*
311 */
312
313static void
314CountLength (ctx, nbytes)
315     ripemd_context* ctx;
316     unsigned int    nbytes;
317{
318  /* update length counter */
319
320  if ((ctx->lowc + nbytes) < ctx->lowc) {
321    /* overflow to msb of length */
322    ctx->highc ++;
323  }
324
325  ctx->lowc += nbytes;
326}
327
328/*
329 * External code from here on.
330 */
331
332#include "ripemd/rmd128.c"
333