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