* Copyright (c) 1991 The Regents of the University of California.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
static char sccsid
[] = "@(#)krb_des.c 5.1 (Berkeley) 2/28/91";
* Copyright (C) 1990 by the Massachusetts Institute of Technology
* Export of this software from the United States of America is assumed
* to require a specific license from the United States Government.
* It is the responsibility of any person or organization contemplating
* export to obtain such a license before exporting.
* WITHIN THAT CONSTRAINT, 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 appear in all copies and that both that copyright notice and
* this permission notice appear in supporting documentation, and that
* the name of M.I.T. not be used in advertising or publicity pertaining
* to distribution of the software without specific, written prior
* permission. M.I.T. makes no representations about the suitability of
* this software for any purpose. It is provided "as is" without express
#if defined(AUTHENTICATE) && defined(ENCRYPT) && defined(KRBDES_ENCRYPT)
extern encrypt_debug_mode
;
static Block krbdes_key
= { 0 };
static Schedule krbdes_sched
= { 0 };
static Block input_feed
= { 0 };
static Block output_feed
= { 0 };
static Block temp_feed
= { 0 };
static unsigned char str_feed
[64] = { IAC
, SB
, TELOPT_ENCRYPT
,
bzero((void *)krbdes_key
, sizeof(Block
));
bzero((void *)krbdes_sched
, sizeof(Schedule
));
bzero((void *)input_feed
, sizeof(Block
));
bzero((void *)output_feed
, sizeof(Block
));
#define KRBDES_FEED_INIT 1
#define KRBDES_FEED_VRFY 2
#define KRBDES_FEED_FAIL 3
#define KRBDES_FEED_VRFY_FAIL 5
* -1: some error. Negotiation is done, encryption not ready.
* 0: Successful, initial negotiation all done.
* 1: successful, negotiation not done yet.
* 2: Not yet. Other things (like getting the key from
* Kerberos) have to happen before we can continue.
int state
[2] = { NOT_YET
, NOT_YET
};
* This is where we keep track of the fact that there has been a
* call to krbdes_start(), but we haven't gotten a valid key from
* kerberos, so that when (if) it does come in, we can continue with
* the initial encryption startup.
krbdes_start(dir
, server
)
* This is simply a request to have the other side
* start output (our input). He will negotiate a
* feed so we need not look for it.
if (!VALIDKEY(krbdes_key
))
return(state
[DECRYPT_STATE
]);
if (state
[DECRYPT_STATE
] == NOT_YET
)
state
[DECRYPT_STATE
] = IN_PROGRESS
;
return(state
[DECRYPT_STATE
]);
if (!VALIDKEY(krbdes_key
)) {
return(state
[ENCRYPT_STATE
]);
if (state
[ENCRYPT_STATE
] == IN_PROGRESS
)
if (VALIDKEY(output_feed
))
printf("Creating new feed\r\n");
* Create a random feed and send it over encrypted.
* The other side will decrypt it, xor in 'KRBDES'
* and then recrypt it and send it back.
des_new_random_key(temp_feed
);
des_ecb_encrypt(temp_feed
, b
, krbdes_sched
, 1);
str_feed
[3] = ENCRYPT_IS
;
for (x
= 0; x
< sizeof(Block
); ++x
) {
if ((*p
++ = b
[x
]) == IAC
)
printsub('>', &str_feed
[2], p
- &str_feed
[2]);
net_write(str_feed
, p
- str_feed
);
state
[ENCRYPT_STATE
] = IN_PROGRESS
;
* -1: some error. Negotiation is done, encryption not ready.
* 0: Successful, initial negotiation all done.
* 1: successful, negotiation not done yet.
why
= (unsigned char *)"Bad IS suboption";
if (cnt
!= sizeof(Block
)) {
printf("Use Feed failed on size\r\n");
why
= (unsigned char *)"Bad block size";
if (!VALIDKEY(krbdes_key
)) {
printf("Use Feed failed on key\r\n");
why
= (unsigned char *)"Invalid key";
printf("Have a Use Feed\r\n");
bcopy((void *)data
, (void *)b
, sizeof(Block
));
des_ecb_encrypt(b
, input_feed
, krbdes_sched
, 0);
des_ecb_encrypt(input_feed
, b
, krbdes_sched
, 1);
str_feed
[3] = ENCRYPT_REPLY
;
for (x
= 0; x
< sizeof(Block
); ++x
) {
if ((*p
++ = b
[x
]) == IAC
)
printsub('>', &str_feed
[2], p
- &str_feed
[2]);
net_write(str_feed
, p
- str_feed
);
printf("Initializing Decrypt stream\r\n");
key_stream_init(krbdes_key
, input_feed
, DIR_DECRYPT
);
state
[DECRYPT_STATE
] = IN_PROGRESS
;
state
[DECRYPT_STATE
] = SUCCESS
;
state
[DECRYPT_STATE
] = FAILED
;
if (encrypt_debug_mode
) {
printf("Unknown option type: %d\r\n", data
[-1]);
why
= (unsigned char *)"Unknown sub-suboption";
* We failed. Send an empty KRBDES_FEED_VRFY option
* to the other side so it will know that things
str_feed
[3] = ENCRYPT_REPLY
;
*p
++ = KRBDES_FEED_VRFY_FAIL
;
if ((*p
++ = *why
++) == IAC
)
printsub('>', &str_feed
[2], p
- &str_feed
[2]);
net_write(str_feed
, p
- str_feed
);
state
[DECRYPT_STATE
] = FAILED
;
* -1: some error. Negotiation is done, encryption not ready.
* 0: Successful, initial negotiation all done.
* 1: successful, negotiation not done yet.
why
= (unsigned char *)"Bad REPLY suboption";
if (cnt
!= sizeof(Block
)) {
printf("Have Feed failed on size\r\n");
why
= (unsigned char *)"Bad block size";
if (!VALIDKEY(krbdes_key
)) {
printf("Have Feed failed on key\r\n");
why
= (unsigned char *)"Invalid key";
printf("Have a Test Feed\r\n");
bcopy((void *)data
, (void *)b
, sizeof(Block
));
des_ecb_encrypt(b
, output_feed
, krbdes_sched
, 0);
if (!SAMEKEY(output_feed
, temp_feed
)) {
printf("Have Feed failed on challange\r\n");
bzero((void *)output_feed
, sizeof(Block
));
why
= (unsigned char*)"Challange decrypt failed";
printf("Initializing Encrypt stream\r\n");
key_stream_init(krbdes_key
, output_feed
, DIR_ENCRYPT
);
str_feed
[3] = ENCRYPT_IS
;
printsub('>', &str_feed
[2], p
- &str_feed
[2]);
net_write(str_feed
, p
- str_feed
);
state
[ENCRYPT_STATE
] = SUCCESS
;
if (encrypt_debug_mode
) {
printf("Unknown option type: %d\r\n", data
[-1]);
why
= (unsigned char *)"Unknown sub-suboption";
str_feed
[3] = ENCRYPT_IS
;
if ((*p
++ = *why
++) == IAC
)
printsub('>', &str_feed
[2], p
- &str_feed
[2]);
net_write(str_feed
, p
- str_feed
);
state
[ENCRYPT_STATE
] = FAILED
;
*s
= key_stream(DIR_ENCRYPT
, *s
);
return(key_stream(DIR_DECRYPT
, c
));
last
= key_stream(DIR_DECRYPT
, c
);
krbdes_session(key
, server
)
if (!key
|| key
->type
!= SK_DES
) {
printf("Can't set krbdes's session key (%d != %d)\r\n",
key
? key
->type
: -1, SK_DES
);
bcopy((void *)key
->data
, (void *)krbdes_key
, sizeof(Block
));
des_set_random_generator_seed(krbdes_key
);
des_key_sched(krbdes_key
, krbdes_sched
);
* Now look to see if krbdes_start() was was waiting for
* the key to show up. If so, go ahead an call it now
krbdes_start(DIR_ENCRYPT
, server
);
krbdes_printsub(data
, cnt
, buf
, buflen
)
unsigned char *data
, *buf
;
buf
[buflen
-1] = '\0'; /* make sure it's NULL terminated */
for (; (buflen
> 0) && (*buf
= *cp
++); buf
++)
for (i
= 3; i
< cnt
&& buflen
> 0; i
++, buflen
--)
sprintf(lbuf
, " %d (unknown)", data
[2]);
for (; (buflen
> 0) && (*buf
= *cp
++); buf
++)
for (i
= 3; i
< cnt
; i
++) {
sprintf(lbuf
, " %d", data
[i
]);
for (cp
= lbuf
; (buflen
> 0) && (*buf
= *cp
++); buf
++)
static Block stream_output
[2];
static Block stream_feed
[2];
static Schedule stream_sched
[2];
static int stream_index
[2];
key_stream_init(key
, seed
, dir
)
des_key_sched(key
, stream_sched
[--dir
]);
bcopy((void *)seed
, (void *)stream_output
[dir
], sizeof(Block
));
stream_index
[dir
] = sizeof(Block
);
int data
; /* data de/encrypting */
if ((index
= stream_index
[--dir
]++) == sizeof(Block
)) {
des_ecb_encrypt(stream_output
[dir
],
bcopy((void *)b
, (void *)stream_feed
[dir
], sizeof(Block
));
stream_index
[dir
] = 1; /* Next time will be 1 */
index
= 0; /* But now use 0 */
* On encryption, we store (feed ^ data) which is cypher
* On decryption we store (data) which is cypher
return(stream_output
[dir
][index
] =
(stream_feed
[dir
][index
] ^ data
));
return((stream_output
[dir
][index
] = data
) ^
stream_feed
[dir
][index
]);