import cyrus-sasl-2.1.23
[cyrus-sasl.git] / mac / libdes / src / fcrypt.c
1 /* crypto/des/fcrypt.c */\r/* Copyright (C) 1995-1997 Eric Young (eay@mincom.oz.au)\r * All rights reserved.\r *\r * This package is an SSL implementation written\r * by Eric Young (eay@mincom.oz.au).\r * The implementation was written so as to conform with Netscapes SSL.\r * \r * This library is free for commercial and non-commercial use as long as\r * the following conditions are aheared to.  The following conditions\r * apply to all code found in this distribution, be it the RC4, RSA,\r * lhash, DES, etc., code; not just the SSL code.  The SSL documentation\r * included with this distribution is covered by the same copyright terms\r * except that the holder is Tim Hudson (tjh@mincom.oz.au).\r * \r * Copyright remains Eric Young's, and as such any Copyright notices in\r * the code are not to be removed.\r * If this package is used in a product, Eric Young should be given attribution\r * as the author of the parts of the library used.\r * This can be in the form of a textual message at program startup or\r * in documentation (online or textual) provided with the package.\r * \r * Redistribution and use in source and binary forms, with or without\r * modification, are permitted provided that the following conditions\r * are met:\r * 1. Redistributions of source code must retain the copyright\r *    notice, this list of conditions and the following disclaimer.\r * 2. Redistributions in binary form must reproduce the above copyright\r *    notice, this list of conditions and the following disclaimer in the\r *    documentation and/or other materials provided with the distribution.\r * 3. All advertising materials mentioning features or use of this software\r *    must display the following acknowledgement:\r *    "This product includes cryptographic software written by\r *     Eric Young (eay@mincom.oz.au)"\r *    The word 'cryptographic' can be left out if the rouines from the library\r *    being used are not cryptographic related :-).\r * 4. If you include any Windows specific code (or a derivative thereof) from \r *    the apps directory (application code) you must include an acknowledgement:\r *    "This product includes software written by Tim Hudson (tjh@mincom.oz.au)"\r * \r * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND\r * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE\r * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r * SUCH DAMAGE.\r * \r * The licence and distribution terms for any publically available version or\r * derivative of this code cannot be changed.  i.e. this code cannot simply be\r * copied and put under another distribution licence\r * [including the GNU Public Licence.]\r */\r\r#include <stdio.h>\r\r/* Eric Young.\r * This version of crypt has been developed from my MIT compatable\r * DES library.\r * The library is available at pub/Crypto/DES at ftp.psy.uq.oz.au\r * eay@mincom.oz.au or eay@psych.psy.uq.oz.au\r */\r\r/* Modification by Jens Kupferschmidt (Cu)\r * I have included directive PARA for shared memory computers.\r * I have included a directive LONGCRYPT to using this routine to cipher\r * passwords with more then 8 bytes like HP-UX 10.x it used. The MAXPLEN\r * definition is the maximum of lenght of password and can changed. I have\r * defined 24.\r */\r\r#define FCRYPT_MOD(R,u,t,E0,E1,tmp) \\r     u=R>>16; \\r     t=R^u; \\r       u=t&E0; t=t&E1; \\r      tmp=(u<<16); u^=R^s[S  ]; u^=tmp; \\r    tmp=(t<<16); t^=R^s[S+1]; t^=tmp\r\r#define DES_FCRYPT\r#include "des_locl.h"\r#undef DES_FCRYPT\r\r#undef PERM_OP\r#define PERM_OP(a,b,t,n,m) ((t)=((((a)>>(n))^(b))&(m)),\\r  (b)^=(t),\\r     (a)^=((t)<<(n)))\r\r#undef HPERM_OP\r#define HPERM_OP(a,t,n,m) ((t)=((((a)<<(16-(n)))^(a))&(m)),\\r (a)=(a)^(t)^(t>>(16-(n))))\\r\r#ifdef PARA\r#define STATIC\r#else\r#define STATIC    static\r#endif\r\r/* It is really only FreeBSD that still suffers from MD5 based crypts */\r#ifdef __FreeBSD__\r#define MD5_CRYPT_SUPPORT 1\r#endif\r#if     MD5_CRYPT_SUPPORT\r/*\r * ----------------------------------------------------------------------------\r * "THE BEER-WARE LICENSE" (Revision 42):\r * <phk@login.dknet.dk> wrote this file.  As long as you retain this notice you\r * can do whatever you want with this stuff. If we meet some day, and you think\r * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp\r * ----------------------------------------------------------------------------\r */\r\r#ifdef HAVE_CONFIG_H\r#include <config.h>\r#endif\r#include <md5.h>\r\rstatic unsigned char itoa64[] =             /* 0 ... 63 => ascii - 64 */\r   "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";\r\rstatic void\rto64(s, v, n)\r char *s;\r       unsigned long v;\r       int n;\r{\r       while (--n >= 0) {\r             *s++ = itoa64[v&0x3f];\r         v >>= 6;\r       }\r}\r\r/*\r * UNIX password\r *\r * Use MD5 for what it is best at...\r */\r\rstatic\rchar *\rcrypt_md5(pw, salt)\r        register const char *pw;\r       register const char *salt;\r{\r   static char     *magic = "$1$"; /*\r                                              * This string is magic for\r                                             * this algorithm.  Having\r                                              * it this way, we can get\r                                              * get better later on\r                                          */\r    static char     passwd[120], *p;\r       static const char *sp,*ep;\r     unsigned char   final[16];\r     int sl,pl,i,j;\r MD5_CTX ctx,ctx1;\r      unsigned long l;\r\r      /* Refine the Salt first */\r    sp = salt;\r\r    /* If it starts with the magic string, then skip that */\r       if(!strncmp(sp,magic,strlen(magic)))\r           sp += strlen(magic);\r\r  /* It stops at the first '$', max 8 chars */\r   for(ep=sp;*ep && *ep != '$' && ep < (sp+8);ep++)\r               continue;\r\r     /* get the length of the true salt */\r  sl = ep - sp;\r\r MD5Init(&ctx);\r\r        /* The password first, since that is what is most unknown */\r   MD5Update(&ctx,pw,strlen(pw));\r\r        /* Then our magic string */\r    MD5Update(&ctx,magic,strlen(magic));\r\r  /* Then the raw salt */\r        MD5Update(&ctx,sp,sl);\r\r        /* Then just as many characters of the MD5(pw,salt,pw) */\r      MD5Init(&ctx1);\r        MD5Update(&ctx1,pw,strlen(pw));\r        MD5Update(&ctx1,sp,sl);\r        MD5Update(&ctx1,pw,strlen(pw));\r        MD5Final(final,&ctx1);\r for(pl = strlen(pw); pl > 0; pl -= 16)\r         MD5Update(&ctx,final,pl>16 ? 16 : pl);\r\r        /* Don't leave anything around in vm they could use. */\r        memset(final,0,sizeof final);\r\r /* Then something really weird... */\r   for (j=0,i = strlen(pw); i ; i >>= 1)\r          if(i&1)\r                    MD5Update(&ctx, final+j, 1);\r               else\r               MD5Update(&ctx, pw+j, 1);\r\r /* Now make the output string */\r       snprintf (passwd, sizeof(passwd),\r                "%s%.*s$", magic, sl, sp);\r\r  MD5Final(final,&ctx);\r\r /*\r      * and now, just to make sure things don't run too fast\r         * On a 60 Mhz Pentium this takes 34 msec, so you would\r         * need 30 seconds to build a 1000 entry dictionary...\r  */\r    for(i=0;i<1000;i++) {\r          MD5Init(&ctx1);\r                if(i & 1)\r                      MD5Update(&ctx1,pw,strlen(pw));\r                else\r                   MD5Update(&ctx1,final,16);\r\r            if(i % 3)\r                      MD5Update(&ctx1,sp,sl);\r\r               if(i % 7)\r                      MD5Update(&ctx1,pw,strlen(pw));\r\r               if(i & 1)\r                      MD5Update(&ctx1,final,16);\r             else\r                   MD5Update(&ctx1,pw,strlen(pw));\r                MD5Final(final,&ctx1);\r }\r\r     p = passwd + strlen(passwd);\r\r  l = (final[ 0]<<16) | (final[ 6]<<8) | final[12]; to64(p,l,4); p += 4;\r l = (final[ 1]<<16) | (final[ 7]<<8) | final[13]; to64(p,l,4); p += 4;\r l = (final[ 2]<<16) | (final[ 8]<<8) | final[14]; to64(p,l,4); p += 4;\r l = (final[ 3]<<16) | (final[ 9]<<8) | final[15]; to64(p,l,4); p += 4;\r l = (final[ 4]<<16) | (final[10]<<8) | final[ 5]; to64(p,l,4); p += 4;\r l =                    final[11]                ; to64(p,l,2); p += 2;\r *p = '\0';\r\r    /* Don't leave anything around in vm they could use. */\r        memset(final,0,sizeof final);\r\r return passwd;\r}\r#endif /* MD5_CRYPT_SUPPORT */\r\r#ifndef NOPROTO\r\rSTATIC int fcrypt_body(DES_LONG *out0, DES_LONG *out1,\r       des_key_schedule ks, DES_LONG Eswap0, DES_LONG Eswap1);\r\r#else\r\rSTATIC int fcrypt_body();\r\r#endif\r\r/* Added more values to handle illegal salt values the way normal\r * crypt() implementations do.  The patch was sent by \r * Bjorn Gronvall <bg@sics.se>\r */\rstatic unsigned const char con_salt[128]={\r0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,\r0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,0xE0,0xE1,\r0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,\r0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,\r0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,\r0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,0x00,0x01,\r0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,\r0x0A,0x0B,0x05,0x06,0x07,0x08,0x09,0x0A,\r0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12,\r0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A,\r0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,\r0x23,0x24,0x25,0x20,0x21,0x22,0x23,0x24,\r0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,\r0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,\r0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,\r0x3D,0x3E,0x3F,0x40,0x41,0x42,0x43,0x44,\r};\r\rstatic unsigned const char cov_2char[64]={\r0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35,\r0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44,\r0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,\r0x4D,0x4E,0x4F,0x50,0x51,0x52,0x53,0x54,\r0x55,0x56,0x57,0x58,0x59,0x5A,0x61,0x62,\r0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,\r0x6B,0x6C,0x6D,0x6E,0x6F,0x70,0x71,0x72,\r0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A\r};\r\r#ifndef NOPROTO\r#ifdef PERL5\rchar *des_crypt(const char *buf,const char *salt);\r#else\rchar *crypt(const char *buf,const char *salt);\r#endif\r#else\r#ifdef PERL5\rchar *des_crypt();\r#else\rchar *crypt();\r#endif\r#endif\r\r#ifdef PERL5\rchar *des_crypt(buf,salt)\r#else\rchar *crypt(buf,salt)\r#endif\rconst char *buf;\rconst char *salt;\r {\r      static char buff[14];\r\r#if     MD5_CRYPT_SUPPORT\r       if (!strncmp(salt, "$1$", 3))\r          return crypt_md5(buf, salt);\r#endif\r\r   return(des_fcrypt(buf,salt,buff));\r     }\r\r\rchar *des_fcrypt(buf,salt,ret)\rconst char *buf;\rconst char *salt;\rchar *ret;\r       {\r      unsigned int i,j,x,y;\r  DES_LONG Eswap0,Eswap1;\r        DES_LONG out[2],ll;\r    des_cblock key;\r        des_key_schedule ks;\r   unsigned char bb[9];\r   unsigned char *b=bb;\r   unsigned char c,u;\r\r    /* eay 25/08/92\r         * If you call crypt("pwd","*") as often happens when you\r       * have * as the pwd field in /etc/passwd, the function\r         * returns *\0XXXXXXXXX\r         * The \0 makes the string look like * so the pwd "*" would\r     * crypt to "*".  This was found when replacing the crypt in\r    * our shared libraries.  People found that the disbled\r         * accounts effectivly had no passwd :-(. */\r   x=ret[0]=((salt[0] == '\0')?'A':salt[0]);\r      Eswap0=con_salt[x]<<2;\r x=ret[1]=((salt[1] == '\0')?'A':salt[1]);\r      Eswap1=con_salt[x]<<6;\r\r/* EAY\rr=strlen(buf);\rr=(r+7)/8;\r*/\r    for (i=0; i<8; i++)\r            {\r              c= *(buf++);\r           if (!c) break;\r         key[i]=(c<<1);\r         }\r      for (; i<8; i++)\r               key[i]=0;\r\r     des_set_key((des_cblock *)(key),ks);\r   fcrypt_body(&(out[0]),&(out[1]),ks,Eswap0,Eswap1);\r\r    ll=out[0]; l2c(ll,b);\r  ll=out[1]; l2c(ll,b);\r  y=0;\r   u=0x80;\r        bb[8]=0;\r       for (i=2; i<13; i++)\r           {\r              c=0;\r           for (j=0; j<6; j++)\r                    {\r                      c<<=1;\r                 if (bb[y] & u) c|=1;\r                   u>>=1;\r                 if (!u)\r                                {\r                              y++;\r                           u=0x80;\r                                }\r                      }\r              ret[i]=cov_2char[c];\r           }\r      ret[13]='\0';\r  return(ret);\r   }\r\rSTATIC int fcrypt_body(out0, out1, ks, Eswap0, Eswap1)\rDES_LONG *out0;\rDES_LONG *out1;\rdes_key_schedule ks;\rDES_LONG Eswap0;\rDES_LONG Eswap1;\r       {\r      register DES_LONG l,r,t,u;\r#ifdef DES_PTR\r      register unsigned char *des_SP=(unsigned char *)des_SPtrans;\r#endif\r    register DES_LONG *s;\r  register int j;\r        register DES_LONG E0,E1;\r\r      l=0;\r   r=0;\r\r  s=(DES_LONG *)ks;\r      E0=Eswap0;\r     E1=Eswap1;\r\r    for (j=0; j<25; j++)\r           {\r#ifdef DES_UNROLL\r            register int i;\r\r               for (i=0; i<32; i+=8)\r                  {\r                      D_ENCRYPT(l,r,i+0); /*  1 */\r                   D_ENCRYPT(r,l,i+2); /*  2 */\r                   D_ENCRYPT(l,r,i+4); /*  3 */\r                   D_ENCRYPT(r,l,i+6); /*  4 */\r                   }\r#else\r                D_ENCRYPT(l,r, 0); /*  1 */\r            D_ENCRYPT(r,l, 2); /*  2 */\r            D_ENCRYPT(l,r, 4); /*  3 */\r            D_ENCRYPT(r,l, 6); /*  4 */\r            D_ENCRYPT(l,r, 8); /*  5 */\r            D_ENCRYPT(r,l,10); /*  6 */\r            D_ENCRYPT(l,r,12); /*  7 */\r            D_ENCRYPT(r,l,14); /*  8 */\r            D_ENCRYPT(l,r,16); /*  9 */\r            D_ENCRYPT(r,l,18); /*  10 */\r           D_ENCRYPT(l,r,20); /*  11 */\r           D_ENCRYPT(r,l,22); /*  12 */\r           D_ENCRYPT(l,r,24); /*  13 */\r           D_ENCRYPT(r,l,26); /*  14 */\r           D_ENCRYPT(l,r,28); /*  15 */\r           D_ENCRYPT(r,l,30); /*  16 */\r#endif\r            t=l;\r           l=r;\r           r=t;\r           }\r      l=ROTATE(l,3)&0xffffffffL;\r     r=ROTATE(r,3)&0xffffffffL;\r\r    PERM_OP(l,r,t, 1,0x55555555L);\r PERM_OP(r,l,t, 8,0x00ff00ffL);\r PERM_OP(l,r,t, 2,0x33333333L);\r PERM_OP(r,l,t,16,0x0000ffffL);\r PERM_OP(l,r,t, 4,0x0f0f0f0fL);\r\r        *out0=r;\r       *out1=l;\r       return(0);\r     }\r\r