#include <sys/cdefs.h>
__RCSID("$NetBSD: skeysubr.c,v 1.29 2023/01/17 14:13:48 msaitoh Exp $");
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <termios.h>
#include <md4.h>
#include <md5.h>
#include <sys/rmd160.h>
#include <sha1.h>
#include "skey.h"
#ifndef SKEY_HASH_DEFAULT
#define SKEY_HASH_DEFAULT 0
#endif
static void f_md4(char *);
static void f_md5(char *);
static void f_sha1(char *);
static int keycrunch_md4(char *, const char *, const char *);
static int keycrunch_md5(char *, const char *, const char *);
static int keycrunch_sha1(char *, const char *, const char *);
static void lowcase(char *);
static void skey_echo(int);
static void trapped(int) __dead;
static char *mkSeedPassword(const char *, const char *, size_t *);
static int skey_hash_type = SKEY_HASH_DEFAULT;
struct skey_algorithm_table {
const char *name;
int (*keycrunch)(char *, const char *, const char *);
void (*f)(char *);
};
static struct skey_algorithm_table skey_algorithm_table[] = {
{ "md4", keycrunch_md4, f_md4 },
{ "md5", keycrunch_md5, f_md5 },
{ "sha1", keycrunch_sha1, f_sha1 },
#if 0
{ "rmd160", keycrunch_rmd160, f_rmd160 },
#endif
{ NULL, NULL, NULL }
};
int keycrunch(char *result,
const char *seed,
const char *passwd)
{
return(skey_algorithm_table[skey_hash_type].keycrunch(result, seed, passwd));
}
static char *mkSeedPassword(const char *seed, const char *passwd,
size_t *buflen)
{
char *buf;
*buflen = strlen(seed) + strlen(passwd);
if ((buf = (char *) malloc(*buflen + 1)) == NULL)
return NULL;
strcpy(buf, seed);
lowcase(buf);
strcat(buf, passwd);
sevenbit(buf);
return buf;
}
static int keycrunch_md4(char *result,
const char *seed,
const char *passwd)
{
char *buf;
MD4_CTX md;
size_t buflen;
u_int32_t results[4];
if ((buf = mkSeedPassword(seed, passwd, &buflen)) == NULL)
return -1;
MD4Init(&md);
MD4Update(&md, (unsigned char *) buf, buflen);
MD4Final((unsigned char *) (void *) results, &md);
free(buf);
results[0] ^= results[2];
results[1] ^= results[3];
(void)memcpy(result, results, SKEY_BINKEY_SIZE);
return 0;
}
static int keycrunch_md5(char *result,
const char *seed,
const char *passwd)
{
char *buf;
MD5_CTX md;
u_int32_t results[4];
size_t buflen;
if ((buf = mkSeedPassword(seed, passwd, &buflen)) == NULL)
return -1;
MD5Init(&md);
MD5Update(&md, (unsigned char *)buf, buflen);
MD5Final((unsigned char *) (void *)results, &md);
free(buf);
results[0] ^= results[2];
results[1] ^= results[3];
(void)memcpy((void *)result, (void *)results, SKEY_BINKEY_SIZE);
return(0);
}
static int keycrunch_sha1(char *result,
const char *seed,
const char *passwd)
{
char *buf;
SHA1_CTX sha;
size_t buflen;
int i, j;
if ((buf = mkSeedPassword(seed, passwd, &buflen)) == NULL)
return -1;
SHA1Init(&sha);
SHA1Update(&sha, (unsigned char *)buf, buflen);
SHA1Final(NULL, &sha);
free(buf);
sha.state[0] ^= sha.state[2];
sha.state[1] ^= sha.state[3];
sha.state[0] ^= sha.state[4];
for(i=j=0; j<8; i++, j+=4) {
result[j] = (unsigned char)(sha.state[i] & 0xff);
result[j+1] = (unsigned char)((sha.state[i] >> 8) & 0xff);
result[j+2] = (unsigned char)((sha.state[i] >> 16) & 0xff);
result[j+3] = (unsigned char)((sha.state[i] >> 24) & 0xff);
}
return(0);
}
#if 0
static int keycrunch_rmd160(char *result,
const char *seed,
const char *passwd)
{
char *buf;
RMD160_CTX rmd;
u_int32_t results[5];
size_t buflen;
if ((buf = mkSeedPassword(seed, passwd, &buflen)) == NULL)
return -1;
RMD160Init(&rmd);
RMD160Update(&rmd, (unsigned char *)buf, buflen);
RMD160Final((unsigned char *)(void *)results, &rmd);
free(buf);
results[0] ^= results[2];
results[1] ^= results[3];
results[0] ^= results[4];
(void)memcpy((void *)result, (void *)results, SKEY_BINKEY_SIZE);
return(0);
}
#endif
void f(char *x)
{
skey_algorithm_table[skey_hash_type].f(x);
}
static void f_md4(char *x)
{
MD4_CTX md;
u_int32_t results[4];
MD4Init(&md);
MD4Update(&md, (unsigned char *) x, SKEY_BINKEY_SIZE);
MD4Final((unsigned char *) (void *) results, &md);
results[0] ^= results[2];
results[1] ^= results[3];
(void)memcpy(x, results, SKEY_BINKEY_SIZE);
}
static void f_md5(char *x)
{
MD5_CTX md;
u_int32_t results[4];
MD5Init(&md);
MD5Update(&md, (unsigned char *)x, SKEY_BINKEY_SIZE);
MD5Final((unsigned char *) (void *)results, &md);
results[0] ^= results[2];
results[1] ^= results[3];
(void)memcpy((void *)x, (void *)results, SKEY_BINKEY_SIZE);
}
static void f_sha1(char *x)
{
SHA1_CTX sha;
int i, j;
SHA1Init(&sha);
SHA1Update(&sha, (unsigned char *)x, SKEY_BINKEY_SIZE);
SHA1Final(NULL, &sha);
sha.state[0] ^= sha.state[2];
sha.state[1] ^= sha.state[3];
sha.state[0] ^= sha.state[4];
for(i=j=0; j<8; i++, j+=4) {
x[j] = (unsigned char)(sha.state[i] & 0xff);
x[j+1] = (unsigned char)((sha.state[i] >> 8) & 0xff);
x[j+2] = (unsigned char)((sha.state[i] >> 16) & 0xff);
x[j+3] = (unsigned char)((sha.state[i] >> 24) & 0xff);
}
}
#if 0
static void f_rmd160(char *x)
{
RMD160_CTX rmd;
u_int32_t results[5];
RMD160Init(&rmd);
RMD160Update(&rmd, (unsigned char *)x, SKEY_BINKEY_SIZE);
RMD160Final((unsigned char *)(void *)results, &rmd);
results[0] ^= results[2];
results[1] ^= results[3];
results[0] ^= results[4];
(void)memcpy((void *)x, (void *)results, SKEY_BINKEY_SIZE);
}
#endif
void rip(char *buf)
{
buf += strcspn(buf, "\r\n");
if (*buf)
*buf = '\0';
}
char *readpass(char *buf, int n)
{
void *old_handler;
skey_echo(0);
old_handler = signal(SIGINT, trapped);
fgets(buf, n, stdin);
rip(buf);
putc('\n', stderr);
fflush(stderr);
if (old_handler != SIG_ERR)
(void)signal(SIGINT, old_handler);
skey_echo(1);
sevenbit(buf);
return buf;
}
char *readskey(char *buf, int n)
{
fgets(buf, n, stdin);
rip(buf);
sevenbit (buf);
return buf;
}
static void trapped(int sig)
{
fputs("^C\n", stderr);
fflush(stderr);
skey_echo(1);
exit(1);
}
int atob8(char *out, const char *in)
{
int i;
int val;
if (in == NULL || out == NULL)
return -1;
for (i=0; i<8; i++) {
if ((in = skipspace(in)) == NULL)
return -1;
if ((val = htoi(*in++)) == -1)
return -1;
*out = val << 4;
if ((in = skipspace(in)) == NULL)
return -1;
if ((val = htoi(*in++)) == -1)
return -1;
*out++ |= val;
}
return 0;
}
int btoa8(char *out, const char *in)
{
int i;
if (in == NULL || out == NULL)
return -1;
for (i=0;i<8;i++) {
sprintf(out, "%02x", *in++ & 0xff);
out += 2;
}
return 0;
}
int htoi(int c)
{
if ('0' <= c && c <= '9')
return c - '0';
if ('a' <= c && c <= 'f')
return 10 + c - 'a';
if ('A' <= c && c <= 'F')
return 10 + c - 'A';
return -1;
}
const char *skipspace(const char *cp)
{
while (*cp == ' ' || *cp == '\t')
cp++;
if (*cp == '\0')
return NULL;
else
return cp;
}
void backspace(char *buf)
{
char bs = 0x8;
char *cp = buf;
char *out = buf;
while (*cp) {
if (*cp == bs) {
if (out == buf) {
cp++;
continue;
} else {
cp++;
out--;
}
} else {
*out++ = *cp++;
}
}
*out = '\0';
}
void sevenbit(char *s)
{
while (*s)
*s++ &= 0x7f;
}
const char *skey_set_algorithm(const char *new)
{
int i;
for (i = 0; skey_algorithm_table[i].name; i++) {
if (strcmp(new, skey_algorithm_table[i].name) == 0) {
skey_hash_type = i;
return(new);
}
}
return(NULL);
}
const char *skey_get_algorithm(void)
{
return(skey_algorithm_table[skey_hash_type].name);
}
static void skey_echo(int action)
{
static struct termios term;
static int echo = 0;
if (action == 0) {
(void) tcgetattr(fileno(stdin), &term);
if ((echo = (term.c_lflag & ECHO)) != 0) {
term.c_lflag &= ~ECHO;
(void) tcsetattr(fileno(stdin), TCSAFLUSH|TCSASOFT, &term);
}
} else if (action && echo) {
term.c_lflag |= ECHO;
(void) tcsetattr(fileno(stdin), TCSAFLUSH|TCSASOFT, &term);
echo = 0;
}
}
static void lowcase(char *s)
{
u_char *p;
for (p = (u_char *) s; *p; p++)
if (isupper(*p))
*p = tolower(*p);
}