305 lines
11 KiB
C
305 lines
11 KiB
C
/*
|
|
NDS client for ncpfs
|
|
Copyright (C) 1997 Arne de Bruijn
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
Revision history:
|
|
|
|
0.00 1997 Arne de Bruijn
|
|
Initial release.
|
|
0.01 1997 Petr Vandrovec <vandrove@vc.cvut.cz>
|
|
Remove shuffle.
|
|
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include "ndscrypt.h"
|
|
#include <ncp/ncplib.h>
|
|
|
|
static unsigned int rol16(unsigned int i, int c) {
|
|
return ((i << c) & 65535) | ((unsigned int)(i & 65535) >> (16 - c));
|
|
}
|
|
static unsigned int ror16(unsigned int i, int c) {
|
|
return ((unsigned int)(i & 65535) >> c) | ((i << (16 - c)) & 65535);
|
|
}
|
|
|
|
static unsigned char nwcryptdata[256]={
|
|
0xD9,0x78,0xF9,0xC4,0x19,0xDD,0xB5,0xED,0x28,0xE9,0xFD,0x79,
|
|
0x4A,0xA0,0xD8,0x9D,0xC6,0x7E,0x37,0x83,0x2B,0x76,0x53,0x8E,
|
|
0x62,0x4C,0x64,0x88,0x44,0x8B,0xFB,0xA2,0x17,0x9A,0x59,0xF5,
|
|
0x87,0xB3,0x4F,0x13,0x61,0x45,0x6D,0x8D,0x09,0x81,0x7D,0x32,
|
|
0xBD,0x8F,0x40,0xEB,0x86,0xB7,0x7B,0x0B,0xF0,0x95,0x21,0x22,
|
|
0x5C,0x6B,0x4E,0x82,0x54,0xD6,0x65,0x93,0xCE,0x60,0xB2,0x1C,
|
|
0x73,0x56,0xC0,0x14,0xA7,0x8C,0xF1,0xDC,0x12,0x75,0xCA,0x1F,
|
|
0x3B,0xBE,0xE4,0xD1,0x42,0x3D,0xD4,0x30,0xA3,0x3C,0xB6,0x26,
|
|
0x6F,0xBF,0x0E,0xDA,0x46,0x69,0x07,0x57,0x27,0xF2,0x1D,0x9B,
|
|
0xBC,0x94,0x43,0x03,0xF8,0x11,0xC7,0xF6,0x90,0xEF,0x3E,0xE7,
|
|
0x06,0xC3,0xD5,0x2F,0xC8,0x66,0x1E,0xD7,0x08,0xE8,0xEA,0xDE,
|
|
0x80,0x52,0xEE,0xF7,0x84,0xAA,0x72,0xAC,0x35,0x4D,0x6A,0x2A,
|
|
0x96,0x1A,0xD2,0x71,0x5A,0x15,0x49,0x74,0x4B,0x9F,0xD0,0x5E,
|
|
0x04,0x18,0xA4,0xEC,0xC2,0xE0,0x41,0x6E,0x0F,0x51,0xCB,0xCC,
|
|
0x24,0x91,0xAF,0x50,0xA1,0xF4,0x70,0x39,0x99,0x7C,0x3A,0x85,
|
|
0x23,0xB8,0xB4,0x7A,0xFC,0x02,0x36,0x5B,0x25,0x55,0x97,0x31,
|
|
0x2D,0x5D,0xFA,0x98,0xE3,0x8A,0x92,0xAE,0x05,0xDF,0x29,0x10,
|
|
0x67,0x6C,0xBA,0xC9,0xD3,0x00,0xE6,0xCF,0xE1,0x9E,0xA8,0x2C,
|
|
0x63,0x16,0x01,0x3F,0x58,0xE2,0x89,0xA9,0x0D,0x38,0x34,0x1B,
|
|
0xAB,0x33,0xFF,0xB0,0xBB,0x48,0x0C,0x5F,0xB9,0xB1,0xCD,0x2E,
|
|
0xC5,0xF3,0xDB,0x47,0xE5,0xA5,0x9C,0x77,0x0A,0xA6,0x20,0x68,
|
|
0xFE,0x7F,0xC1,0xAD};
|
|
|
|
#if 0
|
|
static unsigned char shuffle_table[32]=
|
|
{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 unsigned char shuffle_table2[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};
|
|
#endif
|
|
|
|
static unsigned char nwhashdata[256] =
|
|
{0xBD,0x56,0xEA,0xF2,0xA2,0xF1,0xAC,0x2A,0xB0,0x93,0xD1,0x9C,
|
|
0x1B,0x33,0xFD,0xD0,0x30,0x04,0xB6,0xDC,0x7D,0xDF,0x32,0x4B,
|
|
0xF7,0xCB,0x45,0x9B,0x31,0xBB,0x21,0x5A,0x41,0x9F,0xE1,0xD9,
|
|
0x4A,0x4D,0x9E,0xDA,0xA0,0x68,0x2C,0xC3,0x27,0x5F,0x80,0x36,
|
|
0x3E,0xEE,0xFB,0x95,0x1A,0xFE,0xCE,0xA8,0x34,0xA9,0x13,0xF0,
|
|
0xA6,0x3F,0xD8,0x0C,0x78,0x24,0xAF,0x23,0x52,0xC1,0x67,0x17,
|
|
0xF5,0x66,0x90,0xE7,0xE8,0x07,0xB8,0x60,0x48,0xE6,0x1E,0x53,
|
|
0xF3,0x92,0xA4,0x72,0x8C,0x08,0x15,0x6E,0x86,0x00,0x84,0xFA,
|
|
0xF4,0x7F,0x8A,0x42,0x19,0xF6,0xDB,0xCD,0x14,0x8D,0x50,0x12,
|
|
0xBA,0x3C,0x06,0x4E,0xEC,0xB3,0x35,0x11,0xA1,0x88,0x8E,0x2B,
|
|
0x94,0x99,0xB7,0x71,0x74,0xD3,0xE4,0xBF,0x3A,0xDE,0x96,0x0E,
|
|
0xBC,0x0A,0xED,0x77,0xFC,0x37,0x6B,0x03,0x79,0x89,0x62,0xC6,
|
|
0xD7,0xC0,0xD2,0x7C,0x6A,0x8B,0x22,0xA3,0x5B,0x05,0x5D,0x02,
|
|
0x75,0xD5,0x61,0xE3,0x18,0x8F,0x55,0x51,0xAD,0x1F,0x0B,0x5E,
|
|
0x85,0xE5,0xC2,0x57,0x63,0xCA,0x3D,0x6C,0xB4,0xC5,0xCC,0x70,
|
|
0xB2,0x91,0x59,0x0D,0x47,0x20,0xC8,0x4F,0x58,0xE0,0x01,0xE2,
|
|
0x16,0x38,0xC4,0x6F,0x3B,0x0F,0x65,0x46,0xBE,0x7E,0x2D,0x7B,
|
|
0x82,0xF9,0x40,0xB5,0x1D,0x73,0xF8,0xEB,0x26,0xC7,0x87,0x97,
|
|
0x25,0x54,0xB1,0x28,0xAA,0x98,0x9D,0xA5,0x64,0x6D,0x7A,0xD4,
|
|
0x10,0x81,0x44,0xEF,0x49,0xD6,0xAE,0x2E,0xDD,0x76,0x5C,0x2F,
|
|
0xA7,0x1C,0xC9,0x09,0x69,0x9A,0x83,0xCF,0x29,0x39,0xB9,0xE9,
|
|
0x4C,0xFF,0x43,0xAB};
|
|
|
|
|
|
void nwencrypt(const unsigned short *cryptbuf, const unsigned char *in, unsigned char *out) {
|
|
int i, j;
|
|
register unsigned int i1, i2, i3, i4;
|
|
const unsigned short *p;
|
|
|
|
i1 = WVAL_LH(in, 0);
|
|
i2 = WVAL_LH(in, 2);
|
|
i3 = WVAL_LH(in, 4);
|
|
i4 = WVAL_LH(in, 6);
|
|
p = cryptbuf;
|
|
for (j = 3; j; j--) {
|
|
for (i = (j == 2) ? 6 : 5; i; i--) {
|
|
i1 = rol16(i1 + (*p++) + (i4 & i3) + (~i4 & i2), 1);
|
|
i2 = rol16(i2 + (*p++) + (i1 & i4) + (~i1 & i3), 2);
|
|
i3 = rol16(i3 + (*p++) + (i2 & i1) + (~i2 & i4), 3);
|
|
i4 = rol16(i4 + (*p++) + (i3 & i2) + (~i3 & i1), 5);
|
|
}
|
|
if (j > 1) {
|
|
i1 += cryptbuf[i4 & 63];
|
|
i2 += cryptbuf[i1 & 63];
|
|
i3 += cryptbuf[i2 & 63];
|
|
i4 += cryptbuf[i3 & 63];
|
|
}
|
|
}
|
|
WSET_LH(out, 0, i1);
|
|
WSET_LH(out, 2, i2);
|
|
WSET_LH(out, 4, i3);
|
|
WSET_LH(out, 6, i4);
|
|
}
|
|
|
|
void nwdecrypt(const unsigned short *cryptbuf, const unsigned char *in, unsigned char *out) {
|
|
int i, j;
|
|
const unsigned short *p;
|
|
register unsigned int i1, i2, i3, i4;
|
|
|
|
i1 = WVAL_LH(in, 0);
|
|
i2 = WVAL_LH(in, 2);
|
|
i3 = WVAL_LH(in, 4);
|
|
i4 = WVAL_LH(in, 6);
|
|
p = cryptbuf + 64;
|
|
for (j = 3; j; j--) {
|
|
for (i = (j == 2) ? 6 : 5; i; i--) {
|
|
i4 = ror16(i4, 5) - (~i3 & i1) - (i3 & i2) - (*--p);
|
|
i3 = ror16(i3, 3) - (~i2 & i4) - (i2 & i1) - (*--p);
|
|
i2 = ror16(i2, 2) - (~i1 & i3) - (i1 & i4) - (*--p);
|
|
i1 = ror16(i1, 1) - (~i4 & i2) - (i4 & i3) - (*--p);
|
|
}
|
|
if (j > 1) {
|
|
i4 -= cryptbuf[i3 & 63];
|
|
i3 -= cryptbuf[i2 & 63];
|
|
i2 -= cryptbuf[i1 & 63];
|
|
i1 -= cryptbuf[i4 & 63];
|
|
}
|
|
}
|
|
WSET_LH(out, 0, i1);
|
|
WSET_LH(out, 2, i2);
|
|
WSET_LH(out, 4, i3);
|
|
WSET_LH(out, 6, i4);
|
|
}
|
|
|
|
void nwcryptinit(unsigned short *scryptbuf, const unsigned char *key) {
|
|
int i;
|
|
unsigned char cryptbuf[128], *p;
|
|
|
|
memcpy(cryptbuf, key, 8);
|
|
for (i = 0; i < 120; i++)
|
|
cryptbuf[i + 8] =
|
|
nwcryptdata[(cryptbuf[i] + cryptbuf[i + 7]) & 255];
|
|
cryptbuf[128 - 8] = nwcryptdata[cryptbuf[128 - 8]];
|
|
for (i = 127 - 8; i >= 0; i--)
|
|
cryptbuf[i] = nwcryptdata[cryptbuf[i + 1] ^ cryptbuf[i + 8]];
|
|
for (i = 0, p = cryptbuf; i < 64; i++, p += 2)
|
|
scryptbuf[i] = (*p) | (*(p+1)) << 8;
|
|
}
|
|
|
|
void nwencryptblock(const unsigned char *cryptkey, const unsigned char *buf, int buflen,
|
|
unsigned char *outbuf) {
|
|
int i;
|
|
unsigned char nhash[8];
|
|
unsigned short cryptbuf[64];
|
|
|
|
nwcryptinit(cryptbuf, cryptkey);
|
|
memset(nhash, 0, 8);
|
|
while (buflen >= 8) {
|
|
for (i = 0; i < 8; i++, buf++)
|
|
nhash[i] ^= *buf;
|
|
nwencrypt(cryptbuf, nhash, nhash);
|
|
memcpy(outbuf, nhash, 8);
|
|
outbuf += 8;
|
|
buflen -= 8;
|
|
}
|
|
memset(cryptbuf, 0, sizeof(cryptbuf));
|
|
}
|
|
|
|
void nwdecryptblock(const unsigned char *cryptkey, const unsigned char *buf, int buflen,
|
|
unsigned char *outbuf) {
|
|
int i;
|
|
unsigned char nhash[16], *p;
|
|
unsigned short cryptbuf[64];
|
|
|
|
nwcryptinit(cryptbuf, cryptkey);
|
|
memset(nhash, 0, 16);
|
|
p = nhash;
|
|
while (buflen >= 8) {
|
|
memcpy(p, buf, 8);
|
|
p = nhash + 8 - (p - nhash);
|
|
nwdecrypt(cryptbuf, buf, outbuf);
|
|
for (i = 0; i < 8; i++, outbuf++)
|
|
*outbuf ^= p[i];
|
|
buf += 8;
|
|
buflen -= 8;
|
|
}
|
|
memset(cryptbuf, 0, sizeof(cryptbuf));
|
|
}
|
|
|
|
void nwhash1(unsigned char *hash, int hashlen, const unsigned char *data, int datalen) {
|
|
unsigned char *hp, *hp1, *hend, c;
|
|
const unsigned char *dp;
|
|
|
|
hp1 = (hp = hash) + 1;
|
|
hend = hp + hashlen;
|
|
dp = data;
|
|
while (datalen--) {
|
|
*hp = nwhashdata[*hp1 ^ *hp] ^ *dp++;
|
|
hp = hp1++;
|
|
if (hp1 == hend)
|
|
hp1 = hash;
|
|
}
|
|
while (hp-- > hash) {
|
|
hp1 = hash;
|
|
c = *hp1++;
|
|
while (*(hp1 - 1) = *hp1, ++hp1 < hash + hashlen);
|
|
*(hp1 - 1) = c;
|
|
}
|
|
}
|
|
|
|
void nwhash2(unsigned char *hashbuf, unsigned char c) {
|
|
int i, j;
|
|
unsigned char *p = hashbuf + hashbuf[0x40];
|
|
|
|
p[0x20] = p[0x00] ^ (p[0x10] = c);
|
|
hashbuf[0x41] = (p[0x30] ^= nwhashdata[(unsigned char)(c ^ hashbuf[0x41])]);
|
|
if (!(hashbuf[0x40] = (hashbuf[0x40] + 1) & 15)) {
|
|
c = 0;
|
|
for (i = 18; i; i--)
|
|
for (j = 48, p = hashbuf; j; j--)
|
|
c = (*(p++) ^= nwhashdata[((unsigned char)c + j) & 255]);
|
|
}
|
|
}
|
|
|
|
void nwhash2block(unsigned char *hashbuf, const unsigned char *data, size_t datalen) {
|
|
while (datalen--)
|
|
nwhash2(hashbuf, *data++);
|
|
}
|
|
|
|
void nwhash2end(unsigned char *hashbuf) {
|
|
int i, j;
|
|
|
|
for(j = i = 16 - hashbuf[0x40]; j; j--)
|
|
nwhash2(hashbuf, i);
|
|
for(i = 0x30; i < 0x40; i++)
|
|
nwhash2(hashbuf, hashbuf[i]);
|
|
}
|
|
|
|
#if 0
|
|
void shuffle(const char *objid, const char *pwd, char *out) {
|
|
unsigned char temp[32];
|
|
int i, j, k;
|
|
i = strlen(pwd);
|
|
memset(temp, 0, 32);
|
|
for (j = 0; j < i; j++)
|
|
temp[j & 31] ^= pwd[j];
|
|
if (i)
|
|
for (j = i; j < 32; j += i) {
|
|
temp[j++] = shuffle_table[j];
|
|
k = 32 - j;
|
|
memcpy(temp + j, pwd, (k > i) ? i : k);
|
|
}
|
|
for (i = 0; i < 32; i++)
|
|
temp[i] ^= objid[i & 3];
|
|
j = 0;
|
|
for (k = 0; k < 2; k++)
|
|
for (i = 0; i < 32; i++)
|
|
(char)j += temp[i] = (temp[i] + j) ^
|
|
(temp[(i + j) & 31] - shuffle_table[i]);
|
|
for (i = 0; i < 16; i++)
|
|
out[i] = shuffle_table2[temp[i * 2]] |
|
|
(shuffle_table2[temp[i * 2 + 1]] << 4);
|
|
}
|
|
#endif
|
|
|