auth_md5.c
上传用户:ycwykj01
上传日期:2007-01-04
资源大小:1819k
文件大小:16k
源码类别:

网络编程

开发平台:

Unix_Linux

  1. /*
  2.  * Program: CRAM-MD5 authenticator
  3.  *
  4.  * Author: Mark Crispin
  5.  * Networks and Distributed Computing
  6.  * Computing & Communications
  7.  * University of Washington
  8.  * Administration Building, AG-44
  9.  * Seattle, WA  98195
  10.  * Internet: MRC@CAC.Washington.EDU
  11.  *
  12.  * Date: 21 October 1998
  13.  * Last Edited: 14 September 1999
  14.  *
  15.  * Copyright 1999 by the University of Washington
  16.  *
  17.  *  Permission to use, copy, modify, and distribute this software and its
  18.  * documentation for any purpose and without fee is hereby granted, provided
  19.  * that the above copyright notice appears in all copies and that both the
  20.  * above copyright notice and this permission notice appear in supporting
  21.  * documentation, and that the name of the University of Washington not be
  22.  * used in advertising or publicity pertaining to distribution of the software
  23.  * without specific, written prior permission.  This software is made available
  24.  * "as is", and
  25.  * THE UNIVERSITY OF WASHINGTON DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED,
  26.  * WITH REGARD TO THIS SOFTWARE, INCLUDING WITHOUT LIMITATION ALL IMPLIED
  27.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, AND IN
  28.  * NO EVENT SHALL THE UNIVERSITY OF WASHINGTON BE LIABLE FOR ANY SPECIAL,
  29.  * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  30.  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, TORT
  31.  * (INCLUDING NEGLIGENCE) OR STRICT LIABILITY, ARISING OUT OF OR IN CONNECTION
  32.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  33.  *
  34.  */
  35. /* MD5 context */
  36. #define MD5BLKLEN 64 /* MD5 block length */
  37. #define MD5DIGLEN 16 /* MD5 digest length */
  38. typedef struct {
  39.   unsigned long chigh; /* high 32bits of byte count */
  40.   unsigned long clow; /* low 32bits of byte count */
  41.   unsigned long state[4]; /* state (ABCD) */
  42.   unsigned char buf[MD5BLKLEN]; /* input buffer */
  43.   unsigned char *ptr; /* buffer position */
  44. } MD5CONTEXT;
  45. /* Prototypes */
  46. long auth_md5_valid (void);
  47. long auth_md5_client (authchallenge_t challenger,authrespond_t responder,
  48.       NETMBX *mb,void *stream,unsigned long *trial,char *user);
  49. char *auth_md5_server (authresponse_t responder,int argc,char *argv[]);
  50. char *auth_md5_pwd (char *user);
  51. char *apop_login (char *chal,char *user,char *md5,int argc,char *argv[]);
  52. char *hmac_md5 (char *text,unsigned long tl,char *key,unsigned long kl);
  53. void md5_init (MD5CONTEXT *ctx);
  54. void md5_update (MD5CONTEXT *ctx,unsigned char *data,unsigned long len);
  55. void md5_final (unsigned char *digest,MD5CONTEXT *ctx);
  56. static void md5_transform (unsigned long *state,unsigned char *block);
  57. static void md5_encode (unsigned char *dst,unsigned long *src,int len);
  58. static void md5_decode (unsigned long *dst,unsigned char *src,int len);
  59. /* Authenticator linkage */
  60. AUTHENTICATOR auth_md5 = {
  61.   T, /* secure authenticator */
  62.   "CRAM-MD5", /* authenticator name */
  63.   auth_md5_valid, /* check if valid */
  64.   auth_md5_client, /* client method */
  65.   auth_md5_server, /* server method */
  66.   NIL /* next authenticator */
  67. };
  68. /* Check if CRAM-MD5 valid on this system
  69.  * Returns: T, always
  70.  */
  71. long auth_md5_valid (void)
  72. {
  73.   struct stat sbuf;
  74. /* server forbids MD5 if no MD5 enable file */
  75.   if (stat (MD5ENABLE,&sbuf)) auth_md5.server = NIL;
  76.   return T; /* MD5 is otherwise valid */
  77. }
  78. /* Client authenticator
  79.  * Accepts: challenger function
  80.  *     responder function
  81.  *     parsed network mailbox structure
  82.  *     stream argument for functions
  83.  *     pointer to current trial count
  84.  *     returned user name
  85.  * Returns: T if success, NIL otherwise, number of trials incremented if retry
  86.  */
  87. long auth_md5_client (authchallenge_t challenger,authrespond_t responder,
  88.       NETMBX *mb,void *stream,unsigned long *trial,char *user)
  89. {
  90.   char pwd[MAILTMPLEN],resp[MAILTMPLEN];
  91.   void *chal;
  92.   unsigned long cl;
  93. /* get challenge */
  94.   if (chal = (*challenger) (stream,&cl)) {
  95. /* prompt user */
  96.     mm_login (mb,user,pwd,*trial);
  97.     if (pwd[0]) { /* got password, build response */
  98.       sprintf (resp,"%s %s",user,hmac_md5 (chal,cl,pwd,strlen (pwd)));
  99.       fs_give ((void **) &chal);/* don't need challenge any moe */
  100. /* send credentials, allow retry if OK */
  101.       if ((*responder) (stream,resp,strlen (resp)) &&
  102.   !(chal = (*challenger) (stream,&cl))) return (long) ++*trial;
  103.     }
  104. /* user requested abort */
  105.     else (*responder) (stream,NIL,0);
  106.   }
  107. /* flush any challenge left behind */
  108.   if (chal) fs_give ((void **) &chal);
  109.   *trial = 0; /* retries not permitted */
  110.   return NIL; /* return failure */
  111. }
  112. /* Server authenticator
  113.  * Accepts: responder function
  114.  *     argument count
  115.  *     argument vector
  116.  * Returns: authenticated user name or NIL
  117.  *
  118.  * This is much hairier than it needs to be due to the necessary of zapping
  119.  * the password data.
  120.  */
  121. char *auth_md5_server (authresponse_t responder,int argc,char *argv[])
  122. {
  123.   char *ret = NIL;
  124.   char *p,*u,*user,*hash,chal[MAILTMPLEN];
  125.   unsigned long cl,pl;
  126. /* generate challenge */
  127.   sprintf (chal,"<%lu.%lu@%s>",(unsigned long) getpid (),
  128.    (unsigned long) time (0),mylocalhost ());
  129. /* send challenge, get user and hash */
  130.   if (user = (*responder) (chal,cl = strlen (chal),NIL)) {
  131. /* got user, locate hash */
  132.     if (hash = strrchr (user,' ')) {
  133.       *hash++ = ''; /* tie off user */
  134.       if ((p = auth_md5_pwd (user)) || (p = auth_md5_pwd (lcase (user)))) {
  135. /* quickly verify password */
  136. u = strcmp (hash,hmac_md5 (chal,cl,p,pl = strlen (p))) ? NIL : user;
  137. memset (p,0,pl); /* erase sensitive information */
  138. fs_give ((void **) &p); /* flush erased password */
  139. /* now log in for real */
  140. if (u && authserver_login (u,argc,argv)) ret = myusername ();
  141.       }
  142.     }
  143.     fs_give ((void **) &user);
  144.   }
  145.   if (!ret) sleep (3); /* slow down poassible cracker */
  146.   return ret;
  147. }
  148. /* Return MD5 password for user
  149.  * Accepts: user name
  150.  * Returns: plaintext password if success, else NIL
  151.  *
  152.  * This is much hairier than it needs to be due to the necessary of zapping
  153.  * the password data.
  154.  */
  155. char *auth_md5_pwd (char *user)
  156. {
  157.   struct stat sbuf;
  158.   int fd = open (MD5ENABLE,O_RDONLY,NIL);
  159.   char *s,*t,*buf;
  160.   char *ret = NIL;
  161.   if (fd >= 0) { /* found the file? */
  162.     if (!fstat (fd,&sbuf)) { /* yes, slurp it into memory */
  163.       read (fd,buf = (char *) fs_get (sbuf.st_size + 1),sbuf.st_size);
  164.       for (s = strtok (buf,"1512"); s;
  165.    s = ret ? NIL : strtok (NIL,"1512"))
  166. /* must be valid entry line */
  167. if ((*s != '#') && (t = strchr (s,'t'))) {
  168.   *t++ = ''; /* found tab, tie off user, point to pwd */
  169.   if (*s && *t && !strcmp (s,user)) ret = cpystr (t);
  170. }
  171. /* erase sensitive information from buffer */
  172.       memset (buf,0,sbuf.st_size + 1);
  173.       fs_give ((void **) &buf); /* flush the buffer */
  174.     }
  175.     close (fd); /* don't need file any longer */
  176.   }
  177.   return ret; /* return password */
  178. }
  179. /* APOP server login
  180.  * Accepts: challenge
  181.  *     desired user name
  182.  *     purported MD5
  183.  *     argument count
  184.  *     argument vector
  185.  * Returns: authenticated user name or NIL
  186.  */
  187. char *apop_login (char *chal,char *user,char *md5,int argc,char *argv[])
  188. {
  189.   int i,j;
  190.   char *ret = NIL;
  191.   char *s,tmp[MAILTMPLEN];
  192.   unsigned char digest[MD5DIGLEN];
  193.   MD5CONTEXT ctx;
  194.   char *hex = "0123456789abcdef";
  195.   if ((s = auth_md5_pwd (user)) || (s = auth_md5_pwd (lcase (user)))) {
  196.     md5_init (&ctx); /* initialize MD5 context */
  197. /* build string to get MD5 digest */
  198.     sprintf (tmp,"%.128s%.128s",chal,s);
  199.     memset (s,0,strlen (s)); /* erase sensitive information */
  200.     fs_give ((void **) &s); /* flush erased password */
  201.     md5_update (&ctx,(unsigned char *) tmp,strlen (tmp));
  202.     memset (tmp,0,MAILTMPLEN); /* erase sensitive information */
  203.     md5_final (digest,&ctx);
  204. /* convert to printable hex */
  205.     for (i = 0, s = tmp; i < MD5DIGLEN; i++) {
  206.       *s++ = hex[(j = digest[i]) >> 4];
  207.       *s++ = hex[j & 0xf];
  208.     }
  209.     *s = ''; /* tie off hash text */
  210.     memset (digest,0,MD5DIGLEN);/* erase sensitive information */
  211.     if (!strcmp (md5,tmp) && authserver_login (user,argc,argv))
  212.       ret = cpystr (myusername ());
  213.     memset (tmp,0,MAILTMPLEN); /* erase sensitive information */
  214.   }
  215.   if (!ret) sleep (3); /* slow down poassible cracker */
  216.   return ret;
  217. }
  218. /*
  219.  * RFC 2104 HMAC hashing
  220.  * Accepts: text to hash
  221.  *     text length
  222.  *     key
  223.  *     key length
  224.  * Returns: hash as text, always
  225.  */
  226. char *hmac_md5 (char *text,unsigned long tl,char *key,unsigned long kl)
  227. {
  228.   int i,j;
  229.   static char hshbuf[2*MD5DIGLEN + 1];
  230.   char *s;
  231.   MD5CONTEXT ctx;
  232.   char *hex = "0123456789abcdef";
  233.   unsigned char digest[MD5DIGLEN],k_ipad[MD5BLKLEN+1],k_opad[MD5BLKLEN+1];
  234.   if (kl > MD5BLKLEN) { /* key longer than pad length? */
  235.     md5_init (&ctx); /* yes, set key as MD5(key) */
  236.     md5_update (&ctx,(unsigned char *) key,kl);
  237.     md5_final (digest,&ctx);
  238.     key = (char *) digest;
  239.     kl = MD5DIGLEN;
  240.   }
  241.   memcpy (k_ipad,key,kl); /* store key in pads */
  242.   memset (k_ipad+kl,0,(MD5BLKLEN+1)-kl);
  243.   memcpy (k_opad,k_ipad,MD5BLKLEN+1);
  244. /* XOR key with ipad and opad values */
  245.   for (i = 0; i < MD5BLKLEN; i++) {/* for each byte of pad */
  246.     k_ipad[i] ^= 0x36; /* XOR key with ipad */
  247.     k_opad[i] ^= 0x5c; /*  and opad values */
  248.   }
  249.   md5_init (&ctx); /* inner MD5: hash ipad and text */
  250.   md5_update (&ctx,k_ipad,MD5BLKLEN);
  251.   md5_update (&ctx,(unsigned char *) text,tl);
  252.   md5_final (digest,&ctx);
  253.   md5_init (&ctx); /* outer MD5: hash opad and inner results */
  254.   md5_update (&ctx,k_opad,MD5BLKLEN);
  255.   md5_update (&ctx,digest,MD5DIGLEN);
  256.   md5_final (digest,&ctx);
  257. /* convert to printable hex */
  258.   for (i = 0, s = hshbuf; i < MD5DIGLEN; i++) {
  259.     *s++ = hex[(j = digest[i]) >> 4];
  260.     *s++ = hex[j & 0xf];
  261.   }
  262.   *s = ''; /* tie off hash text */
  263.   return hshbuf;
  264. }
  265. /* Everything after this point is derived from the RSA Data Security, Inc.
  266.  * MD5 Message-Digest Algorithm
  267.  */
  268. #define RND1(a,b,c,d,x,s,ac) 
  269.  a += ((b & c) | (d & ~b)) + x + (unsigned long) ac; 
  270.  a &= 0xffffffff; 
  271.  a = b + ((a << s) | (a >> (32 - s)));
  272. #define RND2(a,b,c,d,x,s,ac) 
  273.  a += ((b & d) | (c & ~d)) + x + (unsigned long) ac; 
  274.  a &= 0xffffffff; 
  275.  a = b + ((a << s) | (a >> (32 - s)));
  276. #define RND3(a,b,c,d,x,s,ac) 
  277.  a += (b ^ c ^ d) + x + (unsigned long) ac; 
  278.  a &= 0xffffffff; 
  279.  a = b + ((a << s) | (a >> (32 - s)));
  280. #define RND4(a,b,c,d,x,s,ac) 
  281.  a += (c ^ (b | ~d)) + x + (unsigned long) ac; 
  282.  a &= 0xffffffff; 
  283.  a = b + ((a << s) | (a >> (32 - s)));
  284. /* Initialize MD5 context
  285.  * Accepts: context to initialize
  286.  */
  287. void md5_init (MD5CONTEXT *ctx)
  288. {
  289.   ctx->clow = ctx->chigh = 0; /* initialize byte count to zero */
  290. /* initialization constants */
  291.   ctx->state[0] = 0x67452301; ctx->state[1] = 0xefcdab89;
  292.   ctx->state[2] = 0x98badcfe; ctx->state[3] = 0x10325476;
  293.   ctx->ptr = ctx->buf; /* reset buffer pointer */
  294. }
  295. /* MD5 add data to context
  296.  * Accepts: context
  297.  *     input data
  298.  *     length of data
  299.  */
  300. void md5_update (MD5CONTEXT *ctx,unsigned char *data,unsigned long len)
  301. {
  302.   unsigned long i = (ctx->buf + MD5BLKLEN) - ctx->ptr;
  303. /* update double precision number of bytes */
  304.   if ((ctx->clow += len) < len) ctx->chigh++;
  305.   while (i <= len) { /* copy/transform data, 64 bytes at a time */
  306.     memcpy (ctx->ptr,data,i); /* fill up 64 byte chunk */
  307.     md5_transform (ctx->state,ctx->ptr = ctx->buf);
  308.     data += i,len -= i,i = MD5BLKLEN;
  309.   }
  310.   memcpy (ctx->ptr,data,len); /* copy final bit of data in buffer */
  311.   ctx->ptr += len; /* update buffer pointer */
  312. }
  313. /* MD5 Finalization
  314.  * Accepts: destination digest
  315.  *     context
  316.  */
  317. void md5_final (unsigned char *digest,MD5CONTEXT *ctx)
  318. {
  319.   unsigned long i,bits[2];
  320.   bits[0] = ctx->clow << 3; /* calculate length in bits (before padding) */
  321.   bits[1] = (ctx->chigh << 3) + (ctx->clow >> 29);
  322.   *ctx->ptr++ = 0x80; /* padding byte */
  323.   if ((i = (ctx->buf + MD5BLKLEN) - ctx->ptr) < 8) {
  324.     memset (ctx->ptr,0,i); /* pad out buffer with zeros */
  325.     md5_transform (ctx->state,ctx->buf);
  326. /* pad out with zeros, leaving 8 bytes */
  327.     memset (ctx->buf,0,MD5BLKLEN - 8);
  328.     ctx->ptr = ctx->buf + MD5BLKLEN - 8;
  329.   }
  330.   else if (i -= 8) { /* need to pad this buffer? */
  331.     memset (ctx->ptr,0,i); /* yes, pad out with zeros, leaving 8 bytes */
  332.     ctx->ptr += i;
  333.   }
  334.   md5_encode (ctx->ptr,bits,2); /* make LSB-first length */
  335.   md5_transform (ctx->state,ctx->buf);
  336. /* store state in digest */
  337.   md5_encode (digest,ctx->state,4);
  338. /* erase context */
  339.   memset (ctx,0,sizeof (MD5CONTEXT));
  340. }
  341. /* MD5 basic transformation
  342.  * Accepts: state vector
  343.  *     current 64-byte block
  344.  */
  345. static void md5_transform (unsigned long *state,unsigned char *block)
  346. {
  347.   unsigned long a = state[0],b = state[1],c = state[2],d = state[3],x[16];
  348.   md5_decode (x,block,16); /* decode into 16 longs */
  349. /* round 1 */
  350.   RND1 (a,b,c,d,x[ 0], 7,0xd76aa478); RND1 (d,a,b,c,x[ 1],12,0xe8c7b756);
  351.   RND1 (c,d,a,b,x[ 2],17,0x242070db); RND1 (b,c,d,a,x[ 3],22,0xc1bdceee);
  352.   RND1 (a,b,c,d,x[ 4], 7,0xf57c0faf); RND1 (d,a,b,c,x[ 5],12,0x4787c62a);
  353.   RND1 (c,d,a,b,x[ 6],17,0xa8304613); RND1 (b,c,d,a,x[ 7],22,0xfd469501);
  354.   RND1 (a,b,c,d,x[ 8], 7,0x698098d8); RND1 (d,a,b,c,x[ 9],12,0x8b44f7af);
  355.   RND1 (c,d,a,b,x[10],17,0xffff5bb1); RND1 (b,c,d,a,x[11],22,0x895cd7be);
  356.   RND1 (a,b,c,d,x[12], 7,0x6b901122); RND1 (d,a,b,c,x[13],12,0xfd987193);
  357.   RND1 (c,d,a,b,x[14],17,0xa679438e); RND1 (b,c,d,a,x[15],22,0x49b40821);
  358. /* round 2 */
  359.   RND2 (a,b,c,d,x[ 1], 5,0xf61e2562); RND2 (d,a,b,c,x[ 6], 9,0xc040b340);
  360.   RND2 (c,d,a,b,x[11],14,0x265e5a51); RND2 (b,c,d,a,x[ 0],20,0xe9b6c7aa);
  361.   RND2 (a,b,c,d,x[ 5], 5,0xd62f105d); RND2 (d,a,b,c,x[10], 9, 0x2441453);
  362.   RND2 (c,d,a,b,x[15],14,0xd8a1e681); RND2 (b,c,d,a,x[ 4],20,0xe7d3fbc8);
  363.   RND2 (a,b,c,d,x[ 9], 5,0x21e1cde6); RND2 (d,a,b,c,x[14], 9,0xc33707d6);
  364.   RND2 (c,d,a,b,x[ 3],14,0xf4d50d87); RND2 (b,c,d,a,x[ 8],20,0x455a14ed);
  365.   RND2 (a,b,c,d,x[13], 5,0xa9e3e905); RND2 (d,a,b,c,x[ 2], 9,0xfcefa3f8);
  366.   RND2 (c,d,a,b,x[ 7],14,0x676f02d9); RND2 (b,c,d,a,x[12],20,0x8d2a4c8a);
  367. /* round 3 */
  368.   RND3 (a,b,c,d,x[ 5], 4,0xfffa3942); RND3 (d,a,b,c,x[ 8],11,0x8771f681);
  369.   RND3 (c,d,a,b,x[11],16,0x6d9d6122); RND3 (b,c,d,a,x[14],23,0xfde5380c);
  370.   RND3 (a,b,c,d,x[ 1], 4,0xa4beea44); RND3 (d,a,b,c,x[ 4],11,0x4bdecfa9);
  371.   RND3 (c,d,a,b,x[ 7],16,0xf6bb4b60); RND3 (b,c,d,a,x[10],23,0xbebfbc70);
  372.   RND3 (a,b,c,d,x[13], 4,0x289b7ec6); RND3 (d,a,b,c,x[ 0],11,0xeaa127fa);
  373.   RND3 (c,d,a,b,x[ 3],16,0xd4ef3085); RND3 (b,c,d,a,x[ 6],23, 0x4881d05);
  374.   RND3 (a,b,c,d,x[ 9], 4,0xd9d4d039); RND3 (d,a,b,c,x[12],11,0xe6db99e5);
  375.   RND3 (c,d,a,b,x[15],16,0x1fa27cf8); RND3 (b,c,d,a,x[ 2],23,0xc4ac5665);
  376. /* round 4 */
  377.   RND4 (a,b,c,d,x[ 0], 6,0xf4292244); RND4 (d,a,b,c,x[ 7],10,0x432aff97);
  378.   RND4 (c,d,a,b,x[14],15,0xab9423a7); RND4 (b,c,d,a,x[ 5],21,0xfc93a039);
  379.   RND4 (a,b,c,d,x[12], 6,0x655b59c3); RND4 (d,a,b,c,x[ 3],10,0x8f0ccc92);
  380.   RND4 (c,d,a,b,x[10],15,0xffeff47d); RND4 (b,c,d,a,x[ 1],21,0x85845dd1);
  381.   RND4 (a,b,c,d,x[ 8], 6,0x6fa87e4f); RND4 (d,a,b,c,x[15],10,0xfe2ce6e0);
  382.   RND4 (c,d,a,b,x[ 6],15,0xa3014314); RND4 (b,c,d,a,x[13],21,0x4e0811a1);
  383.   RND4 (a,b,c,d,x[ 4], 6,0xf7537e82); RND4 (d,a,b,c,x[11],10,0xbd3af235);
  384.   RND4 (c,d,a,b,x[ 2],15,0x2ad7d2bb); RND4 (b,c,d,a,x[ 9],21,0xeb86d391);
  385. /* update state */
  386.   state[0] += a; state[1] += b; state[2] += c; state[3] += d;
  387.   memset (x,0,sizeof (x)); /* erase sensitive data */
  388. }
  389. /* MD5 encode unsigned long into LSB-first bytes
  390.  * Accepts: destination pointer
  391.  *     source
  392.  *     length of source
  393.  */ 
  394. static void md5_encode (unsigned char *dst,unsigned long *src,int len)
  395. {
  396.   int i;
  397.   for (i = 0; i < len; i++) {
  398.     *dst++ = (unsigned char) (src[i] & 0xff);
  399.     *dst++ = (unsigned char) ((src[i] >> 8) & 0xff);
  400.     *dst++ = (unsigned char) ((src[i] >> 16) & 0xff);
  401.     *dst++ = (unsigned char) ((src[i] >> 24) & 0xff);
  402.   }
  403. }
  404. /* MD5 decode LSB-first bytes into unsigned long
  405.  * Accepts: destination pointer
  406.  *     source
  407.  *     length of destination
  408.  */ 
  409. static void md5_decode (unsigned long *dst,unsigned char *src,int len)
  410. {
  411.   int i, j;
  412.   for (i = 0, j = 0; i < len; i++, j += 4)
  413.     dst[i] = ((unsigned long) src[j]) | (((unsigned long) src[j+1]) << 8) |
  414.       (((unsigned long) src[j+2]) << 16) | (((unsigned long) src[j+3]) << 24);
  415. }