Plan 9 from Bell Labs’s /usr/web/sources/contrib/steve/root/sys/src/cmd/aux/ncpfs/nwcrypt.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#include <u.h>
#include <libc.h>
#include "ncp.h"

/*$*********************************************************
   $*
   $* 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.
****************************************************************************/

/******************* Data types ***************************/
typedef u8int buf32[32];
typedef u8int buf16[16];
typedef u8int buf8[8];
typedef u8int buf4[4];

static u8int 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, u8int *target)
{
	u16int b4;
	u8int 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(u8int *lon, u8int *buf, int buflen, u8int *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++, d++)
			temp[s] = temp[s] ^ buf[d];
		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);
}


void
nw_encrypt(u8int *fra, u8int *buf, u8int *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[NWKEYLEN];
	int i, di, ax;
	char cl, dl, ch;

	memcpy(copy, new, NWKEYLEN);

	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, NWKEYLEN);
	}
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.