/*
Folio 4.x hash algorithm
(C) 2000-2001 Paul Janssens - All rights reserved
nfohash checks the integrity of folio 4.x .nfo, .sdw and .lcf files
by comparing the (16 bit) hashes present in these files with the expected values.
(Please note that these 16-bit hashes are encoded in little-endian.)
Publication of this algorithm effectively breaks the rights management of Folio
4.x .nfo files. (security versions 0x0407, 0x0408, 0x0411 and possibly later)
I couldn't possibly be bothered to find out who currently holds the copyright to the Folio program suite.
nfohash is free software;
you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as published by
the Free Software Foundation.
nfohash 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.
You should have received a copy of the GNU General Public License version 2
along with the nfohash sourcecode; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdio.h>
#include <stdlib.h>
/* typedef unsigned int uint; /* should be in <sys/types.h> , else uncomment*/
uint seed[4];
const uint tab1[256] = {
0x0000,0xc0c1,0xc181,0x0140,0xc301,0x03c0,0x0280,0 xc241,
0xc601,0x06c0,0x0780,0xc741,0x0500,0xc5c1,0xc481,0 x0440,
0xcc01,0x0cc0,0x0d80,0xcd41,0x0f00,0xcfc1,0xce81,0 x0e40,
0x0a00,0xcac1,0xcb81,0x0b40,0xc901,0x09c0,0x0880,0 xc841,
0xd801,0x18c0,0x1980,0xd941,0x1b00,0xdbc1,0xda81,0 x1a40,
0x1e00,0xdec1,0xdf81,0x1f40,0xdd01,0x1dc0,0x1c80,0 xdc41,
0x1400,0xd4c1,0xd581,0x1540,0xd701,0x17c0,0x1680,0 xd641,
0xd201,0x12c0,0x1380,0xd341,0x1100,0xd1c1,0xd081,0 x1040,
0xf001,0x30c0,0x3180,0xf141,0x3300,0xf3c1,0xf281,0 x3240,
0x3600,0xf6c1,0xf781,0x3740,0xf501,0x35c0,0x3480,0 xf441,
0x3c00,0xfcc1,0xfd81,0x3d40,0xff01,0x3fc0,0x3e80,0 xfe41,
0xfa01,0x3ac0,0x3b80,0xfb41,0x3900,0xf9c1,0xf881,0 x3840,
0x2800,0xe8c1,0xe981,0x2940,0xeb01,0x2bc0,0x2a80,0 xea41,
0xee01,0x2ec0,0x2f80,0xef41,0x2d00,0xedc1,0xec81,0 x2c40,
0xe401,0x24c0,0x2580,0xe541,0x2700,0xe7c1,0xe681,0 x2640,
0x2200,0xe2c1,0xe381,0x2340,0xe101,0x21c0,0x2080,0 xe041,
0xa001,0x60c0,0x6180,0xa141,0x6300,0xa3c1,0xa281,0 x6240,
0x6600,0xa6c1,0xa781,0x6740,0xa501,0x65c0,0x6480,0 xa441,
0x6c00,0xacc1,0xad81,0x6d40,0xaf01,0x6fc0,0x6e80,0 xae41,
0xaa01,0x6ac0,0x6b80,0xab41,0x6900,0xa9c1,0xa881,0 x6840,
0x7800,0xb8c1,0xb981,0x7940,0xbb01,0x7bc0,0x7a80,0 xba41,
0xbe01,0x7ec0,0x7f80,0xbf41,0x7d00,0xbdc1,0xbc81,0 x7c40,
0xb401,0x74c0,0x7580,0xb541,0x7700,0xb7c1,0xb681,0 x7640,
0x7200,0xb2c1,0xb381,0x7340,0xb101,0x71c0,0x7080,0 xb041,
0x5000,0x90c1,0x9181,0x5140,0x9301,0x53c0,0x5280,0 x9241,
0x9601,0x56c0,0x5780,0x9741,0x5500,0x95c1,0x9481,0 x5440,
0x9c01,0x5cc0,0x5d80,0x9d41,0x5f00,0x9fc1,0x9e81,0 x5e40,
0x5a00,0x9ac1,0x9b81,0x5b40,0x9901,0x59c0,0x5880,0 x9841,
0x8801,0x48c0,0x4980,0x8941,0x4b00,0x8bc1,0x8a81,0 x4a40,
0x4e00,0x8ec1,0x8f81,0x4f40,0x8d01,0x4dc0,0x4c80,0 x8c41,
0x4400,0x84c1,0x8581,0x4540,0x8701,0x47c0,0x4680,0 x8641,
0x8201,0x42c0,0x4380,0x8341,0x4100,0x81c1,0x8081,0 x4040
};
const uint tab2[256] = {
0x0000,0xd219,0xa0f2,0x72eb,0x4524,0x973d,0xe5d6,0 x37cf,
0x8a48,0x5851,0x2aba,0xf8a3,0xcf6c,0x1d75,0x6f9e,0 xbd87,
0x1051,0xc248,0xb0a3,0x62ba,0x5575,0x876c,0xf587,0 x279e,
0x9a19,0x4800,0x3aeb,0xe8f2,0xdf3d,0x0d24,0x7fcf,0 xadd6,
0x20a3,0xf2ba,0x8051,0x5248,0x6587,0xb79e,0xc575,0 x176c,
0xaaeb,0x78f2,0x0a19,0xd800,0xefcf,0x3dd6,0x4f3d,0 x9d24,
0x30f2,0xe2eb,0x9000,0x4219,0x75d6,0xa7cf,0xd524,0 x073d,
0xbaba,0x68a3,0x1a48,0xc851,0xff9e,0x2d87,0x5f6c,0 x8d75,
0x4146,0x935f,0xe1b4,0x33ad,0x0462,0xd67b,0xa490,0 x7689,
0xcb0e,0x1917,0x6bfc,0xb9e5,0x8e2a,0x5c33,0x2ed8,0 xfcc1,
0x5117,0x830e,0xf1e5,0x23fc,0x1433,0xc62a,0xb4c1,0 x66d8,
0xdb5f,0x0946,0x7bad,0xa9b4,0x9e7b,0x4c62,0x3e89,0 xec90,
0x61e5,0xb3fc,0xc117,0x130e,0x24c1,0xf6d8,0x8433,0 x562a,
0xebad,0x39b4,0x4b5f,0x9946,0xae89,0x7c90,0x0e7b,0 xdc62,
0x71b4,0xa3ad,0xd146,0x035f,0x3490,0xe689,0x9462,0 x467b,
0xfbfc,0x29e5,0x5b0e,0x8917,0xbed8,0x6cc1,0x1e2a,0 xcc33,
0x828c,0x5095,0x227e,0xf067,0xc7a8,0x15b1,0x675a,0 xb543,
0x08c4,0xdadd,0xa836,0x7a2f,0x4de0,0x9ff9,0xed12,0 x3f0b,
0x92dd,0x40c4,0x322f,0xe036,0xd7f9,0x05e0,0x770b,0 xa512,
0x1895,0xca8c,0xb867,0x6a7e,0x5db1,0x8fa8,0xfd43,0 x2f5a,
0xa22f,0x7036,0x02dd,0xd0c4,0xe70b,0x3512,0x47f9,0 x95e0,
0x2867,0xfa7e,0x8895,0x5a8c,0x6d43,0xbf5a,0xcdb1,0 x1fa8,
0xb27e,0x6067,0x128c,0xc095,0xf75a,0x2543,0x57a8,0 x85b1,
0x3836,0xea2f,0x98c4,0x4add,0x7d12,0xaf0b,0xdde0,0 x0ff9,
0xc3ca,0x11d3,0x6338,0xb121,0x86ee,0x54f7,0x261c,0 xf405,
0x4982,0x9b9b,0xe970,0x3b69,0x0ca6,0xdebf,0xac54,0 x7e4d,
0xd39b,0x0182,0x7369,0xa170,0x96bf,0x44a6,0x364d,0 xe454,
0x59d3,0x8bca,0xf921,0x2b38,0x1cf7,0xceee,0xbc05,0 x6e1c,
0xe369,0x3170,0x439b,0x9182,0xa64d,0x7454,0x06bf,0 xd4a6,
0x6921,0xbb38,0xc9d3,0x1bca,0x2c05,0xfe1c,0x8cf7,0 x5eee,
0xf338,0x2121,0x53ca,0x81d3,0xb61c,0x6405,0x16ee,0 xc4f7,
0x7970,0xab69,0xd982,0x0b9b,0x3c54,0xee4d,0x9ca6,0 x4ebf
};
uint calchash(uint seed, uint size, unsigned char *src) {
uint i = 0;
uint r = seed & 0xFFFF;
for (i=0;i<(size);i++)
r = (tab1[r/256]^tab2[r%256]^src[i]) & 0xFFFF;
return r;
}
int check(uint seed, uint size, unsigned char *src, uint feedback, uint cs) {
uint r = calchash(seed,size,src);
if(feedback) {
if(r==cs) {
if (feedback>1)
printf("checksum ok\n");
} else {
printf("WRONG CHECKSUM: calculated %x, expected %x\n",r,cs);
}
}
return (r==cs);
}
int checkhash(uint seed, uint size, unsigned char *src, uint feedback) {
uint cs = src[size-2]+256*src[size-1];
return check(seed,size-2,src,feedback,cs);
}
int checkhash2(uint seed, uint size, unsigned char *src, uint feedback) {
uint cs = src[2]+256*src[3];
return check(seed,size-4,src+4,feedback,cs);
}
void initseed(uint *seed, unsigned char *page) {
seed[0] = 0;
seed[1] = 0xED21;
seed[2] = (page[0x100]^page[0x104])+256*(page[0x101]^page[0x105]);
seed[3] = (page[0x104]+256*page[0x105]);
}
void checkparts(unsigned char *page, uint feedback) {
uint cs;
int seeds_ix[8] = {-1,0,0,1,2,2,2,2};
uint offset[8] = {0x000,0x050,0x0E0,0x100,0x120,0x1B0,0x2C0,0x300};
uint size[8] = {0x050,0x090,0x020,0x020,0x090,0x110,0x040,0x400};
uint part;
for(part=1;part<8;part++) {
if(!checkhash(seed[seeds_ix[part]],size[part],page+offset[part],feedback))
printf("error in part %i of page 0\n",part);
}
}
void checkfile(FILE *infile,const char *name) {
unsigned char page[4096];
uint cs;
uint b = 0;
fread(page,1,0x1000,infile);
initseed(seed,page);
checkparts(page,1);
if(memcmp(page+0x50,page+0x750,0x6B0))
printf("page 0: error in mirrored portion\n");
b = 1;
while(fread(page,1,0x1000,infile)==0x1000) {
if(!checkhash2(seed[3]+b,0x1000,page,1))
printf("checksum error at page %u\n",b);
b++;
}
printf("checked %u pages in %s\n",b,name);
}
int main(int argc, const char * argv[]) {
FILE *infile = NULL;
uint i;
if(argc>1) for(i=1;i<argc;i++) {
const char *name =argv[i];
infile = fopen(name,"r");
if(infile)
checkfile(infile,name);
else
printf("could not open %s for input\n",name);
} else {
printf("usage: nfohash <filename> [ <filename> ]*\n");
printf("e.g.\n\tnfohash *.nfo *.sdw *.lcf\n");
}
exit(0);
}
Folio 4.x hash algorithm
(C) 2000-2001 Paul Janssens - All rights reserved
nfohash checks the integrity of folio 4.x .nfo, .sdw and .lcf files
by comparing the (16 bit) hashes present in these files with the expected values.
(Please note that these 16-bit hashes are encoded in little-endian.)
Publication of this algorithm effectively breaks the rights management of Folio
4.x .nfo files. (security versions 0x0407, 0x0408, 0x0411 and possibly later)
I couldn't possibly be bothered to find out who currently holds the copyright to the Folio program suite.
nfohash is free software;
you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as published by
the Free Software Foundation.
nfohash 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.
You should have received a copy of the GNU General Public License version 2
along with the nfohash sourcecode; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdio.h>
#include <stdlib.h>
/* typedef unsigned int uint; /* should be in <sys/types.h> , else uncomment*/
uint seed[4];
const uint tab1[256] = {
0x0000,0xc0c1,0xc181,0x0140,0xc301,0x03c0,0x0280,0 xc241,
0xc601,0x06c0,0x0780,0xc741,0x0500,0xc5c1,0xc481,0 x0440,
0xcc01,0x0cc0,0x0d80,0xcd41,0x0f00,0xcfc1,0xce81,0 x0e40,
0x0a00,0xcac1,0xcb81,0x0b40,0xc901,0x09c0,0x0880,0 xc841,
0xd801,0x18c0,0x1980,0xd941,0x1b00,0xdbc1,0xda81,0 x1a40,
0x1e00,0xdec1,0xdf81,0x1f40,0xdd01,0x1dc0,0x1c80,0 xdc41,
0x1400,0xd4c1,0xd581,0x1540,0xd701,0x17c0,0x1680,0 xd641,
0xd201,0x12c0,0x1380,0xd341,0x1100,0xd1c1,0xd081,0 x1040,
0xf001,0x30c0,0x3180,0xf141,0x3300,0xf3c1,0xf281,0 x3240,
0x3600,0xf6c1,0xf781,0x3740,0xf501,0x35c0,0x3480,0 xf441,
0x3c00,0xfcc1,0xfd81,0x3d40,0xff01,0x3fc0,0x3e80,0 xfe41,
0xfa01,0x3ac0,0x3b80,0xfb41,0x3900,0xf9c1,0xf881,0 x3840,
0x2800,0xe8c1,0xe981,0x2940,0xeb01,0x2bc0,0x2a80,0 xea41,
0xee01,0x2ec0,0x2f80,0xef41,0x2d00,0xedc1,0xec81,0 x2c40,
0xe401,0x24c0,0x2580,0xe541,0x2700,0xe7c1,0xe681,0 x2640,
0x2200,0xe2c1,0xe381,0x2340,0xe101,0x21c0,0x2080,0 xe041,
0xa001,0x60c0,0x6180,0xa141,0x6300,0xa3c1,0xa281,0 x6240,
0x6600,0xa6c1,0xa781,0x6740,0xa501,0x65c0,0x6480,0 xa441,
0x6c00,0xacc1,0xad81,0x6d40,0xaf01,0x6fc0,0x6e80,0 xae41,
0xaa01,0x6ac0,0x6b80,0xab41,0x6900,0xa9c1,0xa881,0 x6840,
0x7800,0xb8c1,0xb981,0x7940,0xbb01,0x7bc0,0x7a80,0 xba41,
0xbe01,0x7ec0,0x7f80,0xbf41,0x7d00,0xbdc1,0xbc81,0 x7c40,
0xb401,0x74c0,0x7580,0xb541,0x7700,0xb7c1,0xb681,0 x7640,
0x7200,0xb2c1,0xb381,0x7340,0xb101,0x71c0,0x7080,0 xb041,
0x5000,0x90c1,0x9181,0x5140,0x9301,0x53c0,0x5280,0 x9241,
0x9601,0x56c0,0x5780,0x9741,0x5500,0x95c1,0x9481,0 x5440,
0x9c01,0x5cc0,0x5d80,0x9d41,0x5f00,0x9fc1,0x9e81,0 x5e40,
0x5a00,0x9ac1,0x9b81,0x5b40,0x9901,0x59c0,0x5880,0 x9841,
0x8801,0x48c0,0x4980,0x8941,0x4b00,0x8bc1,0x8a81,0 x4a40,
0x4e00,0x8ec1,0x8f81,0x4f40,0x8d01,0x4dc0,0x4c80,0 x8c41,
0x4400,0x84c1,0x8581,0x4540,0x8701,0x47c0,0x4680,0 x8641,
0x8201,0x42c0,0x4380,0x8341,0x4100,0x81c1,0x8081,0 x4040
};
const uint tab2[256] = {
0x0000,0xd219,0xa0f2,0x72eb,0x4524,0x973d,0xe5d6,0 x37cf,
0x8a48,0x5851,0x2aba,0xf8a3,0xcf6c,0x1d75,0x6f9e,0 xbd87,
0x1051,0xc248,0xb0a3,0x62ba,0x5575,0x876c,0xf587,0 x279e,
0x9a19,0x4800,0x3aeb,0xe8f2,0xdf3d,0x0d24,0x7fcf,0 xadd6,
0x20a3,0xf2ba,0x8051,0x5248,0x6587,0xb79e,0xc575,0 x176c,
0xaaeb,0x78f2,0x0a19,0xd800,0xefcf,0x3dd6,0x4f3d,0 x9d24,
0x30f2,0xe2eb,0x9000,0x4219,0x75d6,0xa7cf,0xd524,0 x073d,
0xbaba,0x68a3,0x1a48,0xc851,0xff9e,0x2d87,0x5f6c,0 x8d75,
0x4146,0x935f,0xe1b4,0x33ad,0x0462,0xd67b,0xa490,0 x7689,
0xcb0e,0x1917,0x6bfc,0xb9e5,0x8e2a,0x5c33,0x2ed8,0 xfcc1,
0x5117,0x830e,0xf1e5,0x23fc,0x1433,0xc62a,0xb4c1,0 x66d8,
0xdb5f,0x0946,0x7bad,0xa9b4,0x9e7b,0x4c62,0x3e89,0 xec90,
0x61e5,0xb3fc,0xc117,0x130e,0x24c1,0xf6d8,0x8433,0 x562a,
0xebad,0x39b4,0x4b5f,0x9946,0xae89,0x7c90,0x0e7b,0 xdc62,
0x71b4,0xa3ad,0xd146,0x035f,0x3490,0xe689,0x9462,0 x467b,
0xfbfc,0x29e5,0x5b0e,0x8917,0xbed8,0x6cc1,0x1e2a,0 xcc33,
0x828c,0x5095,0x227e,0xf067,0xc7a8,0x15b1,0x675a,0 xb543,
0x08c4,0xdadd,0xa836,0x7a2f,0x4de0,0x9ff9,0xed12,0 x3f0b,
0x92dd,0x40c4,0x322f,0xe036,0xd7f9,0x05e0,0x770b,0 xa512,
0x1895,0xca8c,0xb867,0x6a7e,0x5db1,0x8fa8,0xfd43,0 x2f5a,
0xa22f,0x7036,0x02dd,0xd0c4,0xe70b,0x3512,0x47f9,0 x95e0,
0x2867,0xfa7e,0x8895,0x5a8c,0x6d43,0xbf5a,0xcdb1,0 x1fa8,
0xb27e,0x6067,0x128c,0xc095,0xf75a,0x2543,0x57a8,0 x85b1,
0x3836,0xea2f,0x98c4,0x4add,0x7d12,0xaf0b,0xdde0,0 x0ff9,
0xc3ca,0x11d3,0x6338,0xb121,0x86ee,0x54f7,0x261c,0 xf405,
0x4982,0x9b9b,0xe970,0x3b69,0x0ca6,0xdebf,0xac54,0 x7e4d,
0xd39b,0x0182,0x7369,0xa170,0x96bf,0x44a6,0x364d,0 xe454,
0x59d3,0x8bca,0xf921,0x2b38,0x1cf7,0xceee,0xbc05,0 x6e1c,
0xe369,0x3170,0x439b,0x9182,0xa64d,0x7454,0x06bf,0 xd4a6,
0x6921,0xbb38,0xc9d3,0x1bca,0x2c05,0xfe1c,0x8cf7,0 x5eee,
0xf338,0x2121,0x53ca,0x81d3,0xb61c,0x6405,0x16ee,0 xc4f7,
0x7970,0xab69,0xd982,0x0b9b,0x3c54,0xee4d,0x9ca6,0 x4ebf
};
uint calchash(uint seed, uint size, unsigned char *src) {
uint i = 0;
uint r = seed & 0xFFFF;
for (i=0;i<(size);i++)
r = (tab1[r/256]^tab2[r%256]^src[i]) & 0xFFFF;
return r;
}
int check(uint seed, uint size, unsigned char *src, uint feedback, uint cs) {
uint r = calchash(seed,size,src);
if(feedback) {
if(r==cs) {
if (feedback>1)
printf("checksum ok\n");
} else {
printf("WRONG CHECKSUM: calculated %x, expected %x\n",r,cs);
}
}
return (r==cs);
}
int checkhash(uint seed, uint size, unsigned char *src, uint feedback) {
uint cs = src[size-2]+256*src[size-1];
return check(seed,size-2,src,feedback,cs);
}
int checkhash2(uint seed, uint size, unsigned char *src, uint feedback) {
uint cs = src[2]+256*src[3];
return check(seed,size-4,src+4,feedback,cs);
}
void initseed(uint *seed, unsigned char *page) {
seed[0] = 0;
seed[1] = 0xED21;
seed[2] = (page[0x100]^page[0x104])+256*(page[0x101]^page[0x105]);
seed[3] = (page[0x104]+256*page[0x105]);
}
void checkparts(unsigned char *page, uint feedback) {
uint cs;
int seeds_ix[8] = {-1,0,0,1,2,2,2,2};
uint offset[8] = {0x000,0x050,0x0E0,0x100,0x120,0x1B0,0x2C0,0x300};
uint size[8] = {0x050,0x090,0x020,0x020,0x090,0x110,0x040,0x400};
uint part;
for(part=1;part<8;part++) {
if(!checkhash(seed[seeds_ix[part]],size[part],page+offset[part],feedback))
printf("error in part %i of page 0\n",part);
}
}
void checkfile(FILE *infile,const char *name) {
unsigned char page[4096];
uint cs;
uint b = 0;
fread(page,1,0x1000,infile);
initseed(seed,page);
checkparts(page,1);
if(memcmp(page+0x50,page+0x750,0x6B0))
printf("page 0: error in mirrored portion\n");
b = 1;
while(fread(page,1,0x1000,infile)==0x1000) {
if(!checkhash2(seed[3]+b,0x1000,page,1))
printf("checksum error at page %u\n",b);
b++;
}
printf("checked %u pages in %s\n",b,name);
}
int main(int argc, const char * argv[]) {
FILE *infile = NULL;
uint i;
if(argc>1) for(i=1;i<argc;i++) {
const char *name =argv[i];
infile = fopen(name,"r");
if(infile)
checkfile(infile,name);
else
printf("could not open %s for input\n",name);
} else {
printf("usage: nfohash <filename> [ <filename> ]*\n");
printf("e.g.\n\tnfohash *.nfo *.sdw *.lcf\n");
}
exit(0);
}