189690bcce
SRA does a Diffie-Hellmen exchange and then DES-encrypts the authentication data. If the authentication is successful, it also sets up a session key for DES encryption. SRA was originally developed at Texas A&M University. This code is probably export restricted (despite the fact that I originally found it at a University in Germany). SRA is not perfect. It is vulnerable to monkey-in-the-middle attacks and does not use tremendously large DH constants (and thus an individual exchange probably could be factored in a few days on modern CPU horsepower). It does not, however, require any changes in user or administrative behavior and foils session hijacking and sniffing. The goal of this commit is that telnet and telnetd end up in the DES distribution and that therefore an encrypted session telnet becomes standard issue for FreeBSD.
267 lines
5.7 KiB
C
267 lines
5.7 KiB
C
/* public key routines */
|
|
/* functions:
|
|
genkeys(char *public, char *secret)
|
|
common_key(char *secret, char *public, desData *deskey)
|
|
pk_encode(char *in, *out, DesData *deskey);
|
|
pk_decode(char *in, *out, DesData *deskey);
|
|
where
|
|
char public[HEXKEYBYTES + 1];
|
|
char secret[HEXKEYBYTES + 1];
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <sys/time.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <des.h>
|
|
#include "mp.h"
|
|
#include "pk.h"
|
|
#if defined(SOLARIS2) || defined(LINUX)
|
|
#include <stdlib.h>
|
|
#endif
|
|
|
|
/*
|
|
* Choose top 128 bits of the common key to use as our idea key.
|
|
*/
|
|
static
|
|
extractideakey(ck, ideakey)
|
|
MINT *ck;
|
|
IdeaData *ideakey;
|
|
{
|
|
MINT *a;
|
|
MINT *z;
|
|
short r;
|
|
int i;
|
|
short base = (1 << 8);
|
|
char *k;
|
|
|
|
z = itom(0);
|
|
a = itom(0);
|
|
madd(ck, z, a);
|
|
for (i = 0; i < ((KEYSIZE - 128) / 8); i++) {
|
|
sdiv(a, base, a, &r);
|
|
}
|
|
k = (char *)ideakey;
|
|
for (i = 0; i < 16; i++) {
|
|
sdiv(a, base, a, &r);
|
|
*k++ = r;
|
|
}
|
|
mfree(z);
|
|
mfree(a);
|
|
}
|
|
|
|
/*
|
|
* Choose middle 64 bits of the common key to use as our des key, possibly
|
|
* overwriting the lower order bits by setting parity.
|
|
*/
|
|
static
|
|
extractdeskey(ck, deskey)
|
|
MINT *ck;
|
|
DesData *deskey;
|
|
{
|
|
MINT *a;
|
|
MINT *z;
|
|
short r;
|
|
int i;
|
|
short base = (1 << 8);
|
|
char *k;
|
|
|
|
z = itom(0);
|
|
a = itom(0);
|
|
madd(ck, z, a);
|
|
for (i = 0; i < ((KEYSIZE - 64) / 2) / 8; i++) {
|
|
sdiv(a, base, a, &r);
|
|
}
|
|
k = (char *)deskey;
|
|
for (i = 0; i < 8; i++) {
|
|
sdiv(a, base, a, &r);
|
|
*k++ = r;
|
|
}
|
|
mfree(z);
|
|
mfree(a);
|
|
}
|
|
|
|
/*
|
|
* get common key from my secret key and his public key
|
|
*/
|
|
void common_key(char *xsecret, char *xpublic, IdeaData *ideakey, DesData *deskey)
|
|
{
|
|
MINT *public;
|
|
MINT *secret;
|
|
MINT *common;
|
|
MINT *modulus = xtom(HEXMODULUS);
|
|
|
|
public = xtom(xpublic);
|
|
secret = xtom(xsecret);
|
|
common = itom(0);
|
|
pow(public, secret, modulus, common);
|
|
extractdeskey(common, deskey);
|
|
extractideakey(common, ideakey);
|
|
#if DES_OSTHOLM
|
|
des_fixup_key_parity(deskey);
|
|
#else
|
|
des_set_odd_parity(deskey);
|
|
#endif
|
|
mfree(common);
|
|
mfree(secret);
|
|
mfree(public);
|
|
mfree(modulus);
|
|
}
|
|
|
|
|
|
/*
|
|
* Generate a seed
|
|
*/
|
|
void getseed(seed, seedsize)
|
|
char *seed;
|
|
int seedsize;
|
|
{
|
|
int i,f;
|
|
int rseed;
|
|
struct timeval tv;
|
|
long devrand;
|
|
|
|
(void)gettimeofday(&tv, (struct timezone *)NULL);
|
|
rseed = tv.tv_sec + tv.tv_usec;
|
|
/* XXX What the hell is this?! */
|
|
for (i = 0; i < 8; i++) {
|
|
rseed ^= (rseed << 8);
|
|
}
|
|
|
|
f=open("/dev/random",O_NONBLOCK|O_RDONLY);
|
|
if (f>=0)
|
|
{
|
|
read(f,&devrand,sizeof(devrand));
|
|
close(f);
|
|
}
|
|
srand48((long)rseed^devrand);
|
|
|
|
for (i = 0; i < seedsize; i++) {
|
|
seed[i] = (lrand48() & 0xff);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
* Generate a random public/secret key pair
|
|
*/
|
|
void genkeys(public, secret)
|
|
char *public;
|
|
char *secret;
|
|
{
|
|
int i;
|
|
|
|
# define BASEBITS (8*sizeof(short) - 1)
|
|
# define BASE (1 << BASEBITS)
|
|
|
|
MINT *pk = itom(0);
|
|
MINT *sk = itom(0);
|
|
MINT *tmp;
|
|
MINT *base = itom(BASE);
|
|
MINT *root = itom(PROOT);
|
|
MINT *modulus = xtom(HEXMODULUS);
|
|
short r;
|
|
unsigned short seed[KEYSIZE/BASEBITS + 1];
|
|
char *xkey;
|
|
|
|
getseed((char *)seed, sizeof(seed));
|
|
for (i = 0; i < KEYSIZE/BASEBITS + 1; i++) {
|
|
r = seed[i] % BASE;
|
|
tmp = itom(r);
|
|
mult(sk, base, sk);
|
|
madd(sk, tmp, sk);
|
|
mfree(tmp);
|
|
}
|
|
tmp = itom(0);
|
|
mdiv(sk, modulus, tmp, sk);
|
|
mfree(tmp);
|
|
pow(root, sk, modulus, pk);
|
|
xkey = mtox(sk);
|
|
adjust(secret, xkey);
|
|
xkey = mtox(pk);
|
|
adjust(public, xkey);
|
|
mfree(sk);
|
|
mfree(base);
|
|
mfree(pk);
|
|
mfree(root);
|
|
mfree(modulus);
|
|
}
|
|
|
|
/*
|
|
* Adjust the input key so that it is 0-filled on the left
|
|
*/
|
|
adjust(keyout, keyin)
|
|
char keyout[HEXKEYBYTES+1];
|
|
char *keyin;
|
|
{
|
|
char *p;
|
|
char *s;
|
|
|
|
for (p = keyin; *p; p++)
|
|
;
|
|
for (s = keyout + HEXKEYBYTES; p >= keyin; p--, s--) {
|
|
*s = *p;
|
|
}
|
|
while (s >= keyout) {
|
|
*s-- = '0';
|
|
}
|
|
}
|
|
|
|
static char hextab[17] = "0123456789ABCDEF";
|
|
|
|
/* given a DES key, cbc encrypt and translate input to terminated hex */
|
|
void pk_encode(in, out, key)
|
|
char *in,*out;
|
|
DesData *key;
|
|
{
|
|
char buf[256];
|
|
DesData i;
|
|
des_key_schedule k;
|
|
int l,op,deslen;
|
|
|
|
memset(&i,0,sizeof(i));
|
|
memset(buf,0,sizeof(buf));
|
|
deslen = ((strlen(in) + 7)/8)*8;
|
|
des_key_sched(key, k);
|
|
des_cbc_encrypt((des_cblock *)in,(des_cblock *)buf,deslen,
|
|
k,&i,DES_ENCRYPT);
|
|
for (l=0,op=0;l<deslen;l++) {
|
|
out[op++] = hextab[(buf[l] & 0xf0) >> 4];
|
|
out[op++] = hextab[(buf[l] & 0x0f)];
|
|
}
|
|
out[op] = '\0';
|
|
}
|
|
|
|
/* given a DES key, translate input from hex and decrypt */
|
|
void pk_decode(in, out, key)
|
|
char *in,*out;
|
|
DesData *key;
|
|
{
|
|
char buf[256];
|
|
DesData i;
|
|
des_key_schedule k;
|
|
int l,n1,n2,op;
|
|
|
|
memset(&i,0,sizeof(i));
|
|
memset(buf,0,sizeof(buf));
|
|
for (l=0,op=0;l<strlen(in)/2;l++,op+=2) {
|
|
if(in[op] == '0' && in[op+1] == '0') {
|
|
buf[l] = '\0';
|
|
break;
|
|
}
|
|
if (in[op] > '9')
|
|
n1 = in[op] - 'A' + 10;
|
|
else
|
|
n1 = in[op] - '0';
|
|
if (in[op+1] > '9')
|
|
n2 = in[op+1] - 'A' + 10;
|
|
else
|
|
n2 = in[op+1] - '0';
|
|
buf[l] = n1*16 +n2;
|
|
}
|
|
des_key_sched(key, k);
|
|
des_cbc_encrypt((des_cblock *)buf,(des_cblock *)out,strlen(in)/2,
|
|
k,&i,DES_DECRYPT);
|
|
out[strlen(in)/2] = '\0';
|
|
}
|