home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / N / TCPIP / NETKIT-B.05 / NETKIT-B / NetKit-B-0.05 / libtelnet / krb_des.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-17  |  13.6 KB  |  559 lines

  1. /*-
  2.  * Copyright (c) 1991 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. /*static char sccsid[] = "from: @(#)krb_des.c    5.1 (Berkeley) 2/28/91";*/
  36. static char rcsid[] = "$Id: krb_des.c,v 1.2 1993/08/01 18:32:31 mycroft Exp $";
  37. #endif /* not lint */
  38.  
  39. /*
  40.  * Copyright (C) 1990 by the Massachusetts Institute of Technology
  41.  *
  42.  * Export of this software from the United States of America is assumed
  43.  * to require a specific license from the United States Government.
  44.  * It is the responsibility of any person or organization contemplating
  45.  * export to obtain such a license before exporting.
  46.  *
  47.  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
  48.  * distribute this software and its documentation for any purpose and
  49.  * without fee is hereby granted, provided that the above copyright
  50.  * notice appear in all copies and that both that copyright notice and
  51.  * this permission notice appear in supporting documentation, and that
  52.  * the name of M.I.T. not be used in advertising or publicity pertaining
  53.  * to distribution of the software without specific, written prior
  54.  * permission.  M.I.T. makes no representations about the suitability of
  55.  * this software for any purpose.  It is provided "as is" without express
  56.  * or implied warranty.
  57.  */
  58.  
  59. #if    defined(AUTHENTICATE) && defined(ENCRYPT) && defined(KRBDES_ENCRYPT)
  60. #include <arpa/telnet.h>
  61. #include <stdio.h>
  62. #ifdef    __STDC__
  63. #include <stdlib.h>
  64. #endif
  65.  
  66. #include "encrypt.h"
  67. #include "key-proto.h"
  68. #include "misc-proto.h"
  69.  
  70. extern encrypt_debug_mode;
  71.  
  72. static Block krbdes_key = { 0 };
  73. static Schedule krbdes_sched = { 0 };
  74. static Block input_feed = { 0 };
  75. static Block output_feed = { 0 };
  76. static Block temp_feed = { 0 };
  77.  
  78. static unsigned char str_feed[64] = { IAC, SB, TELOPT_ENCRYPT,
  79.                       ENCRYPT_IS,
  80.                       ENCTYPE_KRBDES, };
  81.  
  82.     void
  83. krbdes_init(server)
  84.     int server;
  85. {
  86.     bzero((void *)krbdes_key, sizeof(Block));
  87.     bzero((void *)krbdes_sched, sizeof(Schedule));
  88.     bzero((void *)input_feed, sizeof(Block));
  89.     bzero((void *)output_feed, sizeof(Block));
  90. }
  91.  
  92. #define    KRBDES_FEED_INIT    1
  93. #define    KRBDES_FEED_VRFY    2
  94. #define    KRBDES_FEED_FAIL    3
  95. #define    KRBDES_FEED_OK        4
  96. #define    KRBDES_FEED_VRFY_FAIL    5
  97.  
  98. /*
  99.  * Returns:
  100.  *    -1: some error.  Negotiation is done, encryption not ready.
  101.  *     0: Successful, initial negotiation all done.
  102.  *     1: successful, negotiation not done yet.
  103.  *     2: Not yet.  Other things (like getting the key from
  104.  *        Kerberos) have to happen before we can continue.
  105.  */
  106.  
  107.  
  108. #define    NOT_YET        2
  109. #define    IN_PROGRESS    1
  110. #define    SUCCESS        0
  111. #define    FAILED        -1
  112.  
  113. int state[2] = { NOT_YET, NOT_YET };
  114. #define    ENCRYPT_STATE 0
  115. #define    DECRYPT_STATE 1
  116.  
  117. /*
  118.  * This is where we keep track of the fact that there has been a
  119.  * call to krbdes_start(), but we haven't gotten a valid key from
  120.  * kerberos, so that when (if) it does come in, we can continue with
  121.  * the initial encryption startup.
  122.  */
  123. static int need_start;
  124.  
  125.     int
  126. krbdes_start(dir, server)
  127.     int dir;
  128.     int server;
  129.     Block b;
  130.     int x;
  131.     unsigned char *p;
  132.  
  133.     switch (dir) {
  134.     case DIR_DECRYPT:
  135.         /*
  136.          * This is simply a request to have the other side
  137.          * start output (our input).  He will negotiate a
  138.          * feed so we need not look for it.
  139.          */
  140.         if (!VALIDKEY(krbdes_key))
  141.             return(state[DECRYPT_STATE]);
  142.         if (state[DECRYPT_STATE] == NOT_YET)
  143.             state[DECRYPT_STATE] = IN_PROGRESS;
  144.         return(state[DECRYPT_STATE]);
  145.  
  146.     case DIR_ENCRYPT:
  147.         if (!VALIDKEY(krbdes_key)) {
  148.             need_start = 1;
  149.             return(state[ENCRYPT_STATE]);
  150.         }
  151.         if (state[ENCRYPT_STATE] == IN_PROGRESS)
  152.             return(IN_PROGRESS);
  153.         if (VALIDKEY(output_feed))
  154.             return(SUCCESS);
  155.         if (encrypt_debug_mode)
  156.             printf("Creating new feed\r\n");
  157.         /*
  158.          * Create a random feed and send it over encrypted.
  159.          * The other side will decrypt it, xor in 'KRBDES'
  160.          * and then recrypt it and send it back.
  161.          */
  162.         des_new_random_key(temp_feed);
  163.         des_ecb_encrypt(temp_feed, b, krbdes_sched, 1);
  164.         str_feed[3] = ENCRYPT_IS;
  165.         p = str_feed + 5;
  166.         *p++ = KRBDES_FEED_INIT;
  167.         for (x = 0; x < sizeof(Block); ++x) {
  168.             if ((*p++ = b[x]) == IAC)
  169.                 *p++ = IAC;
  170.         }
  171.         *p++ = IAC;
  172.         *p++ = SE;
  173.         printsub('>', &str_feed[2], p - &str_feed[2]);
  174.         net_write(str_feed, p - str_feed);
  175.         temp_feed[0] ^= 'K';
  176.         temp_feed[1] ^= 'R';
  177.         temp_feed[2] ^= 'B';
  178.         temp_feed[3] ^= 'D';
  179.         temp_feed[4] ^= 'E';
  180.         temp_feed[5] ^= 'S';
  181.         state[ENCRYPT_STATE] = IN_PROGRESS;
  182.         return(IN_PROGRESS);
  183.     default:
  184.         return(FAILED);
  185.     }
  186. }
  187.  
  188. /*
  189.  * Returns:
  190.  *    -1: some error.  Negotiation is done, encryption not ready.
  191.  *     0: Successful, initial negotiation all done.
  192.  *     1: successful, negotiation not done yet.
  193.  */
  194.  
  195.     int
  196. krbdes_is(data, cnt)
  197.     unsigned char *data;
  198.     int cnt;
  199. {
  200.     int x;
  201.     unsigned char *p;
  202.     unsigned char *why = 0;
  203.     Block b;
  204.  
  205.     if (cnt-- < 1) {
  206.         why = (unsigned char *)"Bad IS suboption";
  207.         goto failure;
  208.     }
  209.  
  210.     switch (*data++) {
  211.     case KRBDES_FEED_INIT:
  212.         if (cnt != sizeof(Block)) {
  213.             if (encrypt_debug_mode)
  214.                 printf("Use Feed failed on size\r\n");
  215.             why = (unsigned char *)"Bad block size";
  216.             goto failure;
  217.         }
  218.         if (!VALIDKEY(krbdes_key)) {
  219.             if (encrypt_debug_mode)
  220.                 printf("Use Feed failed on key\r\n");
  221.             why = (unsigned char *)"Invalid key";
  222.             goto failure;
  223.         }
  224.         if (encrypt_debug_mode)
  225.             printf("Have a Use Feed\r\n");
  226.  
  227.         bcopy((void *)data, (void *)b, sizeof(Block));
  228.         des_ecb_encrypt(b, input_feed, krbdes_sched, 0);
  229.  
  230.         input_feed[0] ^= 'K';
  231.         input_feed[1] ^= 'R';
  232.         input_feed[2] ^= 'B';
  233.         input_feed[3] ^= 'D';
  234.         input_feed[4] ^= 'E';
  235.         input_feed[5] ^= 'S';
  236.  
  237.         des_ecb_encrypt(input_feed, b, krbdes_sched, 1);
  238.         str_feed[3] = ENCRYPT_REPLY;
  239.         p = str_feed + 5;
  240.         *p++ = KRBDES_FEED_VRFY;
  241.         for (x = 0; x < sizeof(Block); ++x) {
  242.             if ((*p++ = b[x]) == IAC)
  243.                 *p++ = IAC;
  244.         }
  245.         *p++ = IAC;
  246.         *p++ = SE;
  247.         printsub('>', &str_feed[2], p - &str_feed[2]);
  248.         net_write(str_feed, p - str_feed);
  249.         if (encrypt_debug_mode)
  250.             printf("Initializing Decrypt stream\r\n");
  251.         key_stream_init(krbdes_key, input_feed, DIR_DECRYPT);
  252.         state[DECRYPT_STATE] = IN_PROGRESS;
  253.         return(IN_PROGRESS);
  254.  
  255.     case KRBDES_FEED_OK:
  256.         state[DECRYPT_STATE] = SUCCESS;
  257.         return(SUCCESS);
  258.  
  259.     case KRBDES_FEED_FAIL:
  260.         state[DECRYPT_STATE] = FAILED;
  261.         return(FAILED);
  262.  
  263.     default:
  264.         if (encrypt_debug_mode) {
  265.             printf("Unknown option type: %d\r\n", data[-1]);
  266.             printd(data, cnt);
  267.             printf("\r\n");
  268.         }
  269.         why = (unsigned char *)"Unknown sub-suboption";
  270.     failure:
  271.         /*
  272.          * We failed.  Send an empty KRBDES_FEED_VRFY option
  273.          * to the other side so it will know that things
  274.          * failed.
  275.          */
  276.         str_feed[3] = ENCRYPT_REPLY;
  277.         p = str_feed + 5;
  278.         *p++ = KRBDES_FEED_VRFY_FAIL;
  279.         if (why) {
  280.             while (*why) {
  281.                 if ((*p++ = *why++) == IAC)
  282.                     *p++ = IAC;
  283.             }
  284.         }
  285.         *p++ = IAC;
  286.         *p++ = SE;
  287.         printsub('>', &str_feed[2], p - &str_feed[2]);
  288.         net_write(str_feed, p - str_feed);
  289.         state[DECRYPT_STATE] = FAILED;
  290.         return(FAILED);
  291.     }
  292. }
  293.  
  294. /*
  295.  * Returns:
  296.  *    -1: some error.  Negotiation is done, encryption not ready.
  297.  *     0: Successful, initial negotiation all done.
  298.  *     1: successful, negotiation not done yet.
  299.  */
  300.  
  301.     int
  302. krbdes_reply(data, cnt)
  303.     unsigned char *data;
  304.     int cnt;
  305. {
  306.     int x;
  307.     unsigned char *p;
  308.     unsigned char *why = 0;
  309.     Block b;
  310.  
  311.     if (cnt-- < 1) {
  312.         why = (unsigned char *)"Bad REPLY suboption";
  313.         goto failure;
  314.     }
  315.  
  316.     switch (*data++) {
  317.     case KRBDES_FEED_VRFY:
  318.         if (cnt != sizeof(Block)) {
  319.             if (encrypt_debug_mode)
  320.                 printf("Have Feed failed on size\r\n");
  321.             why = (unsigned char *)"Bad block size";
  322.             goto failure;
  323.         }
  324.         if (!VALIDKEY(krbdes_key)) {
  325.             if (encrypt_debug_mode)
  326.                 printf("Have Feed failed on key\r\n");
  327.             why = (unsigned char *)"Invalid key";
  328.             goto failure;
  329.         }
  330.         if (encrypt_debug_mode)
  331.             printf("Have a Test Feed\r\n");
  332.  
  333.         bcopy((void *)data, (void *)b, sizeof(Block));
  334.         des_ecb_encrypt(b, output_feed, krbdes_sched, 0);
  335.         if (!SAMEKEY(output_feed, temp_feed)) {
  336.             if (encrypt_debug_mode)
  337.                 printf("Have Feed failed on challange\r\n");
  338.             bzero((void *)output_feed, sizeof(Block));
  339.             why = (unsigned char*)"Challange decrypt failed";
  340.             goto failure;
  341.         }
  342.         if (encrypt_debug_mode)
  343.             printf("Initializing Encrypt stream\r\n");
  344.         key_stream_init(krbdes_key, output_feed, DIR_ENCRYPT);
  345.  
  346.         str_feed[3] = ENCRYPT_IS;
  347.         p = str_feed + 5;
  348.         *p++ = KRBDES_FEED_OK;
  349.         *p++ = IAC;
  350.         *p++ = SE;
  351.         printsub('>', &str_feed[2], p - &str_feed[2]);
  352.         net_write(str_feed, p - str_feed);
  353.         state[ENCRYPT_STATE] = SUCCESS;
  354.         return(SUCCESS);
  355.  
  356.     default:
  357.         if (encrypt_debug_mode) {
  358.             printf("Unknown option type: %d\r\n", data[-1]);
  359.             printd(data, cnt);
  360.             printf("\r\n");
  361.         }
  362.         why = (unsigned char *)"Unknown sub-suboption";
  363.     failure:
  364.         str_feed[3] = ENCRYPT_IS;
  365.         p = str_feed + 5;
  366.         *p++ = KRBDES_FEED_FAIL;
  367.         if (why) {
  368.             while (*why) {
  369.                 if ((*p++ = *why++) == IAC)
  370.                     *p++ = IAC;
  371.             }
  372.         }
  373.         *p++ = IAC;
  374.         *p++ = SE;
  375.         printsub('>', &str_feed[2], p - &str_feed[2]);
  376.         net_write(str_feed, p - str_feed);
  377.         state[ENCRYPT_STATE] = FAILED;
  378.         return(FAILED);
  379.     }
  380. }
  381.  
  382.     void
  383. krbdes_encrypt(s, c)
  384.     unsigned char *s;
  385.     int c;
  386. {
  387.     while (c-- > 0) {
  388.         *s = key_stream(DIR_ENCRYPT, *s);
  389.         ++s;
  390.     }
  391. }
  392.  
  393.     int
  394. krbdes_decrypt(c)
  395.     int c;
  396. {
  397.     return(key_stream(DIR_DECRYPT, c));
  398. #ifdef    ndef
  399.  
  400.     if (c == -1) {
  401.         ++use;
  402.         return(0);
  403.     }
  404.     if (use) {
  405.         use = 0;
  406.     } else {
  407.         last = key_stream(DIR_DECRYPT, c);
  408.     }
  409.  
  410.     return(last ^ c);
  411. #endif
  412. }
  413.  
  414.     void
  415. krbdes_session(key, server)
  416.     Session_Key *key;
  417.     int server;
  418. {
  419.     static once = 1;
  420.  
  421.     if (!key || key->type != SK_DES) {
  422.         if (encrypt_debug_mode)
  423.             printf("Can't set krbdes's session key (%d != %d)\r\n",
  424.                 key ? key->type : -1, SK_DES);
  425.         return;
  426.     }
  427.     bcopy((void *)key->data, (void *)krbdes_key, sizeof(Block));
  428.     if (once) {
  429.         des_set_random_generator_seed(krbdes_key);
  430.         once = 0;
  431.     }
  432.     des_key_sched(krbdes_key, krbdes_sched);
  433.     /*
  434.      * Now look to see if krbdes_start() was was waiting for
  435.      * the key to show up.  If so, go ahead an call it now
  436.      * that we have the key.
  437.      */
  438.     if (need_start) {
  439.         krbdes_start(DIR_ENCRYPT, server);
  440.         need_start = 0;
  441.     }
  442. }
  443.  
  444.     void
  445. krbdes_printsub(data, cnt, buf, buflen)
  446.     unsigned char *data, *buf;
  447.     int cnt, buflen;
  448. {
  449.     char lbuf[32];
  450.     register int i;
  451.     char *cp;
  452.  
  453.     buf[buflen-1] = '\0';        /* make sure it's NULL terminated */
  454.     buflen -= 1;
  455.  
  456.     switch(data[2]) {
  457.     case KRBDES_FEED_OK:
  458.         cp = "FEED_OK";
  459.         goto common1;
  460.     case KRBDES_FEED_FAIL:
  461.         cp = "FEED_FAIL";
  462.     common1:
  463.         for (; (buflen > 0) && (*buf = *cp++); buf++)
  464.             buflen--;
  465.         if (cnt > 3) {
  466.             if (buflen <= 0)
  467.                 break;
  468.             *buf++ = ' ';
  469.             if (--buflen <= 0)
  470.                 break;
  471.             *buf++ = '"';
  472.             for (i = 3; i < cnt && buflen > 0; i++, buflen--)
  473.                 *buf++ = data[i];
  474.             if (buflen <= 0)
  475.                 break;
  476.             *buf++ = '"';
  477.             --buflen;
  478.         }
  479.         if (buflen <= 0)
  480.             break;
  481.         *buf++ = '\0';
  482.         break;
  483.         
  484.     case KRBDES_FEED_INIT:
  485.         cp = "FEED_INIT ";
  486.         goto common2;
  487.  
  488.     case KRBDES_FEED_VRFY:
  489.         cp = "FEED_VRFY ";
  490.         goto common2;
  491.  
  492.     default:
  493.         sprintf(lbuf, " %d (unknown)", data[2]);
  494.         cp = lbuf;
  495.     common2:
  496.         for (; (buflen > 0) && (*buf = *cp++); buf++)
  497.             buflen--;
  498.         for (i = 3; i < cnt; i++) {
  499.             sprintf(lbuf, " %d", data[i]);
  500.             for (cp = lbuf; (buflen > 0) && (*buf = *cp++); buf++)
  501.                 buflen--;
  502.         }
  503.         break;
  504.     }
  505. }
  506.  
  507. static    Block stream_output[2];
  508. static    Block stream_feed[2];
  509. static    Schedule stream_sched[2];
  510. static    int stream_index[2];
  511.  
  512.     void
  513. key_stream_init(key, seed, dir)
  514.     Block key;
  515.     Block seed;
  516.     int dir;
  517. {
  518.     des_key_sched(key, stream_sched[--dir]);
  519.     bcopy((void *)seed, (void *)stream_output[dir], sizeof(Block));
  520.     stream_index[dir] = sizeof(Block);
  521. }
  522.  
  523.     unsigned char
  524. key_stream(dir, data)
  525.     int dir;
  526.     int data;    /* data de/encrypting */
  527. {
  528.     int index;
  529.  
  530.     if (data == -1) {
  531.         /* Backpeddle */
  532.         if (stream_index[--dir])
  533.             --stream_index[dir];
  534.         return(0);
  535.     }
  536.     if ((index = stream_index[--dir]++) == sizeof(Block)) {
  537.         Block b;
  538.         des_ecb_encrypt(stream_output[dir],
  539.                 b,
  540.                 stream_sched[dir], 1);
  541.         bcopy((void *)b, (void *)stream_feed[dir], sizeof(Block));
  542.         stream_index[dir] = 1;    /* Next time will be 1 */
  543.         index = 0;        /* But now use 0 */
  544.     }
  545.  
  546.     /*
  547.      * On encryption, we store (feed ^ data) which is cypher
  548.      * On decryption we store (data) which is cypher
  549.      */
  550.     if (dir == DIR_DECRYPT)
  551.         return(stream_output[dir][index] =
  552.                 (stream_feed[dir][index] ^ data));
  553.     else
  554.         return((stream_output[dir][index] = data) ^
  555.                   stream_feed[dir][index]);
  556. }
  557. #endif
  558.