/* 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 Remove shuffle. */ #include #include "ndscrypt.h" #include 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