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