openssl1.0/crypto/des/des.c
2019-08-09 10:00:55 +02:00

869 lines
27 KiB
C

/* crypto/des/des.c */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
* This package is an SSL implementation written
* by Eric Young (eay@cryptsoft.com).
* The implementation was written so as to conform with Netscapes SSL.
*
* This library is free for commercial and non-commercial use as long as
* the following conditions are aheared to. The following conditions
* apply to all code found in this distribution, be it the RC4, RSA,
* lhash, DES, etc., code; not just the SSL code. The SSL documentation
* included with this distribution is covered by the same copyright terms
* except that the holder is Tim Hudson (tjh@cryptsoft.com).
*
* Copyright remains Eric Young's, and as such any Copyright notices in
* the code are not to be removed.
* If this package is used in a product, Eric Young should be given attribution
* as the author of the parts of the library used.
* This can be in the form of a textual message at program startup or
* in documentation (online or textual) provided with the package.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the 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 cryptographic software written by
* Eric Young (eay@cryptsoft.com)"
* The word 'cryptographic' can be left out if the rouines from the library
* being used are not cryptographic related :-).
* 4. If you include any Windows specific code (or a derivative thereof) from
* the apps directory (application code) you must include an acknowledgement:
* "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
*
* THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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 AUTHOR 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
* SUCH DAMAGE.
*
* The licence and distribution terms for any publically available version or
* derivative of this code cannot be changed. i.e. this code cannot simply be
* copied and put under another distribution licence
* [including the GNU Public Licence.]
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openssl/opensslconf.h>
#ifndef OPENSSL_SYS_MSDOS
# ifndef OPENSSL_SYS_VMS
# include OPENSSL_UNISTD
# else /* OPENSSL_SYS_VMS */
# ifdef __DECC
# include <unistd.h>
# else /* not __DECC */
# include <math.h>
# endif /* __DECC */
# endif /* OPENSSL_SYS_VMS */
#else /* OPENSSL_SYS_MSDOS */
# include <io.h>
#endif
#include <time.h>
#include "des_ver.h"
#ifdef OPENSSL_SYS_VMS
# include <types.h>
# include <stat.h>
#else
# ifndef _IRIX
# include <sys/types.h>
# endif
# include <sys/stat.h>
#endif
#include <openssl/des.h>
#include <openssl/rand.h>
#include <openssl/ui_compat.h>
void usage(void);
void doencryption(void);
int uufwrite(unsigned char *data, int size, unsigned int num, FILE *fp);
void uufwriteEnd(FILE *fp);
int uufread(unsigned char *out, int size, unsigned int num, FILE *fp);
int uuencode(unsigned char *in, int num, unsigned char *out);
int uudecode(unsigned char *in, int num, unsigned char *out);
void DES_3cbc_encrypt(DES_cblock *input, DES_cblock *output, long length,
DES_key_schedule sk1, DES_key_schedule sk2,
DES_cblock *ivec1, DES_cblock *ivec2, int enc);
#ifdef OPENSSL_SYS_VMS
# define EXIT(a) exit(a&0x10000000L)
#else
# define EXIT(a) exit(a)
#endif
#define BUFSIZE (8*1024)
#define VERIFY 1
#define KEYSIZ 8
#define KEYSIZB 1024 /* should hit tty line limit first :-) */
char key[KEYSIZB + 1];
int do_encrypt, longk = 0;
FILE *DES_IN, *DES_OUT, *CKSUM_OUT;
char uuname[200];
unsigned char uubuf[50];
int uubufnum = 0;
#define INUUBUFN (45*100)
#define OUTUUBUF (65*100)
unsigned char b[OUTUUBUF];
unsigned char bb[300];
DES_cblock cksum = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
char cksumname[200] = "";
int vflag, cflag, eflag, dflag, kflag, bflag, fflag, sflag, uflag, flag3,
hflag, error;
int main(int argc, char **argv)
{
int i;
struct stat ins, outs;
char *p;
char *in = NULL, *out = NULL;
vflag = cflag = eflag = dflag = kflag = hflag = bflag = fflag = sflag =
uflag = flag3 = 0;
error = 0;
memset(key, 0, sizeof(key));
for (i = 1; i < argc; i++) {
p = argv[i];
if ((p[0] == '-') && (p[1] != '\0')) {
p++;
while (*p) {
switch (*(p++)) {
case '3':
flag3 = 1;
longk = 1;
break;
case 'c':
cflag = 1;
strncpy(cksumname, p, 200);
cksumname[sizeof(cksumname) - 1] = '\0';
p += strlen(cksumname);
break;
case 'C':
cflag = 1;
longk = 1;
strncpy(cksumname, p, 200);
cksumname[sizeof(cksumname) - 1] = '\0';
p += strlen(cksumname);
break;
case 'e':
eflag = 1;
break;
case 'v':
vflag = 1;
break;
case 'E':
eflag = 1;
longk = 1;
break;
case 'd':
dflag = 1;
break;
case 'D':
dflag = 1;
longk = 1;
break;
case 'b':
bflag = 1;
break;
case 'f':
fflag = 1;
break;
case 's':
sflag = 1;
break;
case 'u':
uflag = 1;
strncpy(uuname, p, 200);
uuname[sizeof(uuname) - 1] = '\0';
p += strlen(uuname);
break;
case 'h':
hflag = 1;
break;
case 'k':
kflag = 1;
if ((i + 1) == argc) {
fputs("must have a key with the -k option\n", stderr);
error = 1;
} else {
int j;
i++;
strncpy(key, argv[i], KEYSIZB);
for (j = strlen(argv[i]) - 1; j >= 0; j--)
argv[i][j] = '\0';
}
break;
default:
fprintf(stderr, "'%c' unknown flag\n", p[-1]);
error = 1;
break;
}
}
} else {
if (in == NULL)
in = argv[i];
else if (out == NULL)
out = argv[i];
else
error = 1;
}
}
if (error)
usage();
/*-
* We either
* do checksum or
* do encrypt or
* do decrypt or
* do decrypt then ckecksum or
* do checksum then encrypt
*/
if (((eflag + dflag) == 1) || cflag) {
if (eflag)
do_encrypt = DES_ENCRYPT;
if (dflag)
do_encrypt = DES_DECRYPT;
} else {
if (vflag) {
#ifndef _Windows
fprintf(stderr, "des(1) built with %s\n", libdes_version);
#endif
EXIT(1);
} else
usage();
}
#ifndef _Windows
if (vflag)
fprintf(stderr, "des(1) built with %s\n", libdes_version);
#endif
if ((in != NULL) && (out != NULL) &&
#ifndef OPENSSL_SYS_MSDOS
(stat(in, &ins) != -1) &&
(stat(out, &outs) != -1) &&
(ins.st_dev == outs.st_dev) && (ins.st_ino == outs.st_ino))
#else /* OPENSSL_SYS_MSDOS */
(strcmp(in, out) == 0))
#endif
{
fputs("input and output file are the same\n", stderr);
EXIT(3);
}
if (!kflag)
if (des_read_pw_string
(key, KEYSIZB + 1, "Enter key:", eflag ? VERIFY : 0)) {
fputs("password error\n", stderr);
EXIT(2);
}
if (in == NULL)
DES_IN = stdin;
else if ((DES_IN = fopen(in, "r")) == NULL) {
perror("opening input file");
EXIT(4);
}
CKSUM_OUT = stdout;
if (out == NULL) {
DES_OUT = stdout;
CKSUM_OUT = stderr;
} else if ((DES_OUT = fopen(out, "w")) == NULL) {
perror("opening output file");
EXIT(5);
}
#ifdef OPENSSL_SYS_MSDOS
/* This should set the file to binary mode. */
{
# include <fcntl.h>
if (!(uflag && dflag))
setmode(fileno(DES_IN), O_BINARY);
if (!(uflag && eflag))
setmode(fileno(DES_OUT), O_BINARY);
}
#endif
doencryption();
fclose(DES_IN);
fclose(DES_OUT);
EXIT(0);
}
void usage(void)
{
char **u;
static const char *Usage[] = {
"des <options> [input-file [output-file]]",
"options:",
"-v : des(1) version number",
"-e : encrypt using SunOS compatible user key to DES key conversion.",
"-E : encrypt ",
"-d : decrypt using SunOS compatible user key to DES key conversion.",
"-D : decrypt ",
"-c[ckname] : generate a cbc_cksum using SunOS compatible user key to",
" DES key conversion and output to ckname (stdout default,",
" stderr if data being output on stdout). The checksum is",
" generated before encryption and after decryption if used",
" in conjunction with -[eEdD].",
"-C[ckname] : generate a cbc_cksum as for -c but compatible with -[ED].",
"-k key : use key 'key'",
"-h : the key that is entered will be a hexadecimal number",
" that is used directly as the des key",
"-u[uuname] : input file is uudecoded if -[dD] or output uuencoded data if -[eE]",
" (uuname is the filename to put in the uuencode header).",
"-b : encrypt using DES in ecb encryption mode, the default is cbc mode.",
"-3 : encrypt using triple DES encryption. This uses 2 keys",
" generated from the input key. If the input key is less",
" than 8 characters long, this is equivalent to normal",
" encryption. Default is triple cbc, -b makes it triple ecb.",
NULL
};
for (u = (char **)Usage; *u; u++) {
fputs(*u, stderr);
fputc('\n', stderr);
}
EXIT(1);
}
void doencryption(void)
{
#ifdef _LIBC
extern unsigned long time();
#endif
register int i;
DES_key_schedule ks, ks2;
DES_cblock iv, iv2;
char *p;
int num = 0, j, k, l, rem, ll, len, last, ex = 0;
DES_cblock kk, k2;
FILE *O;
int Exit = 0;
#ifndef OPENSSL_SYS_MSDOS
static unsigned char buf[BUFSIZE + 8], obuf[BUFSIZE + 8];
#else
static unsigned char *buf = NULL, *obuf = NULL;
if (buf == NULL) {
if (((buf = OPENSSL_malloc(BUFSIZE + 8)) == NULL) ||
((obuf = OPENSSL_malloc(BUFSIZE + 8)) == NULL)) {
fputs("Not enough memory\n", stderr);
Exit = 10;
goto problems;
}
}
#endif
if (hflag) {
j = (flag3 ? 16 : 8);
p = key;
for (i = 0; i < j; i++) {
k = 0;
if ((*p <= '9') && (*p >= '0'))
k = (*p - '0') << 4;
else if ((*p <= 'f') && (*p >= 'a'))
k = (*p - 'a' + 10) << 4;
else if ((*p <= 'F') && (*p >= 'A'))
k = (*p - 'A' + 10) << 4;
else {
fputs("Bad hex key\n", stderr);
Exit = 9;
goto problems;
}
p++;
if ((*p <= '9') && (*p >= '0'))
k |= (*p - '0');
else if ((*p <= 'f') && (*p >= 'a'))
k |= (*p - 'a' + 10);
else if ((*p <= 'F') && (*p >= 'A'))
k |= (*p - 'A' + 10);
else {
fputs("Bad hex key\n", stderr);
Exit = 9;
goto problems;
}
p++;
if (i < 8)
kk[i] = k;
else
k2[i - 8] = k;
}
DES_set_key_unchecked(&k2, &ks2);
OPENSSL_cleanse(k2, sizeof(k2));
} else if (longk || flag3) {
if (flag3) {
DES_string_to_2keys(key, &kk, &k2);
DES_set_key_unchecked(&k2, &ks2);
OPENSSL_cleanse(k2, sizeof(k2));
} else
DES_string_to_key(key, &kk);
} else
for (i = 0; i < KEYSIZ; i++) {
l = 0;
k = key[i];
for (j = 0; j < 8; j++) {
if (k & 1)
l++;
k >>= 1;
}
if (l & 1)
kk[i] = key[i] & 0x7f;
else
kk[i] = key[i] | 0x80;
}
DES_set_key_unchecked(&kk, &ks);
OPENSSL_cleanse(key, sizeof(key));
OPENSSL_cleanse(kk, sizeof(kk));
/* woops - A bug that does not showup under unix :-( */
memset(iv, 0, sizeof(iv));
memset(iv2, 0, sizeof(iv2));
l = 1;
rem = 0;
/* first read */
if (eflag || (!dflag && cflag)) {
for (;;) {
num = l = fread(&(buf[rem]), 1, BUFSIZE, DES_IN);
l += rem;
num += rem;
if (l < 0) {
perror("read error");
Exit = 6;
goto problems;
}
rem = l % 8;
len = l - rem;
if (feof(DES_IN)) {
for (i = 7 - rem; i > 0; i--) {
if (RAND_bytes(buf + l++, 1) <= 0)
goto problems;
}
buf[l++] = rem;
ex = 1;
len += rem;
} else
l -= rem;
if (cflag) {
DES_cbc_cksum(buf, &cksum, (long)len, &ks, &cksum);
if (!eflag) {
if (feof(DES_IN))
break;
else
continue;
}
}
if (bflag && !flag3)
for (i = 0; i < l; i += 8)
DES_ecb_encrypt((DES_cblock *)&(buf[i]),
(DES_cblock *)&(obuf[i]),
&ks, do_encrypt);
else if (flag3 && bflag)
for (i = 0; i < l; i += 8)
DES_ecb2_encrypt((DES_cblock *)&(buf[i]),
(DES_cblock *)&(obuf[i]),
&ks, &ks2, do_encrypt);
else if (flag3 && !bflag) {
char tmpbuf[8];
if (rem)
memcpy(tmpbuf, &(buf[l]), (unsigned int)rem);
DES_3cbc_encrypt((DES_cblock *)buf, (DES_cblock *)obuf,
(long)l, ks, ks2, &iv, &iv2, do_encrypt);
if (rem)
memcpy(&(buf[l]), tmpbuf, (unsigned int)rem);
} else {
DES_cbc_encrypt(buf, obuf, (long)l, &ks, &iv, do_encrypt);
if (l >= 8)
memcpy(iv, &(obuf[l - 8]), 8);
}
if (rem)
memcpy(buf, &(buf[l]), (unsigned int)rem);
i = 0;
while (i < l) {
if (uflag)
j = uufwrite(obuf, 1, (unsigned int)l - i, DES_OUT);
else
j = fwrite(obuf, 1, (unsigned int)l - i, DES_OUT);
if (j == -1) {
perror("Write error");
Exit = 7;
goto problems;
}
i += j;
}
if (feof(DES_IN)) {
if (uflag)
uufwriteEnd(DES_OUT);
break;
}
}
} else { /* decrypt */
ex = 1;
for (;;) {
if (ex) {
if (uflag)
l = uufread(buf, 1, BUFSIZE, DES_IN);
else
l = fread(buf, 1, BUFSIZE, DES_IN);
ex = 0;
rem = l % 8;
l -= rem;
}
if (l < 0) {
perror("read error");
Exit = 6;
goto problems;
}
if (bflag && !flag3)
for (i = 0; i < l; i += 8)
DES_ecb_encrypt((DES_cblock *)&(buf[i]),
(DES_cblock *)&(obuf[i]),
&ks, do_encrypt);
else if (flag3 && bflag)
for (i = 0; i < l; i += 8)
DES_ecb2_encrypt((DES_cblock *)&(buf[i]),
(DES_cblock *)&(obuf[i]),
&ks, &ks2, do_encrypt);
else if (flag3 && !bflag) {
DES_3cbc_encrypt((DES_cblock *)buf, (DES_cblock *)obuf,
(long)l, ks, ks2, &iv, &iv2, do_encrypt);
} else {
DES_cbc_encrypt(buf, obuf, (long)l, &ks, &iv, do_encrypt);
if (l >= 8)
memcpy(iv, &(buf[l - 8]), 8);
}
if (uflag)
ll = uufread(&(buf[rem]), 1, BUFSIZE, DES_IN);
else
ll = fread(&(buf[rem]), 1, BUFSIZE, DES_IN);
ll += rem;
rem = ll % 8;
ll -= rem;
if (feof(DES_IN) && (ll == 0)) {
last = obuf[l - 1];
if ((last > 7) || (last < 0)) {
fputs("The file was not decrypted correctly.\n", stderr);
Exit = 8;
last = 0;
}
l = l - 8 + last;
}
i = 0;
if (cflag)
DES_cbc_cksum(obuf,
(DES_cblock *)cksum, (long)l / 8 * 8, &ks,
(DES_cblock *)cksum);
while (i != l) {
j = fwrite(obuf, 1, (unsigned int)l - i, DES_OUT);
if (j == -1) {
perror("Write error");
Exit = 7;
goto problems;
}
i += j;
}
l = ll;
if ((l == 0) && feof(DES_IN))
break;
}
}
if (cflag) {
l = 0;
if (cksumname[0] != '\0') {
if ((O = fopen(cksumname, "w")) != NULL) {
CKSUM_OUT = O;
l = 1;
}
}
for (i = 0; i < 8; i++)
fprintf(CKSUM_OUT, "%02X", cksum[i]);
fprintf(CKSUM_OUT, "\n");
if (l)
fclose(CKSUM_OUT);
}
problems:
OPENSSL_cleanse(buf, sizeof(buf));
OPENSSL_cleanse(obuf, sizeof(obuf));
OPENSSL_cleanse(&ks, sizeof(ks));
OPENSSL_cleanse(&ks2, sizeof(ks2));
OPENSSL_cleanse(iv, sizeof(iv));
OPENSSL_cleanse(iv2, sizeof(iv2));
OPENSSL_cleanse(kk, sizeof(kk));
OPENSSL_cleanse(k2, sizeof(k2));
OPENSSL_cleanse(uubuf, sizeof(uubuf));
OPENSSL_cleanse(b, sizeof(b));
OPENSSL_cleanse(bb, sizeof(bb));
OPENSSL_cleanse(cksum, sizeof(cksum));
if (Exit)
EXIT(Exit);
}
/* We ignore this parameter but it should be > ~50 I believe */
int uufwrite(unsigned char *data, int size, unsigned int num, FILE *fp)
{
int i, j, left, rem, ret = num;
static int start = 1;
if (start) {
fprintf(fp, "begin 600 %s\n",
(uuname[0] == '\0') ? "text.d" : uuname);
start = 0;
}
if (uubufnum) {
if (uubufnum + num < 45) {
memcpy(&(uubuf[uubufnum]), data, (unsigned int)num);
uubufnum += num;
return (num);
} else {
i = 45 - uubufnum;
memcpy(&(uubuf[uubufnum]), data, (unsigned int)i);
j = uuencode((unsigned char *)uubuf, 45, b);
fwrite(b, 1, (unsigned int)j, fp);
uubufnum = 0;
data += i;
num -= i;
}
}
for (i = 0; i < (((int)num) - INUUBUFN); i += INUUBUFN) {
j = uuencode(&(data[i]), INUUBUFN, b);
fwrite(b, 1, (unsigned int)j, fp);
}
rem = (num - i) % 45;
left = (num - i - rem);
if (left) {
j = uuencode(&(data[i]), left, b);
fwrite(b, 1, (unsigned int)j, fp);
i += left;
}
if (i != num) {
memcpy(uubuf, &(data[i]), (unsigned int)rem);
uubufnum = rem;
}
return (ret);
}
void uufwriteEnd(FILE *fp)
{
int j;
static const char *end = " \nend\n";
if (uubufnum != 0) {
uubuf[uubufnum] = '\0';
uubuf[uubufnum + 1] = '\0';
uubuf[uubufnum + 2] = '\0';
j = uuencode(uubuf, uubufnum, b);
fwrite(b, 1, (unsigned int)j, fp);
}
fwrite(end, 1, strlen(end), fp);
}
/*
* int size: should always be > ~ 60; I actually ignore this parameter :-)
*/
int uufread(unsigned char *out, int size, unsigned int num, FILE *fp)
{
int i, j, tot;
static int done = 0;
static int valid = 0;
static int start = 1;
if (start) {
for (;;) {
b[0] = '\0';
fgets((char *)b, 300, fp);
if (b[0] == '\0') {
fprintf(stderr, "no 'begin' found in uuencoded input\n");
return (-1);
}
if (strncmp((char *)b, "begin ", 6) == 0)
break;
}
start = 0;
}
if (done)
return (0);
tot = 0;
if (valid) {
memcpy(out, bb, (unsigned int)valid);
tot = valid;
valid = 0;
}
for (;;) {
b[0] = '\0';
fgets((char *)b, 300, fp);
if (b[0] == '\0')
break;
i = strlen((char *)b);
if ((b[0] == 'e') && (b[1] == 'n') && (b[2] == 'd')) {
done = 1;
while (!feof(fp)) {
fgets((char *)b, 300, fp);
}
break;
}
i = uudecode(b, i, bb);
if (i < 0)
break;
if ((i + tot + 8) > num) {
/* num to copy to make it a multiple of 8 */
j = (num / 8 * 8) - tot - 8;
memcpy(&(out[tot]), bb, (unsigned int)j);
tot += j;
memcpy(bb, &(bb[j]), (unsigned int)i - j);
valid = i - j;
break;
}
memcpy(&(out[tot]), bb, (unsigned int)i);
tot += i;
}
return (tot);
}
#define ccc2l(c,l) (l =((DES_LONG)(*((c)++)))<<16, \
l|=((DES_LONG)(*((c)++)))<< 8, \
l|=((DES_LONG)(*((c)++))))
#define l2ccc(l,c) (*((c)++)=(unsigned char)(((l)>>16)&0xff), \
*((c)++)=(unsigned char)(((l)>> 8)&0xff), \
*((c)++)=(unsigned char)(((l) )&0xff))
int uuencode(unsigned char *in, int num, unsigned char *out)
{
int j, i, n, tot = 0;
DES_LONG l;
register unsigned char *p;
p = out;
for (j = 0; j < num; j += 45) {
if (j + 45 > num)
i = (num - j);
else
i = 45;
*(p++) = i + ' ';
for (n = 0; n < i; n += 3) {
ccc2l(in, l);
*(p++) = ((l >> 18) & 0x3f) + ' ';
*(p++) = ((l >> 12) & 0x3f) + ' ';
*(p++) = ((l >> 6) & 0x3f) + ' ';
*(p++) = ((l) & 0x3f) + ' ';
tot += 4;
}
*(p++) = '\n';
tot += 2;
}
*p = '\0';
l = 0;
return (tot);
}
int uudecode(unsigned char *in, int num, unsigned char *out)
{
int j, i, k;
unsigned int n = 0, space = 0;
DES_LONG l;
DES_LONG w, x, y, z;
unsigned int blank = (unsigned int)'\n' - ' ';
for (j = 0; j < num;) {
n = *(in++) - ' ';
if (n == blank) {
n = 0;
in--;
}
if (n > 60) {
fprintf(stderr, "uuencoded line length too long\n");
return (-1);
}
j++;
for (i = 0; i < n; j += 4, i += 3) {
/*
* the following is for cases where spaces are removed from
* lines.
*/
if (space) {
w = x = y = z = 0;
} else {
w = *(in++) - ' ';
x = *(in++) - ' ';
y = *(in++) - ' ';
z = *(in++) - ' ';
}
if ((w > 63) || (x > 63) || (y > 63) || (z > 63)) {
k = 0;
if (w == blank)
k = 1;
if (x == blank)
k = 2;
if (y == blank)
k = 3;
if (z == blank)
k = 4;
space = 1;
switch (k) {
case 1:
w = 0;
in--;
case 2:
x = 0;
in--;
case 3:
y = 0;
in--;
case 4:
z = 0;
in--;
break;
case 0:
space = 0;
fprintf(stderr, "bad uuencoded data values\n");
w = x = y = z = 0;
return (-1);
break;
}
}
l = (w << 18) | (x << 12) | (y << 6) | (z);
l2ccc(l, out);
}
if (*(in++) != '\n') {
fprintf(stderr, "missing nl in uuencoded line\n");
w = x = y = z = 0;
return (-1);
}
j++;
}
*out = '\0';
w = x = y = z = 0;
return (n);
}