* 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
[] = "@(#)enc_des.c 5.1 (Berkeley) 3/22/91";
#if defined(AUTHENTICATE) && defined(ENCRYPT) && defined(DES_ENCRYPT)
extern encrypt_debug_mode
;
#define IN_PROGRESS (NO_SEND_IV|NO_RECV_IV|NO_KEYID)
unsigned char fb_feed
[64];
{ "\0", 1, 0, 0, 0 }, /* default key of zero */
#define KEYFLAG_NOINIT 00
#define SHIFT_VAL(a,b) (KEYFLAG_SHIFT*((a)+((b)*2)))
void fb64_stream_iv
P((Block
, struct stinfo
*));
void fb64_init
P((struct fb
*));
int fb64_start
P((struct fb
*, int, int));
int fb64_is
P((unsigned char *, int, struct fb
*));
int fb64_reply
P((unsigned char *, int, struct fb
*));
void fb64_session
P((Session_Key
*, int, struct fb
*));
void fb64_stream_key
P((Block
, struct stinfo
*));
int fb64_keyid
P((int, unsigned char *, int *, struct fb
*));
fb
[CFB
].fb_feed
[4] = ENCTYPE_DES_CFB64
;
fb
[CFB
].streams
[0].str_flagshift
= SHIFT_VAL(0, CFB
);
fb
[CFB
].streams
[1].str_flagshift
= SHIFT_VAL(1, CFB
);
fb
[OFB
].fb_feed
[4] = ENCTYPE_DES_OFB64
;
fb
[CFB
].streams
[0].str_flagshift
= SHIFT_VAL(0, OFB
);
fb
[CFB
].streams
[1].str_flagshift
= SHIFT_VAL(1, OFB
);
bzero((void *)fbp
, sizeof(*fbp
));
fbp
->state
[0] = fbp
->state
[1] = FAILED
;
fbp
->fb_feed
[2] = TELOPT_ENCRYPT
;
fbp
->fb_feed
[3] = ENCRYPT_IS
;
* -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.
return(fb64_start(&fb
[CFB
], dir
, server
));
return(fb64_start(&fb
[OFB
], dir
, server
));
fb64_start(fbp
, dir
, server
)
* This is simply a request to have the other side
* start output (our input). He will negotiate an
* IV so we need not look for it.
state
= fbp
->state
[dir
-1];
state
= fbp
->state
[dir
-1];
else if ((state
& NO_SEND_IV
) == 0)
if (!VALIDKEY(fbp
->krbdes_key
)) {
printf("Creating new feed\r\n");
* Create a random feed and send it over.
des_new_random_key(fbp
->temp_feed
);
des_ecb_encrypt(fbp
->temp_feed
, fbp
->temp_feed
,
for (x
= 0; x
< sizeof(Block
); ++x
) {
if ((*p
++ = fbp
->temp_feed
[x
]) == IAC
)
printsub('>', &fbp
->fb_feed
[2], p
- &fbp
->fb_feed
[2]);
net_write(fbp
->fb_feed
, p
- fbp
->fb_feed
);
return(fbp
->state
[dir
-1] = state
);
* -1: some error. Negotiation is done, encryption not ready.
* 0: Successful, initial negotiation all done.
* 1: successful, negotiation not done yet.
return(fb64_is(data
, cnt
, &fb
[CFB
]));
return(fb64_is(data
, cnt
, &fb
[OFB
]));
register int state
= fbp
->state
[DIR_DECRYPT
-1];
if (cnt
!= sizeof(Block
)) {
printf("CFB64: initial vector failed on size\r\n");
printf("CFB64: initial vector received\r\n");
printf("Initializing Decrypt stream\r\n");
fb64_stream_iv((void *)data
, &fbp
->streams
[DIR_DECRYPT
-1]);
printsub('>', &fbp
->fb_feed
[2], p
- &fbp
->fb_feed
[2]);
net_write(fbp
->fb_feed
, p
- fbp
->fb_feed
);
state
= fbp
->state
[DIR_DECRYPT
-1] = IN_PROGRESS
;
if (encrypt_debug_mode
) {
printf("Unknown option type: %d\r\n", *(data
-1));
* We failed. Send an FB64_IV_BAD option
* to the other side so it will know that
printsub('>', &fbp
->fb_feed
[2], p
- &fbp
->fb_feed
[2]);
net_write(fbp
->fb_feed
, p
- fbp
->fb_feed
);
return(fbp
->state
[DIR_DECRYPT
-1] = state
);
* -1: some error. Negotiation is done, encryption not ready.
* 0: Successful, initial negotiation all done.
* 1: successful, negotiation not done yet.
return(fb64_reply(data
, cnt
, &fb
[CFB
]));
return(fb64_reply(data
, cnt
, &fb
[OFB
]));
fb64_reply(data
, cnt
, fbp
)
register int state
= fbp
->state
[DIR_ENCRYPT
-1];
fb64_stream_iv(fbp
->temp_feed
, &fbp
->streams
[DIR_ENCRYPT
-1]);
encrypt_send_keyid(DIR_ENCRYPT
, (unsigned char *)"\0", 1, 1);
bzero(fbp
->temp_feed
, sizeof(Block
));
fb64_stream_iv(fbp
->temp_feed
, &fbp
->streams
[DIR_ENCRYPT
-1]);
if (encrypt_debug_mode
) {
printf("Unknown option type: %d\r\n", data
[-1]);
return(fbp
->state
[DIR_ENCRYPT
-1] = state
);
cfb64_session(key
, server
)
fb64_session(key
, server
, &fb
[CFB
]);
ofb64_session(key
, server
)
fb64_session(key
, server
, &fb
[OFB
]);
fb64_session(key
, server
, fbp
)
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 *)fbp
->krbdes_key
, sizeof(Block
));
fb64_stream_key(fbp
->krbdes_key
, &fbp
->streams
[DIR_ENCRYPT
-1]);
fb64_stream_key(fbp
->krbdes_key
, &fbp
->streams
[DIR_DECRYPT
-1]);
des_set_random_generator_seed(fbp
->krbdes_key
);
des_key_sched(fbp
->krbdes_key
, fbp
->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
fb64_start(fbp
, DIR_ENCRYPT
, server
);
* We only accept a keyid of 0. If we get a keyid of
* 0, then mark the state as SUCCESS.
cfb64_keyid(dir
, kp
, lenp
)
return(fb64_keyid(dir
, kp
, lenp
, &fb
[CFB
]));
ofb64_keyid(dir
, kp
, lenp
)
return(fb64_keyid(dir
, kp
, lenp
, &fb
[OFB
]));
fb64_keyid(dir
, kp
, lenp
, fbp
)
register int state
= fbp
->state
[dir
-1];
if (*lenp
!= 1 || (*kp
!= '\0')) {
return(fbp
->state
[dir
-1] = state
);
fb64_printsub(data
, cnt
, buf
, buflen
, type
)
unsigned char *data
, *buf
, *type
;
buf
[buflen
-1] = '\0'; /* make sure it's NULL terminated */
sprintf(lbuf
, "%s_IV", type
);
sprintf(lbuf
, "%s_IV_OK", type
);
sprintf(lbuf
, "%s_IV_BAD", type
);
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
++)
cfb64_printsub(data
, cnt
, buf
, buflen
)
unsigned char *data
, *buf
;
fb64_printsub(data
, cnt
, buf
, buflen
, "CFB64");
ofb64_printsub(data
, cnt
, buf
, buflen
)
unsigned char *data
, *buf
;
fb64_printsub(data
, cnt
, buf
, buflen
, "OFB64");
fb64_stream_iv(seed
, stp
)
register struct stinfo
*stp
;
bcopy((void *)seed
, (void *)stp
->str_iv
, sizeof(Block
));
bcopy((void *)seed
, (void *)stp
->str_output
, sizeof(Block
));
des_key_sched(stp
->str_ikey
, stp
->str_sched
);
stp
->str_index
= sizeof(Block
);
fb64_stream_key(key
, stp
)
register struct stinfo
*stp
;
bcopy((void *)key
, (void *)stp
->str_ikey
, sizeof(Block
));
des_key_sched(key
, stp
->str_sched
);
bcopy((void *)stp
->str_iv
, (void *)stp
->str_output
, sizeof(Block
));
stp
->str_index
= sizeof(Block
);
* DES 64 bit Cipher Feedback
* INPUT --(--------->(+)+---> DATA
* iV: Initial vector, 64 bits (8 bytes) long.
* Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt).
* On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output.
register unsigned char *s
;
register struct stinfo
*stp
= &fb
[CFB
].streams
[DIR_ENCRYPT
-1];
if (index
== sizeof(Block
)) {
des_ecb_encrypt(stp
->str_output
, b
, stp
->str_sched
, 1);
bcopy((void *)b
, (void *)stp
->str_feed
, sizeof(Block
));
/* On encryption, we store (feed ^ data) which is cypher */
*s
= stp
->str_output
[index
] = (stp
->str_feed
[index
] ^ *s
);
register struct stinfo
*stp
= &fb
[CFB
].streams
[DIR_DECRYPT
-1];
* Back up one byte. It is assumed that we will
* never back up more than one byte. If we do, this
index
= stp
->str_index
++;
if (index
== sizeof(Block
)) {
des_ecb_encrypt(stp
->str_output
, b
, stp
->str_sched
, 1);
bcopy((void *)b
, (void *)stp
->str_feed
, sizeof(Block
));
stp
->str_index
= 1; /* Next time will be 1 */
index
= 0; /* But now use 0 */
/* On decryption we store (data) which is cypher. */
stp
->str_output
[index
] = data
;
return(data
^ stp
->str_feed
[index
]);
* DES 64 bit Output Feedback
* INPUT -------->(+) ----> DATA
* iV: Initial vector, 64 bits (8 bytes) long.
* Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt).
* On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output.
register unsigned char *s
;
register struct stinfo
*stp
= &fb
[OFB
].streams
[DIR_ENCRYPT
-1];
if (index
== sizeof(Block
)) {
des_ecb_encrypt(stp
->str_feed
, b
, stp
->str_sched
, 1);
bcopy((void *)b
, (void *)stp
->str_feed
, sizeof(Block
));
*s
++ ^= stp
->str_feed
[index
];
register struct stinfo
*stp
= &fb
[OFB
].streams
[DIR_DECRYPT
-1];
* Back up one byte. It is assumed that we will
* never back up more than one byte. If we do, this
index
= stp
->str_index
++;
if (index
== sizeof(Block
)) {
des_ecb_encrypt(stp
->str_feed
, b
, stp
->str_sched
, 1);
bcopy((void *)b
, (void *)stp
->str_feed
, sizeof(Block
));
stp
->str_index
= 1; /* Next time will be 1 */
index
= 0; /* But now use 0 */
return(data
^ stp
->str_feed
[index
]);