Mercurial > ecos
diff packages/net/snmp/lib/current/src/md5.c @ 103:95f3e12a6327 ecos-sw-2000-06-23
Merge from eCos master repository on 2000-06-23-16:41:10-BST
| author | jlarmour |
|---|---|
| date | Fri, 23 Jun 2000 17:06:31 +0000 |
| parents | |
| children | e0c0827131d1 |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/packages/net/snmp/lib/current/src/md5.c @@ -0,0 +1,530 @@ +//========================================================================== +// +// ./lib/current/src/md5.c +// +// +//========================================================================== +//####COPYRIGHTBEGIN#### +// +// ------------------------------------------- +// The contents of this file are subject to the Red Hat eCos Public License +// Version 1.1 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://www.redhat.com/ +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +// License for the specific language governing rights and limitations under +// the License. +// +// The Original Code is eCos - Embedded Configurable Operating System, +// released September 30, 1998. +// +// The Initial Developer of the Original Code is Red Hat. +// Portions created by Red Hat are +// Copyright (C) 1998, 1999, 2000 Red Hat, Inc. +// All Rights Reserved. +// ------------------------------------------- +// +//####COPYRIGHTEND#### +//####UCDSNMPCOPYRIGHTBEGIN#### +// +// ------------------------------------------- +// +// Portions of this software may have been derived from the UCD-SNMP +// project, <http://ucd-snmp.ucdavis.edu/> from the University of +// California at Davis, which was originally based on the Carnegie Mellon +// University SNMP implementation. Portions of this software are therefore +// covered by the appropriate copyright disclaimers included herein. +// +// The release used was version 4.1.2 of May 2000. "ucd-snmp-4.1.2" +// ------------------------------------------- +// +//####UCDSNMPCOPYRIGHTEND#### +//========================================================================== +//#####DESCRIPTIONBEGIN#### +// +// Author(s): hmt +// Contributors: hmt +// Date: 2000-05-30 +// Purpose: Port of UCD-SNMP distribution to eCos. +// Description: +// +// +//####DESCRIPTIONEND#### +// +//========================================================================== +/******************************************************************** + Copyright 1989, 1991, 1992 by Carnegie Mellon University + + Derivative Work - +Copyright 1996, 1998, 1999, 2000 The Regents of the University of California + + All Rights Reserved + +Permission to use, copy, modify and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appears in all copies and +that both that copyright notice and this permission notice appear in +supporting documentation, and that the name of CMU and The Regents of +the University of California not be used in advertising or publicity +pertaining to distribution of the software without specific written +permission. + +CMU AND THE REGENTS OF THE UNIVERSITY OF CALIFORNIA DISCLAIM ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL CMU OR +THE REGENTS OF THE UNIVERSITY OF CALIFORNIA BE LIABLE FOR ANY SPECIAL, +INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING +FROM THE LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF +CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*********************************************************************/ +/* +** ************************************************************************** +** md5.c -- Implementation of MD5 Message Digest Algorithm ** +** Updated: 2/16/90 by Ronald L. Rivest ** +** (C) 1990 RSA Data Security, Inc. ** +** ************************************************************************** +*/ + +/* +** To use MD5: +** -- Include md5.h in your program +** -- Declare an MDstruct MD to hold the state of the digest computation. +** -- Initialize MD using MDbegin(&MD) +** -- For each full block (64 bytes) X you wish to process, call +** MDupdate(&MD,X,512) +** (512 is the number of bits in a full block.) +** -- For the last block (less than 64 bytes) you wish to process, +** MDupdate(&MD,X,n) +** where n is the number of bits in the partial block. A partial +** block terminates the computation, so every MD computation should +** terminate by processing a partial block, even if it has n = 0. +** -- The message digest is available in MD.buffer[0] ... MD.buffer[3]. +** (Least-significant byte of each word should be output first.) +** -- You can print out the digest using MDprint(&MD) +*/ + +/* Implementation notes: +** This implementation assumes that ints are 32-bit quantities. +** If the machine stores the least-significant byte of an int in the +** least-addressed byte (eg., VAX and 8086), then LOWBYTEFIRST should be +** set to TRUE. Otherwise (eg., SUNS), LOWBYTEFIRST should be set to +** FALSE. Note that on machines with LOWBYTEFIRST FALSE the routine +** MDupdate modifies has a side-effect on its input array (the order of bytes +** in each word are reversed). If this is undesired a call to MDreverse(X) can +** reverse the bytes of X back into order after each call to MDupdate. +*/ + +/* code uses WORDS_BIGENDIAN defined by configure now -- WH 9/27/95 */ + +/* Compile-time includes +*/ + +#include <config.h> + +#include <stdio.h> +#include <sys/types.h> +#if HAVE_STRING_H +#include <string.h> +#else +#include <strings.h> +#endif +#if HAVE_WINSOCK_H +#include <winsock.h> +#endif + +#include "md5.h" + +/* Compile-time declarations of MD5 ``magic constants''. +*/ +#define I0 0x67452301 /* Initial values for MD buffer */ +#define I1 0xefcdab89 +#define I2 0x98badcfe +#define I3 0x10325476 +#define fs1 7 /* round 1 shift amounts */ +#define fs2 12 +#define fs3 17 +#define fs4 22 +#define gs1 5 /* round 2 shift amounts */ +#define gs2 9 +#define gs3 14 +#define gs4 20 +#define hs1 4 /* round 3 shift amounts */ +#define hs2 11 +#define hs3 16 +#define hs4 23 +#define is1 6 /* round 4 shift amounts */ +#define is2 10 +#define is3 15 +#define is4 21 + + +/* Compile-time macro declarations for MD5. +** Note: The ``rot'' operator uses the variable ``tmp''. +** It assumes tmp is declared as unsigned int, so that the >> +** operator will shift in zeros rather than extending the sign bit. +*/ +#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 rot(X,S) (tmp=X,(tmp<<S) | (tmp>>(32-S))) +#define ff(A,B,C,D,i,s,lp) A = rot((A + f(B,C,D) + X[i] + lp),s) + B +#define gg(A,B,C,D,i,s,lp) A = rot((A + g(B,C,D) + X[i] + lp),s) + B +#define hh(A,B,C,D,i,s,lp) A = rot((A + h(B,C,D) + X[i] + lp),s) + B +#define ii(A,B,C,D,i,s,lp) A = rot((A + i_(B,C,D) + X[i] + lp),s) + B + +#ifdef STDC_HEADERS +#define Uns(num) num##U +#else +#define Uns(num) num +#endif /* STDC_HEADERS */ + +void MDreverse (unsigned int *); +static void MDblock (MDptr, unsigned int *); + +#ifdef SNMP_TESTING_CODE +/* MDprint(MDp) +** Print message digest buffer MDp as 32 hexadecimal digits. +** Order is from low-order byte of buffer[0] to high-order byte of buffer[3]. +** Each byte is printed with high-order hexadecimal digit first. +** This is a user-callable routine. +*/ +void +MDprint(MDptr MDp) +{ + int i,j; + for (i=0;i<4;i++) + for (j=0;j<32;j=j+8) + printf("%02x",(MDp->buffer[i]>>j) & 0xFF); + printf("\n"); + fflush(stdout); +} +#endif /* SNMP_TESTING_CODE */ + +/* MDbegin(MDp) +** Initialize message digest buffer MDp. +** This is a user-callable routine. +*/ +void +MDbegin(MDptr MDp) +{ + int i; + MDp->buffer[0] = I0; + MDp->buffer[1] = I1; + MDp->buffer[2] = I2; + MDp->buffer[3] = I3; + for (i=0;i<8;i++) MDp->count[i] = 0; + MDp->done = 0; +} + +/* MDreverse(X) +** Reverse the byte-ordering of every int in X. +** Assumes X is an array of 16 ints. +** The macro revx reverses the byte-ordering of the next word of X. +*/ +#define revx { t = (*X << 16) | (*X >> 16); \ + *X++ = ((t & 0xFF00FF00) >> 8) | ((t & 0x00FF00FF) << 8); } + +void MDreverse(unsigned int *X) +{ + register unsigned int t; + revx; revx; revx; revx; revx; revx; revx; revx; + revx; revx; revx; revx; revx; revx; revx; revx; +} + +/* MDblock(MDp,X) +** Update message digest buffer MDp->buffer using 16-word data block X. +** Assumes all 16 words of X are full of data. +** Does not update MDp->count. +** This routine is not user-callable. +*/ +static void +MDblock(MDptr MDp, + unsigned int *X) +{ + register unsigned int tmp, A, B, C, D; /* hpux sysv sun */ +#ifdef WORDS_BIGENDIAN + MDreverse(X); +#endif + A = MDp->buffer[0]; + B = MDp->buffer[1]; + C = MDp->buffer[2]; + D = MDp->buffer[3]; + + /* Update the message digest buffer */ + ff(A , B , C , D , 0 , fs1 , Uns(3614090360)); /* Round 1 */ + ff(D , A , B , C , 1 , fs2 , Uns(3905402710)); + ff(C , D , A , B , 2 , fs3 , Uns(606105819)); + ff(B , C , D , A , 3 , fs4 , Uns(3250441966)); + ff(A , B , C , D , 4 , fs1 , Uns(4118548399)); + ff(D , A , B , C , 5 , fs2 , Uns(1200080426)); + ff(C , D , A , B , 6 , fs3 , Uns(2821735955)); + ff(B , C , D , A , 7 , fs4 , Uns(4249261313)); + ff(A , B , C , D , 8 , fs1 , Uns(1770035416)); + ff(D , A , B , C , 9 , fs2 , Uns(2336552879)); + ff(C , D , A , B , 10 , fs3 , Uns(4294925233)); + ff(B , C , D , A , 11 , fs4 , Uns(2304563134)); + ff(A , B , C , D , 12 , fs1 , Uns(1804603682)); + ff(D , A , B , C , 13 , fs2 , Uns(4254626195)); + ff(C , D , A , B , 14 , fs3 , Uns(2792965006)); + ff(B , C , D , A , 15 , fs4 , Uns(1236535329)); + gg(A , B , C , D , 1 , gs1 , Uns(4129170786)); /* Round 2 */ + gg(D , A , B , C , 6 , gs2 , Uns(3225465664)); + gg(C , D , A , B , 11 , gs3 , Uns(643717713)); + gg(B , C , D , A , 0 , gs4 , Uns(3921069994)); + gg(A , B , C , D , 5 , gs1 , Uns(3593408605)); + gg(D , A , B , C , 10 , gs2 , Uns(38016083)); + gg(C , D , A , B , 15 , gs3 , Uns(3634488961)); + gg(B , C , D , A , 4 , gs4 , Uns(3889429448)); + gg(A , B , C , D , 9 , gs1 , Uns(568446438)); + gg(D , A , B , C , 14 , gs2 , Uns(3275163606)); + gg(C , D , A , B , 3 , gs3 , Uns(4107603335)); + gg(B , C , D , A , 8 , gs4 , Uns(1163531501)); + gg(A , B , C , D , 13 , gs1 , Uns(2850285829)); + gg(D , A , B , C , 2 , gs2 , Uns(4243563512)); + gg(C , D , A , B , 7 , gs3 , Uns(1735328473)); + gg(B , C , D , A , 12 , gs4 , Uns(2368359562)); + hh(A , B , C , D , 5 , hs1 , Uns(4294588738)); /* Round 3 */ + hh(D , A , B , C , 8 , hs2 , Uns(2272392833)); + hh(C , D , A , B , 11 , hs3 , Uns(1839030562)); + hh(B , C , D , A , 14 , hs4 , Uns(4259657740)); + hh(A , B , C , D , 1 , hs1 , Uns(2763975236)); + hh(D , A , B , C , 4 , hs2 , Uns(1272893353)); + hh(C , D , A , B , 7 , hs3 , Uns(4139469664)); + hh(B , C , D , A , 10 , hs4 , Uns(3200236656)); + hh(A , B , C , D , 13 , hs1 , Uns(681279174)); + hh(D , A , B , C , 0 , hs2 , Uns(3936430074)); + hh(C , D , A , B , 3 , hs3 , Uns(3572445317)); + hh(B , C , D , A , 6 , hs4 , Uns(76029189)); + hh(A , B , C , D , 9 , hs1 , Uns(3654602809)); + hh(D , A , B , C , 12 , hs2 , Uns(3873151461)); + hh(C , D , A , B , 15 , hs3 , Uns(530742520)); + hh(B , C , D , A , 2 , hs4 , Uns(3299628645)); + ii(A , B , C , D , 0 , is1 , Uns(4096336452)); /* Round 4 */ + ii(D , A , B , C , 7 , is2 , Uns(1126891415)); + ii(C , D , A , B , 14 , is3 , Uns(2878612391)); + ii(B , C , D , A , 5 , is4 , Uns(4237533241)); + ii(A , B , C , D , 12 , is1 , Uns(1700485571)); + ii(D , A , B , C , 3 , is2 , Uns(2399980690)); + ii(C , D , A , B , 10 , is3 , Uns(4293915773)); + ii(B , C , D , A , 1 , is4 , Uns(2240044497)); + ii(A , B , C , D , 8 , is1 , Uns(1873313359)); + ii(D , A , B , C , 15 , is2 , Uns(4264355552)); + ii(C , D , A , B , 6 , is3 , Uns(2734768916)); + ii(B , C , D , A , 13 , is4 , Uns(1309151649)); + ii(A , B , C , D , 4 , is1 , Uns(4149444226)); + ii(D , A , B , C , 11 , is2 , Uns(3174756917)); + ii(C , D , A , B , 2 , is3 , Uns(718787259)); + ii(B , C , D , A , 9 , is4 , Uns(3951481745)); + + MDp->buffer[0] += A; + MDp->buffer[1] += B; + MDp->buffer[2] += C; + MDp->buffer[3] += D; +#ifdef WORDS_BIGENDIAN + MDreverse(X); +#endif +} + +/* MDupdate(MDp,X,count) +** Input: MDp -- an MDptr +** X -- a pointer to an array of unsigned characters. +** count -- the number of bits of X to use. +** (if not a multiple of 8, uses high bits of last byte.) +** Update MDp using the number of bits of X given by count. +** This is the basic input routine for an MD5 user. +** The routine completes the MD computation when count < 512, so +** every MD computation should end with one call to MDupdate with a +** count less than 512. A call with count 0 will be ignored if the +** MD has already been terminated (done != 0), so an extra call with count +** 0 can be given as a ``courtesy close'' to force termination if desired. +** Returns : 0 if processing succeeds or was already done; +** -1 if processing was already done +** -2 if count was too large +*/ +int +MDupdate(MDptr MDp, + unsigned char *X, + unsigned int count) +{ + unsigned int i, tmp, bit, byte, mask; + unsigned char XX[64]; + unsigned char *p; + /* return with no error if this is a courtesy close with count + ** zero and MDp->done is true. + */ + if (count == 0 && MDp->done) return 0; + /* check to see if MD is already done and report error */ + if (MDp->done) { return -1; } +/* + if (MDp->done) { fprintf(stderr,"\nError: MDupdate MD already done."); return; } +*/ + /* Add count to MDp->count */ + tmp = count; + p = MDp->count; + while (tmp) + { tmp += *p; + *p++ = tmp; + tmp = tmp >> 8; + } + /* Process data */ + if (count == 512) + { /* Full block of data to handle */ + MDblock(MDp,(unsigned int *)X); + } + else if (count > 512) /* Check for count too large */ + return -2; +/* + { fprintf(stderr,"\nError: MDupdate called with illegal count value %d.",count); + return; + } +*/ + else /* partial block -- must be last block so finish up */ + { /* Find out how many bytes and residual bits there are */ + int copycount; + byte = count >> 3; + bit = count & 7; + copycount = byte; if (bit) copycount++; + /* Copy X into XX since we need to modify it */ + memset(XX,0,sizeof(XX)); + memcpy(XX,X,copycount); + + /* Add padding '1' bit and low-order zeros in last byte */ + mask = ((unsigned long)1) << (7 - bit); + XX[byte] = (XX[byte] | mask) & ~( mask - 1); + /* If room for bit count, finish up with this block */ + if (byte <= 55) + { for (i=0;i<8;i++) XX[56+i] = MDp->count[i]; + MDblock(MDp,(unsigned int *)XX); + } + else /* need to do two blocks to finish up */ + { MDblock(MDp,(unsigned int *)XX); + for (i=0;i<56;i++) XX[i] = 0; + for (i=0;i<8;i++) XX[56+i] = MDp->count[i]; + MDblock(MDp,(unsigned int *)XX); + } + /* Set flag saying we're done with MD computation */ + MDp->done = 1; + } + return 0; +} + +/* MDchecksum(data, len, MD5): do a checksum on an arbirtrary amount of data */ +int +MDchecksum(u_char *data, size_t len, u_char *mac, size_t maclen) +{ + MDstruct md; + MDstruct *MD = &md; + int rc = 0; + + MDbegin(MD); + while (len >= 64) { + rc = MDupdate(MD, data, 64*8); + if (rc) goto check_end; + data += 64; + len -= 64; + } + rc = MDupdate(MD, data, len*8); + if (rc) goto check_end; + + /* copy the checksum to the outgoing data (all of it that is requested). */ + MDget(MD, mac, maclen); + +check_end: + memset(&md,0,sizeof(md)); + return rc; +} + + +/* MDsign(data, len, MD5): do a checksum on an arbirtrary amount + of data, and prepended with a secret in the standard fashion */ +int +MDsign(u_char *data, size_t len, u_char *mac, size_t maclen, + u_char *secret, size_t secretlen) +{ +#define HASHKEYLEN 64 + + MDstruct MD; + u_char K1[HASHKEYLEN]; + u_char K2[HASHKEYLEN]; + u_char extendedAuthKey[HASHKEYLEN]; + u_char buf[HASHKEYLEN]; + size_t i; + u_char *cp; + int rc = 0; + +/* + memset(K1,0,HASHKEYLEN); + memset(K2,0,HASHKEYLEN); + memset(buf,0,HASHKEYLEN); + memset(extendedAuthKey,0,HASHKEYLEN); +*/ + + if (secretlen != 16 || secret == NULL || mac == NULL || data == NULL || + len <= 0 || maclen <= 0) { +/* DEBUGMSGTL(("md5","MD5 signing not properly initialized")); */ + return -1; + } + + memset(extendedAuthKey, 0, HASHKEYLEN); + memcpy(extendedAuthKey, secret, secretlen); + for(i = 0; i < HASHKEYLEN; i++) { + K1[i] = extendedAuthKey[i] ^ 0x36; + K2[i] = extendedAuthKey[i] ^ 0x5c; + } + + MDbegin(&MD); + rc = MDupdate(&MD, K1, HASHKEYLEN*8); + if (rc) goto update_end; + + i = len; + cp = data; + while (i >= 64) { + rc = MDupdate(&MD, cp, 64*8); + if (rc) goto update_end; + cp += 64; + i -= 64; + } + + rc = MDupdate(&MD, cp, i*8); + if (rc) goto update_end; + + memset(buf,0,HASHKEYLEN); + MDget(&MD, buf, HASHKEYLEN); + + MDbegin(&MD); + rc = MDupdate(&MD, K2, HASHKEYLEN*8); + if (rc) goto update_end; + rc = MDupdate(&MD, buf, 16*8); + if (rc) goto update_end; + + /* copy the sign checksum to the outgoing pointer */ + MDget(&MD, mac, maclen); + +update_end: + memset(buf, 0, HASHKEYLEN); + memset(K1, 0, HASHKEYLEN); + memset(K2, 0, HASHKEYLEN); + memset(extendedAuthKey, 0, HASHKEYLEN); + memset(&MD, 0, sizeof(MD)); + + return rc; +} + +void +MDget(MDstruct *MD, u_char *buf, size_t buflen) +{ + int i, j; + + /* copy the checksum to the outgoing data (all of it that is requested). */ + for(i=0; i < 4 && i*4 < (int)buflen; i++) + for(j=0; j < 4 && i*4+j < (int)buflen; j++) + buf[i*4+j] = (MD->buffer[i] >> j*8) & 0xff; +} + +/* +** End of md5.c +****************************(cut)*****************************************/
