iRiver scramble and descramble code from Dave Cooper

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@5649 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
Daniel Stenberg 2005-01-24 09:01:48 +00:00
parent 99dbd7c5e9
commit adaae249ef
8 changed files with 508 additions and 16 deletions

View file

@ -95,3 +95,4 @@ Brian King
Jiri Jurecek
Jacob Erlbeck
Jean-Philippe Bernardy
Dave Hooper

View file

@ -338,3 +338,36 @@ proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.
------------------------
ihpfirm (source code in the tools/iriver.c file)
COPYRIGHT AND PERMISSION NOTICE
Copyright (c) 2004 Dave Hooper (@spc)
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, and/or sell copies of the
Software, and to permit persons to whom the Software is furnished to do so,
provided that the above copyright notice(s) and this permission notice appear
in all copies of the Software and that both the above copyright notice(s) and
this permission notice appear in supporting documentation.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN
NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE
LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY
DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Except as contained in this notice, the name of a copyright holder shall not
be used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization of the copyright holder.

View file

@ -13,9 +13,12 @@ TARGETS := scramble descramble sh2d bmp2rb convbdf generate_rocklatin
all: $(TARGETS)
@echo "tools done"
scramble: scramble.c
scramble: scramble.o iriver.o
descramble: descramble.o iriver.o
descramble: descramble.c
scramble.o: scramble.c iriver.h
descramble.o: descramble.c iriver.h
iriver.o: iriver.c iriver.h
sh2d: sh2d.c

2
tools/configure vendored
View file

@ -352,7 +352,7 @@ if [ -z "$archos" ]; then
target="-DIRIVER_H100"
memory=32 # always
coldfirecc
tool="cp"
tool="$rootdir/tools/scramble -iriver"
output="rockbox.iriver"
appextra="recorder"
archosrom=""

View file

@ -20,6 +20,20 @@
#include <stdio.h>
#include <stdlib.h>
#include "iriver.h"
void usage(void)
{
printf("usage: descramble [options] <input file> <output file>\n");
printf("options:\n"
"\t-fm Archos FM recorder format\n"
"\t-v2 Archos V2 recorder format\n"
"\t-mm=X Archos Multimedia format (X values: A=JBMM, B=AV1xx, C=AV3xx)\n"
"\t-iriver iRiver format\n"
"\nNo option assumes Archos standard player/recorder format.\n");
exit(1);
}
int main (int argc, char** argv)
{
unsigned long length,i,slen;
@ -32,9 +46,7 @@ int main (int argc, char** argv)
FILE* file;
if (argc < 3) {
printf("usage: %s [-fm] [-v2] [-mm] <input file> <output file>\n",
argv[0]);
return -1;
usage();
}
if (!strcmp(argv[1], "-fm") || !strcmp(argv[1], "-v2")) {
@ -49,6 +61,14 @@ int main (int argc, char** argv)
oname = argv[3];
descramble = 0;
}
if(!strcmp(argv[1], "-iriver")) {
/* iRiver code dealt with in the iriver.c code */
iname = argv[2];
oname = argv[3];
iriver_decode(iname, oname, FALSE, STRIP_NONE);
return 0;
}
/* open file and check size */
file = fopen(iname,"rb");

381
tools/iriver.c Normal file
View file

@ -0,0 +1,381 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2004 by Dave Hooper
*
* This particular source code file is licensed under the X11 license. See the
* bottom of the COPYING file for details on this license.
*
* Original code from http://www.beermex.com/@spc/ihpfirm.src.zip
* Details at http://www.rockbox.org/twiki/bin/view/Main/IriverToolsGuide
*
****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "iriver.h"
const unsigned char munge[] = {
0x7a, 0x36, 0xc4, 0x43, 0x49, 0x6b, 0x35, 0x4e, 0xa3, 0x46, 0x25, 0x84,
0x4d, 0x73, 0x74, 0x61
};
const unsigned char header_modify[] = "* IHPFIRM-DECODED ";
const char * const models[] = { "iHP-100", "iHP-120/iHP-140", "H300 series",
NULL };
/* aligns with models array; expected min firmware size */
const unsigned int firmware_minsize[] = { 1000000, 1000000, 2000000 };
/* aligns with models array; expected max firmware size */
const unsigned int firmware_maxsize[] = { 2000000, 2000000, 4000000 };
const unsigned char header[][16] = {
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 },
{ 0x20, 0x03, 0x08, 0x27, 0x24, 0x00, 0x02, 0x30, 0x19, 0x17, 0x65, 0x73,
0x85, 0x32, 0x83, 0x22 },
{ 0x20, 0x04, 0x03, 0x27, 0x20, 0x50, 0x01, 0x70, 0x80, 0x30, 0x80, 0x06,
0x30, 0x19, 0x17, 0x65 }
};
static int testheader( const unsigned char * const data )
{
const unsigned char * const d = data+16;
const char * const * m = models;
int index = 0;
while( *m )
{
if( memcmp( header[ index ], d, 16 ) == 0 )
return index;
index++;
m++;
};
return -1;
};
static void modifyheader( unsigned char * data )
{
const unsigned char * h = header_modify;
int i;
for( i=0; i<512; i++ )
{
if( *h == '\0' )
h = header_modify;
*data++ ^= *h++;
};
};
static FILE * openinfile( const char * filename )
{
FILE * F = fopen( filename, "rb" );
if( F == NULL )
{
fprintf( stderr, "Couldn't open input file %s\n", filename );
perror( "Error was " );
exit( -1 );
};
return F;
};
static FILE * openoutfile( const char * filename )
{
FILE * F = fopen( filename, "wb" );
if( F == NULL )
{
fprintf( stderr, "Couldn't open output file %s\n", filename );
perror( "Error was " );
exit( -1 );
};
return F;
};
int iriver_decode(char *infile_name, char *outfile_name, BOOL modify,
enum striptype stripmode )
{
FILE * infile = NULL;
FILE * outfile = NULL;
int i = -1;
unsigned char headerdata[512];
unsigned long dwLength1, dwLength2, dwLength3, fp = 0;
unsigned char blockdata[16+16];
unsigned char out[16];
unsigned char newmunge;
signed long lenread;
int s = 0;
unsigned char * pChecksums, * ppChecksums = 0;
unsigned char ck;
infile = openinfile(infile_name);
outfile = openoutfile(outfile_name);
lenread = fread( headerdata, 1, 512, infile );
if( lenread != 512 )
{
fprintf( stderr, "This doesn't look like a valid encrypted iHP "
"firmware - reason: header length\n" );
exit( -1 );
};
i = testheader( headerdata );
if( i == -1 )
{
fprintf( stderr, "This firmware is for an unknown model, or is not"
" a valid encrypted iHP firmware\n" );
exit( -1 );
};
fprintf( stderr, "Model %s\n", models[ i ] );
dwLength1 = headerdata[0] | (headerdata[1]<<8) |
(headerdata[2]<<16) | (headerdata[3]<<24);
dwLength2 = headerdata[4] | (headerdata[5]<<8) |
(headerdata[6]<<16) | (headerdata[7]<<24);
dwLength3 = headerdata[8] | (headerdata[9]<<8) |
(headerdata[10]<<16) | (headerdata[11]<<24);
if( dwLength1 < firmware_minsize[ i ] ||
dwLength1 > firmware_maxsize[ i ] ||
dwLength2 < firmware_minsize[ i ] ||
dwLength2 > dwLength1 ||
dwLength3 > dwLength1 ||
dwLength2>>9 != dwLength3 ||
dwLength2+dwLength3+512 != dwLength1 )
{
fprintf( stderr, "This doesn't look like a valid encrypted "
"iHP firmware - reason: file 'length' data\n" );
exit( -1 );
};
pChecksums = ppChecksums = (unsigned char *)( malloc( dwLength3 ) );
if( modify )
{
modifyheader( headerdata );
};
if( stripmode == STRIP_NONE )
fwrite( headerdata, 512, 1, outfile );
memset( blockdata, 0, 16 );
ck = 0;
while( ( fp < dwLength2 ) &&
( lenread = fread( blockdata+16, 1, 16, infile ) ) == 16 )
{
fp += 16;
for( i=0; i<16; ++i )
{
newmunge = blockdata[16+i] ^ munge[i];
out[i] = newmunge ^ blockdata[i];
blockdata[i] = newmunge;
ck += out[i];
}
if( fp > ESTF_SIZE || stripmode != STRIP_HEADER_CHECKSUM_ESTF )
{
fwrite( out+4, 1, 12, outfile );
fwrite( out, 1, 4, outfile );
}
else
{
if( ESTF_SIZE - fp < 16 )
{
memcpy( out+4, blockdata+16, 12 );
memcpy( out, blockdata+28, 4 );
fwrite( blockdata+16+ESTF_SIZE-fp, 1, ESTF_SIZE-fp, outfile );
}
}
if( s == 496 )
{
s = 0;
memset( blockdata, 0, 16 );
*ppChecksums++ = ck;
ck = 0;
}
else
s+=16;
};
if( fp != dwLength2 )
{
fprintf( stderr, "This doesn't look like a valid encrypted "
"iHP firmware - reason: 'length2' mismatch\n" );
exit( -1 );
};
fp = 0;
ppChecksums = pChecksums;
while( ( fp < dwLength3 ) &&
( lenread = fread( blockdata, 1, 32, infile ) ) > 0 )
{
fp += lenread;
if( stripmode == STRIP_NONE )
fwrite( blockdata, 1, lenread, outfile );
if( memcmp( ppChecksums, blockdata, lenread ) != 0 )
{
fprintf( stderr, "This doesn't look like a valid encrypted "
"iHP firmware - reason: Checksum mismatch!" );
exit( -1 );
};
ppChecksums += lenread;
};
if( fp != dwLength3 )
{
fprintf( stderr, "This doesn't look like a valid encrypted "
"iHP firmware - reason: 'length3' mismatch\n" );
exit( -1 );
};
fprintf( stderr, "File decoded correctly and all checksums matched!\n" );
switch( stripmode )
{
default:
case STRIP_NONE:
fprintf(stderr, "Output file contains all headers and "
"checksums\n");
break;
case STRIP_HEADER_CHECKSUM:
fprintf( stderr, "NB: output file contains only ESTFBINR header"
" and decoded firmware code\n" );
break;
case STRIP_HEADER_CHECKSUM_ESTF:
fprintf( stderr, "NB: output file contains only raw decoded "
"firmware code\n" );
break;
};
return 0;
};
int iriver_encode(char *infile_name, char *outfile_name, BOOL modify )
{
FILE * infile = NULL;
FILE * outfile = NULL;
int i = -1;
unsigned char headerdata[512];
unsigned long dwLength1, dwLength2, dwLength3, fp = 0;
unsigned char blockdata[16+16];
unsigned char out[16];
unsigned char newmunge;
signed long lenread;
int s = 0;
unsigned char * pChecksums, * ppChecksums;
unsigned char ck;
enum striptype stripmode = STRIP_NONE;
infile = openinfile(infile_name);
outfile = openoutfile(outfile_name);
lenread = fread( headerdata, 1, 512, infile );
if( lenread != 512 )
{
fprintf( stderr, "This doesn't look like a valid decoded "
"iHP firmware - reason: header length\n" );
exit( -1 );
};
if( modify )
{
modifyheader( headerdata ); /* reversible */
};
i = testheader( headerdata );
if( i == -1 )
{
fprintf( stderr, "This firmware is for an unknown model, or is not"
" a valid decoded iHP firmware\n" );
exit( -1 );
};
fprintf( stderr, "Model %s\n", models[ i ] );
dwLength1 = headerdata[0] | (headerdata[1]<<8) |
(headerdata[2]<<16) | (headerdata[3]<<24);
dwLength2 = headerdata[4] | (headerdata[5]<<8) |
(headerdata[6]<<16) | (headerdata[7]<<24);
dwLength3 = headerdata[8] | (headerdata[9]<<8) |
(headerdata[10]<<16) | (headerdata[11]<<24);
if( dwLength1 < firmware_minsize[i] ||
dwLength1 > firmware_maxsize[i] ||
dwLength2 < firmware_minsize[i] ||
dwLength2 > dwLength1 ||
dwLength3 > dwLength1 ||
dwLength2+dwLength3+512 != dwLength1 )
{
fprintf( stderr, "This doesn't look like a valid decoded iHP"
" firmware - reason: file 'length' data\n" );
exit( -1 );
};
pChecksums = ppChecksums = (unsigned char *)( malloc( dwLength3 ) );
fwrite( headerdata, 512, 1, outfile );
memset( blockdata, 0, 16 );
ck = 0;
while( ( fp < dwLength2 ) &&
( lenread = fread( blockdata+16, 1, 16, infile ) ) == 16 )
{
fp += 16;
for( i=0; i<16; ++i )
{
newmunge = blockdata[16+((12+i)&0xf)] ^ blockdata[i];
out[i] = newmunge ^ munge[i];
ck += blockdata[16+i];
blockdata[i] = newmunge;
};
fwrite( out, 1, 16, outfile );
if( s == 496 )
{
s = 0;
memset( blockdata, 0, 16 );
*ppChecksums++ = ck;
ck = 0;
}
else
s+=16;
};
if( fp != dwLength2 )
{
fprintf( stderr, "This doesn't look like a valid decoded "
"iHP firmware - reason: 'length1' mismatch\n" );
exit( -1 );
};
/* write out remainder w/out applying descrambler */
fp = 0;
lenread = dwLength3;
ppChecksums = pChecksums;
while( ( fp < dwLength3) &&
( lenread = fwrite( ppChecksums, 1, lenread, outfile ) ) > 0 )
{
fp += lenread;
ppChecksums += lenread;
lenread = dwLength3 - fp;
};
if( fp != dwLength3 )
{
fprintf( stderr, "This doesn't look like a valid decoded "
"iHP firmware - reason: 'length2' mismatch\n" );
exit( -1 );
};
fprintf( stderr, "File encoded successfully and checksum table built!\n" );
return 0;
};

37
tools/iriver.h Normal file
View file

@ -0,0 +1,37 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2005 by Daniel Stenberg
*
* All files in this archive are subject to the GNU General Public License.
* See the file COPYING in the source tree root for full license agreement.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#define TRUE 1
#define FALSE 0
#define BOOL unsigned int
#define ESTF_SIZE 32
enum striptype
{
STRIP_NONE,
STRIP_HEADER_CHECKSUM,
STRIP_HEADER_CHECKSUM_ESTF
};
/* protos for iriver.c */
int iriver_decode(char *infile, char *outfile, BOOL modify,
enum striptype stripmode );
int iriver_encode(char *infile_name, char *outfile_name, BOOL modify );

View file

@ -20,6 +20,8 @@
#include <stdio.h>
#include <stdlib.h>
#include "iriver.h"
void int2le(unsigned int val, unsigned char* addr)
{
addr[0] = val & 0xFF;
@ -36,6 +38,22 @@ void int2be(unsigned int val, unsigned char* addr)
addr[3] = val & 0xFF;
}
void usage(void)
{
printf("usage: scramble [options] <input file> <output file> [xor string]\n");
printf("options:\n"
"\t-fm Archos FM recorder format\n"
"\t-v2 Archos V2 recorder format\n"
"\t-ofm Archos Ondio FM recorder format\n"
"\t-osp Archos Ondio SP format\n"
"\t-neo SSI Neo format\n"
"\t-mm=X Archos Multimedia format (X values: A=JBMM, B=AV1xx, C=AV3xx)\n"
"\t-iriver iRiver format\n"
"\nNo option results in Archos standard player/recorder format.\n");
exit(1);
}
int main (int argc, char** argv)
{
unsigned long length,i,slen;
@ -51,16 +69,7 @@ int main (int argc, char** argv)
enum { none, scramble, xor } method = scramble;
if (argc < 3) {
printf("usage: %s [options] <input file> <output file> [xor string]\n",argv[0]);
printf("options:\n");
printf("\t-fm Archos FM recorder format\n");
printf("\t-v2 Archos V2 recorder format\n");
printf("\t-ofm Archos Ondio FM recorder format\n");
printf("\t-osp Archos Ondio SP format\n");
printf("\t-neo SSI Neo format\n");
printf("\t-mm=X Archos Multimedia format (X values: A=JBMM, B=AV1xx, C=AV3xx)\n");
printf("\nNo option results in Archos standard player/recorder format.\n");
return -1;
usage();
}
if(!strcmp(argv[1], "-fm")) {
@ -111,6 +120,14 @@ int main (int argc, char** argv)
}
}
else if(!strcmp(argv[1], "-iriver")) {
/* iRiver code dealt with in the iriver.c code */
iname = argv[2];
oname = argv[3];
iriver_encode(iname, oname, FALSE);
return 0;
}
/* open file */
file = fopen(iname,"rb");
if (!file) {