#include "mt.h"
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <rpc/rpc.h>
#include <rpc/key_prot.h>
#include <rpc/des_crypt.h>
#include <string.h>
#include <rpcsvc/nis_dhext.h>
#include <md5.h>
#define MD5HEXSIZE 32
extern int bin2hex(int len, unsigned char *binnum, char *hexnum);
extern int hex2bin(int len, char *hexnum, char *binnum);
static char hex[];
static char hexval();
int passwd2des(char *, char *);
static int weak_DES_key(des_block);
#define MAX_KEY_CRYPT_LEN 144
int
xencrypt(secret, passwd)
char *secret;
char *passwd;
{
char key[8];
char ivec[8];
char *buf;
int err;
int len;
len = (int)strlen(secret) / 2;
if (len > MAX_KEY_CRYPT_LEN)
return (0);
buf = malloc((unsigned)len);
(void) hex2bin(len, secret, buf);
(void) passwd2des(passwd, key);
(void) memset(ivec, 0, 8);
err = cbc_crypt(key, buf, len, DES_ENCRYPT | DES_HW, ivec);
if (DES_FAILED(err)) {
free(buf);
return (0);
}
(void) bin2hex(len, (unsigned char *) buf, secret);
free(buf);
return (1);
}
int
xdecrypt(secret, passwd)
char *secret;
char *passwd;
{
char key[8];
char ivec[8];
char *buf;
int err;
int len;
len = (int)strlen(secret) / 2;
if (len > MAX_KEY_CRYPT_LEN)
return (0);
buf = malloc((unsigned)len);
(void) hex2bin(len, secret, buf);
(void) passwd2des(passwd, key);
(void) memset(ivec, 0, 8);
err = cbc_crypt(key, buf, len, DES_DECRYPT | DES_HW, ivec);
if (DES_FAILED(err)) {
free(buf);
return (0);
}
(void) bin2hex(len, (unsigned char *) buf, secret);
free(buf);
return (1);
}
int
passwd2des(pw, key)
char *pw;
char *key;
{
int i;
(void) memset(key, 0, 8);
for (i = 0; *pw; i = (i+1) % 8) {
key[i] ^= *pw++ << 1;
}
des_setparity(key);
return (1);
}
int
hex2bin(len, hexnum, binnum)
int len;
char *hexnum;
char *binnum;
{
int i;
for (i = 0; i < len; i++) {
*binnum++ = 16 * hexval(hexnum[2 * i]) +
hexval(hexnum[2 * i + 1]);
}
return (1);
}
int
bin2hex(len, binnum, hexnum)
int len;
unsigned char *binnum;
char *hexnum;
{
int i;
unsigned val;
for (i = 0; i < len; i++) {
val = binnum[i];
hexnum[i*2] = hex[val >> 4];
hexnum[i*2+1] = hex[val & 0xf];
}
hexnum[len*2] = 0;
return (1);
}
static char hex[16] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
};
static char
hexval(c)
char c;
{
if (c >= '0' && c <= '9') {
return (c - '0');
} else if (c >= 'a' && c <= 'z') {
return (c - 'a' + 10);
} else if (c >= 'A' && c <= 'Z') {
return (c - 'A' + 10);
} else {
return (-1);
}
}
int
xencrypt_g(
char *secret,
keylen_t keylen,
algtype_t algtype,
const char *passwd,
const char netname[],
char **encrypted_secret,
bool_t do_chksum)
{
des_block key;
char ivec[8];
char *binkeybuf;
int err;
const int classic_des = keylen == 192 && algtype == 0;
const int hexkeybytes = BITS2NIBBLES(keylen);
const int keychecksumsize = classic_des ? KEYCHECKSUMSIZE : MD5HEXSIZE;
const int binkeybytes = do_chksum ? keylen/8 + keychecksumsize/2 :
keylen/8;
const int bufsize = do_chksum ? hexkeybytes + keychecksumsize + 1 :
hexkeybytes + 1;
char *hexkeybuf;
if (!secret || !keylen || !passwd || !encrypted_secret)
return (0);
if ((hexkeybuf = malloc(bufsize)) == 0)
return (0);
(void) memcpy(hexkeybuf, secret, hexkeybytes);
if (do_chksum)
if (classic_des) {
(void) memcpy(hexkeybuf + hexkeybytes, secret,
keychecksumsize);
} else {
MD5_CTX md5_ctx;
char md5hexbuf[MD5HEXSIZE + 1] = {0};
uint8_t digest[MD5HEXSIZE/2];
MD5Init(&md5_ctx);
MD5Update(&md5_ctx, (unsigned char *)hexkeybuf,
hexkeybytes);
MD5Final(digest, &md5_ctx);
(void) bin2hex(MD5HEXSIZE/2, digest, md5hexbuf);
(void) memcpy(hexkeybuf + hexkeybytes,
(void *)md5hexbuf, MD5HEXSIZE);
}
hexkeybuf[bufsize - 1] = 0;
if (binkeybytes > MAX_KEY_CRYPT_LEN) {
free(hexkeybuf);
return (0);
}
if ((binkeybuf = malloc((unsigned)binkeybytes)) == 0) {
free(hexkeybuf);
return (0);
}
(void) hex2bin(binkeybytes, hexkeybuf, binkeybuf);
if (classic_des)
(void) passwd2des((char *)passwd, key.c);
else
if (netname)
(void) passwd2des_g(passwd, netname,
(int)strlen(netname), &key, FALSE);
else {
free(hexkeybuf);
return (0);
}
(void) memset(ivec, 0, 8);
err = cbc_crypt(key.c, binkeybuf, binkeybytes, DES_ENCRYPT | DES_HW,
ivec);
if (DES_FAILED(err)) {
free(hexkeybuf);
free(binkeybuf);
return (0);
}
(void) bin2hex(binkeybytes, (unsigned char *) binkeybuf, hexkeybuf);
free(binkeybuf);
*encrypted_secret = hexkeybuf;
return (1);
}
int
xdecrypt_g(
char *secret,
int keylen,
int algtype,
const char *passwd,
const char netname[],
bool_t do_chksum)
{
des_block key;
char ivec[8];
char *buf;
int err;
int len;
const int classic_des = keylen == 192 && algtype == 0;
const int hexkeybytes = BITS2NIBBLES(keylen);
const int keychecksumsize = classic_des ? KEYCHECKSUMSIZE : MD5HEXSIZE;
len = (int)strlen(secret) / 2;
if (len > MAX_KEY_CRYPT_LEN)
return (0);
if ((buf = malloc((unsigned)len)) == 0)
return (0);
(void) hex2bin(len, secret, buf);
if (classic_des)
(void) passwd2des((char *)passwd, key.c);
else
if (netname)
(void) passwd2des_g(passwd, netname,
(int)strlen(netname), &key, FALSE);
else {
free(buf);
return (0);
}
(void) memset(ivec, 0, 8);
err = cbc_crypt(key.c, buf, len, DES_DECRYPT | DES_HW, ivec);
if (DES_FAILED(err)) {
free(buf);
return (0);
}
(void) bin2hex(len, (unsigned char *) buf, secret);
free(buf);
if (do_chksum)
if (classic_des) {
if (memcmp(secret, &(secret[hexkeybytes]),
keychecksumsize) != 0) {
secret[0] = 0;
return (0);
}
} else {
MD5_CTX md5_ctx;
char md5hexbuf[MD5HEXSIZE + 1] = {0};
uint8_t digest[MD5HEXSIZE/2];
MD5Init(&md5_ctx);
MD5Update(&md5_ctx, (unsigned char *)secret,
hexkeybytes);
MD5Final(digest, &md5_ctx);
(void) bin2hex(MD5HEXSIZE/2, digest, md5hexbuf);
if (memcmp(&(secret[hexkeybytes]),
md5hexbuf, MD5HEXSIZE) != 0) {
secret[0] = 0;
return (0);
}
}
secret[hexkeybytes] = '\0';
return (1);
}
int
passwd2des_g(
const char *pw,
const char *mixin,
int len,
des_block *key,
bool_t altalg)
{
int i, j, incr = 1;
des_block ivec, tkey;
char *text;
int plen, tlen;
(void) memset(tkey.c, 0, 8);
(void) memset(ivec.c, 0, 8);
#define KEYLEN sizeof (tkey.c)
plen = strlen(pw);
tlen = ((plen + len + (KEYLEN-1))/KEYLEN)*KEYLEN;
if ((text = malloc(tlen)) == NULL) {
return (0);
}
(void) memset(text, 0, tlen);
if (!altalg) {
(void) memcpy(text, pw, plen);
(void) memcpy(&text[plen], mixin, len);
for (i = 0, j = 0; pw[j]; j++) {
tkey.c[i] ^= pw[j] << 1;
i += incr;
if (i == 8) {
i = 7;
incr = -incr;
} else if (i == -1) {
i = 0;
incr = -incr;
}
}
for (j = 0; j < len; j++) {
tkey.c[i] ^= mixin[j];
i += incr;
if (i == 8) {
i = 7;
incr = -incr;
} else if (i == -1) {
i = 0;
incr = -incr;
}
}
} else {
(void) memcpy(text, mixin, len);
(void) memcpy(&text[len], pw, plen);
for (i = 0, j = 0; j < len; j++) {
tkey.c[i] ^= mixin[j];
i += incr;
if (i == 8) {
i = 7;
incr = -incr;
} else if (i == -1) {
i = 0;
incr = -incr;
}
}
for (j = 0; pw[j]; j++) {
tkey.c[i] ^= pw[j] << 1;
i += incr;
if (i == 8) {
i = 7;
incr = -incr;
} else if (i == -1) {
i = 0;
incr = -incr;
}
}
}
des_setparity_g(&tkey);
(void) cbc_crypt(tkey.c, text, tlen, DES_ENCRYPT|DES_HW, ivec.c);
des_setparity_g(&ivec);
free(text);
if (weak_DES_key(ivec)) {
ivec.c[7] ^= 0xf0;
}
(void) memcpy((*key).c, ivec.c, sizeof (ivec.c));
return (1);
}
struct DESkey {
uint32_t h1;
uint32_t h2;
};
static struct DESkey weakDESkeys[] = {
{0x01010101, 0x01010101},
{0x1f1f1f1f, 0x1f1f1f1f},
{0xe0e0e0e0, 0xe0e0e0e0},
{0xfefefefe, 0xfefefefe},
{0x01fe01fe, 0x01fe01fe},
{0x1fe01fe0, 0x0ef10ef1},
{0x01e001e0, 0x01f101f1},
{0x1ffe1ffe, 0x0efe0efe},
{0x011f011f, 0x010e010e},
{0xe0fee0fe, 0xf1fef1fe},
{0xfe01fe01, 0xfe01fe01},
{0xe01fe01f, 0xf10ef10e},
{0xe001e001, 0xf101f101},
{0xfe1ffe1f, 0xfe0efe0e},
{0x1f011f01, 0x0e010e01},
{0xfee0fee0, 0xfef1fef1}
};
static int
weak_DES_key(des_block db)
{
int i;
for (i = 0; i < sizeof (weakDESkeys)/sizeof (struct DESkey); i++) {
if (weakDESkeys[i].h1 == db.key.high &&
weakDESkeys[i].h2 == db.key.low)
return (1);
}
return (0);
}