345 lines
10 KiB
C
345 lines
10 KiB
C
/*$*********************************************************
|
|
$*
|
|
$* This code has been taken from DDJ 11/93, from an
|
|
$* article by Pawel Szczerbina.
|
|
$*
|
|
$* Password encryption routines follow.
|
|
$* Converted to C from Barry Nance's Pascal
|
|
$* prog published in the March -93 issue of Byte.
|
|
$*
|
|
$* Adapted to be useable for ncpfs by
|
|
$* Volker Lendecke <lendecke@namu01.gwdg.de> in
|
|
$* October 1995.
|
|
$*
|
|
$********************************************************* */
|
|
|
|
/****************************************************************************
|
|
|
|
I read that Novell is not very open when it comes to technical details
|
|
of the Netware Core Protocol. This might be especially true for the
|
|
encryption stuff. I took the necessary code from Dr. Dobb's Journal
|
|
11/93, Undocumented Corner. I asked Jon Erickson <jon@ddj.com> about
|
|
the legal status of this piece of code:
|
|
|
|
|
|
---
|
|
Date: Thu, 12 Oct 1995 13:44:18 +0100
|
|
From: Volker Lendecke <lendecke>
|
|
To: jon@ddj.com
|
|
Subject: legal status of your source code?
|
|
|
|
|
|
Hello!
|
|
|
|
I hope that you're the right one to write to, you are the first on your WWW
|
|
server. If you are not, could you please forward this message to the right
|
|
person? Thanks.
|
|
|
|
I'm currently exploring the possibility to write a free (in the GNU GPL
|
|
sense) NCP filesystem, which would allow me to access a novell server
|
|
transparently. For that I would like to use the encryption functions you
|
|
published in DDJ 11/93, Undocumented Corner. I would make some cosmetic
|
|
changes, such as other indentations, minor code changes and so on. But I do
|
|
not know if that allows me to publish this code under GPL. One alternative
|
|
would be to publish a diff against your listing, but that would probably
|
|
contain much of your code as well, and it would be very inconvenient for
|
|
the average user.
|
|
|
|
I think that you have some kind of standard procedure for such a
|
|
case. Please tell me what I should do.
|
|
|
|
Many thanks in advance,
|
|
|
|
Volker
|
|
|
|
+=================================================================+
|
|
! Volker Lendecke Internet: lendecke@namu01.gwdg.de !
|
|
! D-37081 Goettingen, Germany !
|
|
+=================================================================+
|
|
|
|
--
|
|
|
|
|
|
I got the following answer:
|
|
|
|
---
|
|
From: Jon Erickson <jon@ddj.com>
|
|
X-Mailer: SCO System V Mail (version 3.2)
|
|
To: lendecke@namu01.gwdg.de
|
|
Subject: Re: legal status of your source code?
|
|
Date: Thu, 12 Oct 95 5:42:56 PDT
|
|
|
|
Volker,
|
|
Code from Dr. Dobb's Journal related articles is provided for
|
|
anyone to use. Clearly, the author of the article should be
|
|
given credit.
|
|
Jon Erickson
|
|
|
|
---
|
|
|
|
With this answer in mind, I took the code and made it a bit more
|
|
C-like. The original seemed to be translated by a mechanical pascal->c
|
|
translator. Jon's answer encouraged me to publish nwcrypt.c under the
|
|
GPL. If anybody who knows more about copyright and sees any problems
|
|
with this, please tell me.
|
|
****************************************************************************/
|
|
|
|
#include <string.h>
|
|
/******************* Data types ***************************/
|
|
typedef unsigned char buf32[32];
|
|
typedef unsigned char buf16[16];
|
|
typedef unsigned char buf8[8];
|
|
typedef unsigned char buf4[4];
|
|
|
|
static unsigned char encrypttable[256] =
|
|
{0x7, 0x8, 0x0, 0x8, 0x6, 0x4, 0xE, 0x4, 0x5, 0xC, 0x1, 0x7, 0xB, 0xF, 0xA, 0x8,
|
|
0xF, 0x8, 0xC, 0xC, 0x9, 0x4, 0x1, 0xE, 0x4, 0x6, 0x2, 0x4, 0x0, 0xA, 0xB, 0x9,
|
|
0x2, 0xF, 0xB, 0x1, 0xD, 0x2, 0x1, 0x9, 0x5, 0xE, 0x7, 0x0, 0x0, 0x2, 0x6, 0x6,
|
|
0x0, 0x7, 0x3, 0x8, 0x2, 0x9, 0x3, 0xF, 0x7, 0xF, 0xC, 0xF, 0x6, 0x4, 0xA, 0x0,
|
|
0x2, 0x3, 0xA, 0xB, 0xD, 0x8, 0x3, 0xA, 0x1, 0x7, 0xC, 0xF, 0x1, 0x8, 0x9, 0xD,
|
|
0x9, 0x1, 0x9, 0x4, 0xE, 0x4, 0xC, 0x5, 0x5, 0xC, 0x8, 0xB, 0x2, 0x3, 0x9, 0xE,
|
|
0x7, 0x7, 0x6, 0x9, 0xE, 0xF, 0xC, 0x8, 0xD, 0x1, 0xA, 0x6, 0xE, 0xD, 0x0, 0x7,
|
|
0x7, 0xA, 0x0, 0x1, 0xF, 0x5, 0x4, 0xB, 0x7, 0xB, 0xE, 0xC, 0x9, 0x5, 0xD, 0x1,
|
|
0xB, 0xD, 0x1, 0x3, 0x5, 0xD, 0xE, 0x6, 0x3, 0x0, 0xB, 0xB, 0xF, 0x3, 0x6, 0x4,
|
|
0x9, 0xD, 0xA, 0x3, 0x1, 0x4, 0x9, 0x4, 0x8, 0x3, 0xB, 0xE, 0x5, 0x0, 0x5, 0x2,
|
|
0xC, 0xB, 0xD, 0x5, 0xD, 0x5, 0xD, 0x2, 0xD, 0x9, 0xA, 0xC, 0xA, 0x0, 0xB, 0x3,
|
|
0x5, 0x3, 0x6, 0x9, 0x5, 0x1, 0xE, 0xE, 0x0, 0xE, 0x8, 0x2, 0xD, 0x2, 0x2, 0x0,
|
|
0x4, 0xF, 0x8, 0x5, 0x9, 0x6, 0x8, 0x6, 0xB, 0xA, 0xB, 0xF, 0x0, 0x7, 0x2, 0x8,
|
|
0xC, 0x7, 0x3, 0xA, 0x1, 0x4, 0x2, 0x5, 0xF, 0x7, 0xA, 0xC, 0xE, 0x5, 0x9, 0x3,
|
|
0xE, 0x7, 0x1, 0x2, 0xE, 0x1, 0xF, 0x4, 0xA, 0x6, 0xC, 0x6, 0xF, 0x4, 0x3, 0x0,
|
|
0xC, 0x0, 0x3, 0x6, 0xF, 0x8, 0x7, 0xB, 0x2, 0xD, 0xC, 0x6, 0xA, 0xA, 0x8, 0xD};
|
|
|
|
static buf32 encryptkeys =
|
|
{0x48, 0x93, 0x46, 0x67, 0x98, 0x3D, 0xE6, 0x8D,
|
|
0xB7, 0x10, 0x7A, 0x26, 0x5A, 0xB9, 0xB1, 0x35,
|
|
0x6B, 0x0F, 0xD5, 0x70, 0xAE, 0xFB, 0xAD, 0x11,
|
|
0xF4, 0x47, 0xDC, 0xA7, 0xEC, 0xCF, 0x50, 0xC0};
|
|
|
|
|
|
static void
|
|
shuffle1(buf32 temp, unsigned char *target)
|
|
{
|
|
short b4;
|
|
unsigned char b3;
|
|
int s, b2, i;
|
|
|
|
b4 = 0;
|
|
|
|
for (b2 = 0; b2 <= 1; ++b2)
|
|
{
|
|
for (s = 0; s <= 31; ++s)
|
|
{
|
|
b3 = (temp[s] + b4) ^ (temp[(s + b4) & 31] - encryptkeys[s]);
|
|
b4 = b4 + b3;
|
|
temp[s] = b3;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i <= 15; ++i)
|
|
{
|
|
target[i] = encrypttable[temp[2 * i]]
|
|
| (encrypttable[temp[2 * i + 1]] << 4);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
shuffle(const unsigned char *lon, const unsigned char *buf, int buflen,
|
|
unsigned char *target)
|
|
{
|
|
int b2, d, s;
|
|
buf32 temp;
|
|
|
|
while ((buflen > 0)
|
|
&& (buf[buflen - 1] == 0))
|
|
{
|
|
buflen = buflen - 1;
|
|
}
|
|
|
|
for (s = 0; s < 32; s++)
|
|
{
|
|
temp[s] = 0;
|
|
}
|
|
|
|
d = 0;
|
|
while (buflen >= 32)
|
|
{
|
|
for (s = 0; s <= 31; ++s)
|
|
{
|
|
temp[s] = temp[s] ^ buf[d];
|
|
d = d + 1;
|
|
}
|
|
buflen = buflen - 32;
|
|
}
|
|
b2 = d;
|
|
if (buflen > 0)
|
|
{
|
|
for (s = 0; s <= 31; ++s)
|
|
{
|
|
if (d + buflen == b2)
|
|
{
|
|
b2 = d;
|
|
temp[s] = temp[s] ^ encryptkeys[s];
|
|
} else
|
|
{
|
|
temp[s] = temp[s] ^ buf[b2];
|
|
b2 = b2 + 1;
|
|
}
|
|
}
|
|
}
|
|
for (s = 0; s <= 31; ++s)
|
|
temp[s] = temp[s] ^ lon[s & 3];
|
|
|
|
shuffle1(temp, target);
|
|
}
|
|
|
|
|
|
static void
|
|
nw_encrypt(const unsigned char *fra,
|
|
const unsigned char *buf,
|
|
unsigned char *til)
|
|
{
|
|
buf32 k;
|
|
int s;
|
|
|
|
shuffle(&(fra[0]), buf, 16, &(k[0]));
|
|
shuffle(&(fra[4]), buf, 16, &(k[16]));
|
|
|
|
for (s = 0; s <= 15; ++s)
|
|
k[s] = k[s] ^ k[31 - s];
|
|
|
|
for (s = 0; s <= 7; ++s)
|
|
til[s] = k[s] ^ k[15 - s];
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* */
|
|
/* The following code was contributed by */
|
|
/* Guntram Blohm <gbl%th7csun1@str.daimler-benz.com> */
|
|
/* */
|
|
/*****************************************************************************/
|
|
|
|
/* server side (mars etc.) should:
|
|
* store the *encrypted* password internally (output from shuffle)
|
|
* verify if nw_encrypt(cryptkey from GetCryptKey, old stored password)
|
|
== cryptkey in EncryptedChangePassword request buffer (this means
|
|
old password was correct)
|
|
* decrypt new password in request buffer using (yet to write) inverse of
|
|
newpassencrypt with old stored password as parameter
|
|
* compute the length of the unencrypted new password as len ^ (first byte of
|
|
old internal password) ^ (second byte of old internal password)
|
|
*/
|
|
|
|
static char
|
|
newshuffle[256 + 16] =
|
|
{
|
|
0x0f, 0x08, 0x05, 0x07, 0x0c, 0x02, 0x0e, 0x09,
|
|
0x00, 0x01, 0x06, 0x0d, 0x03, 0x04, 0x0b, 0x0a,
|
|
0x02, 0x0c, 0x0e, 0x06, 0x0f, 0x00, 0x01, 0x08,
|
|
0x0d, 0x03, 0x0a, 0x04, 0x09, 0x0b, 0x05, 0x07,
|
|
|
|
0x05, 0x02, 0x09, 0x0f, 0x0c, 0x04, 0x0d, 0x00,
|
|
0x0e, 0x0a, 0x06, 0x08, 0x0b, 0x01, 0x03, 0x07,
|
|
0x0f, 0x0d, 0x02, 0x06, 0x07, 0x08, 0x05, 0x09,
|
|
0x00, 0x04, 0x0c, 0x03, 0x01, 0x0a, 0x0b, 0x0e,
|
|
|
|
0x05, 0x0e, 0x02, 0x0b, 0x0d, 0x0a, 0x07, 0x00,
|
|
0x08, 0x06, 0x04, 0x01, 0x0f, 0x0c, 0x03, 0x09,
|
|
0x08, 0x02, 0x0f, 0x0a, 0x05, 0x09, 0x06, 0x0c,
|
|
0x00, 0x0b, 0x01, 0x0d, 0x07, 0x03, 0x04, 0x0e,
|
|
|
|
0x0e, 0x08, 0x00, 0x09, 0x04, 0x0b, 0x02, 0x07,
|
|
0x0c, 0x03, 0x0a, 0x05, 0x0d, 0x01, 0x06, 0x0f,
|
|
0x01, 0x04, 0x08, 0x0a, 0x0d, 0x0b, 0x07, 0x0e,
|
|
0x05, 0x0f, 0x03, 0x09, 0x00, 0x02, 0x06, 0x0c,
|
|
|
|
0x05, 0x03, 0x0c, 0x08, 0x0b, 0x02, 0x0e, 0x0a,
|
|
0x04, 0x01, 0x0d, 0x00, 0x06, 0x07, 0x0f, 0x09,
|
|
0x06, 0x00, 0x0b, 0x0e, 0x0d, 0x04, 0x0c, 0x0f,
|
|
0x07, 0x02, 0x08, 0x0a, 0x01, 0x05, 0x03, 0x09,
|
|
|
|
0x0b, 0x05, 0x0a, 0x0e, 0x0f, 0x01, 0x0c, 0x00,
|
|
0x06, 0x04, 0x02, 0x09, 0x03, 0x0d, 0x07, 0x08,
|
|
0x07, 0x02, 0x0a, 0x00, 0x0e, 0x08, 0x0f, 0x04,
|
|
0x0c, 0x0b, 0x09, 0x01, 0x05, 0x0d, 0x03, 0x06,
|
|
|
|
0x07, 0x04, 0x0f, 0x09, 0x05, 0x01, 0x0c, 0x0b,
|
|
0x00, 0x03, 0x08, 0x0e, 0x02, 0x0a, 0x06, 0x0d,
|
|
0x09, 0x04, 0x08, 0x00, 0x0a, 0x03, 0x01, 0x0c,
|
|
0x05, 0x0f, 0x07, 0x02, 0x0b, 0x0e, 0x06, 0x0d,
|
|
|
|
0x09, 0x05, 0x04, 0x07, 0x0e, 0x08, 0x03, 0x01,
|
|
0x0d, 0x0b, 0x0c, 0x02, 0x00, 0x0f, 0x06, 0x0a,
|
|
0x09, 0x0a, 0x0b, 0x0d, 0x05, 0x03, 0x0f, 0x00,
|
|
0x01, 0x0c, 0x08, 0x07, 0x06, 0x04, 0x0e, 0x02,
|
|
|
|
0x03, 0x0e, 0x0f, 0x02, 0x0d, 0x0c, 0x04, 0x05,
|
|
0x09, 0x06, 0x00, 0x01, 0x0b, 0x07, 0x0a, 0x08,
|
|
};
|
|
|
|
/*
|
|
* verschluesseln des neuen Passworts fuer keyed change password
|
|
* Verwendung:
|
|
* - Shuffle (aus nwcrypt.c) altes passwort nach old (16 bytes)
|
|
* - shuffle neues passwort nach new (16 bytes)
|
|
* - nwpassencrypt (diese Funktion) zweimal aufrufen fuer je 8 bytes:
|
|
* nwpassencrypt(old+0, new+0, out+0)
|
|
* nwpassencrypt(old+8, new+8, out+8)
|
|
* - NCP-Buffer aufbauen:
|
|
* 2 byte Laenge im Hi-Lo-Format
|
|
* 1 byte Funktion (0x4b)
|
|
* 8 byte (nwcrypt Ergebnis analog login/verify password)
|
|
* 2 byte Objecttype
|
|
* 1 byte Objectname-Laenge
|
|
* n byte Objectname
|
|
* 1 byte (Laenge des eingegebenen neuen Passworts ^ old[0] ^ old[1])&0x7f|0x40
|
|
* 16 byte (Ergebnis dieser Funktion doppelt aufgerufen, s.o.)
|
|
*/
|
|
|
|
/*
|
|
* Encrypt the new password for keyed change password
|
|
* For info on how to use this function, look at ncp_change_login_passwd
|
|
* in ncplib.c.
|
|
*/
|
|
|
|
static void
|
|
newpassencrypt(char *old, char *new, char *out)
|
|
{
|
|
char *p, *bx;
|
|
char copy[8];
|
|
int i, di, ax;
|
|
char cl, dl, ch;
|
|
|
|
memcpy(copy, new, 8);
|
|
|
|
for (i = 0; i < 16; i++)
|
|
{
|
|
for (di = 0, ax = 0, p = old; di < 8; di++, ax += 0x20, p++)
|
|
{
|
|
cl = newshuffle[(((copy[di] ^ *p) >> 4) & 0x0f) + ax + 0x10] << 4;
|
|
dl = newshuffle[((copy[di] ^ *p) & 0xf) + ax];
|
|
copy[di] = cl | dl;
|
|
}
|
|
|
|
ch = old[7];
|
|
for (bx = old + 7; bx > old; bx--)
|
|
{
|
|
*bx = ((bx[-1] >> 4) & 0x0f) | ((*bx) << 4);
|
|
}
|
|
*old = ((ch >> 4) & 0x0f) | (*old) << 4;
|
|
|
|
memset(out, '\0', 8);
|
|
|
|
for (di = 0; di < 16; di++)
|
|
{
|
|
if (newshuffle[di + 0x100] & 1)
|
|
ch = ((copy[newshuffle[di + 0x100] / 2] >> 4) & 0x0f);
|
|
else
|
|
ch = copy[newshuffle[di + 0x100] / 2] & 0x0f;
|
|
out[di / 2] |= ((di & 1) ? ch << 4 : ch);
|
|
}
|
|
memcpy(copy, out, 8);
|
|
}
|
|
}
|
|
|