diff options
author | Maurus Cuelenaere <mcuelenaere@gmail.com> | 2008-04-09 11:53:28 +0000 |
---|---|---|
committer | Maurus Cuelenaere <mcuelenaere@gmail.com> | 2008-04-09 11:53:28 +0000 |
commit | e810721e72d0d70d87b02603299d50809b794470 (patch) | |
tree | 19cc6a608e064abd6361493bb5cfa7589c531bba | |
parent | 5a3651bf940001693153ab52a67c9cd87e7d41c7 (diff) | |
download | rockbox-e810721e72d0d70d87b02603299d50809b794470.tar.gz rockbox-e810721e72d0d70d87b02603299d50809b794470.zip |
First commit:
* add Creative (ZVM, 60GB, ZV, ZVW, ZENV) support to scramble
* update configure to the correct values
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@17042 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r-- | tools/Makefile | 8 | ||||
-rwxr-xr-x | tools/configure | 9 | ||||
-rw-r--r-- | tools/creative.c | 159 | ||||
-rw-r--r-- | tools/creative.h | 53 | ||||
-rw-r--r-- | tools/hmac-sha1.c | 463 | ||||
-rw-r--r-- | tools/hmac-sha1.h | 84 | ||||
-rw-r--r-- | tools/scramble.c | 111 |
7 files changed, 784 insertions, 103 deletions
diff --git a/tools/Makefile b/tools/Makefile index 94378d8fc5..e43bf98f22 100644 --- a/tools/Makefile +++ b/tools/Makefile | |||
@@ -13,16 +13,18 @@ LDFLAGS := -g | |||
13 | 13 | ||
14 | CLEANALL := scramble descramble iriver sh2d bmp2rb rdf2binary convbdf \ | 14 | CLEANALL := scramble descramble iriver sh2d bmp2rb rdf2binary convbdf \ |
15 | generate_rocklatin mkboot ipod_fw codepages uclpack mi4 gigabeat database \ | 15 | generate_rocklatin mkboot ipod_fw codepages uclpack mi4 gigabeat database \ |
16 | lngdump telechips gigabeats mktccboot mknkboot rbspeexenc | 16 | lngdump telechips gigabeats creative hmac-sha1 mktccboot mknkboot rbspeexenc |
17 | 17 | ||
18 | all: | 18 | all: |
19 | @echo "Run make in your build directory!" | 19 | @echo "Run make in your build directory!" |
20 | 20 | ||
21 | scramble: scramble.o iriver.o mi4.o gigabeat.o gigabeats.o telechips.o iaudio_bl_flash.o | 21 | scramble: scramble.o iriver.o mi4.o gigabeat.o gigabeats.o telechips.o iaudio_bl_flash.o creative.o hmac-sha1.o |
22 | descramble: descramble.o iriver.o gigabeat.o | 22 | descramble: descramble.o iriver.o gigabeat.o |
23 | scramble.o: scramble.c iriver.h mi4.h gigabeat.h telechips.h iaudio_bl_flash.h creative.h | ||
23 | 24 | ||
24 | scramble.o: scramble.c iriver.h mi4.h gigabeat.h telechips.h iaudio_bl_flash.h | ||
25 | descramble.o: descramble.c iriver.h gigabeat.h | 25 | descramble.o: descramble.c iriver.h gigabeat.h |
26 | creative.o: creative.c creative.h | ||
27 | hmac-sha1.o: hmac-sha1.c hmac-sha1.h | ||
26 | iriver.o: iriver.c iriver.h | 28 | iriver.o: iriver.c iriver.h |
27 | gigabeat.o: gigabeat.c gigabeat.h | 29 | gigabeat.o: gigabeat.c gigabeat.h |
28 | gigabeats.o: gigabeats.c gigabeats.h | 30 | gigabeats.o: gigabeats.c gigabeats.h |
diff --git a/tools/configure b/tools/configure index 7f70c332ae..151a4b70ff 100755 --- a/tools/configure +++ b/tools/configure | |||
@@ -1455,18 +1455,19 @@ fi | |||
1455 | target_id=35 | 1455 | target_id=35 |
1456 | modelname="creativezvm" | 1456 | modelname="creativezvm" |
1457 | target="-DCREATIVE_ZVM" | 1457 | target="-DCREATIVE_ZVM" |
1458 | memory=32 # always | 1458 | memory=64 |
1459 | arm926ejscc | 1459 | arm926ejscc |
1460 | bmp2rb_mono="$rootdir/tools/bmp2rb -f 0" | 1460 | bmp2rb_mono="$rootdir/tools/bmp2rb -f 0" |
1461 | bmp2rb_native="$rootdir/tools/bmp2rb -f 4" | 1461 | bmp2rb_native="$rootdir/tools/bmp2rb -f 4" |
1462 | bmp2rb_remotemono="$rootdir/tools/bmp2rb -f 0" | 1462 | bmp2rb_remotemono="$rootdir/tools/bmp2rb -f 0" |
1463 | bmp2rb_remotenative="$rootdir/tools/bmp2rb -f 0" | 1463 | bmp2rb_remotenative="$rootdir/tools/bmp2rb -f 0" |
1464 | tool="cp" | ||
1464 | output="rockbox.zvm" | 1465 | output="rockbox.zvm" |
1465 | appextra="recorder:gui" | 1466 | appextra="recorder:gui" |
1466 | plugins="yes" | 1467 | plugins="" |
1467 | swcodec="yes" | 1468 | swcodec="yes" |
1468 | toolset=$gigabeatbitmaptools | 1469 | toolset=$gigabeatbitmaptools |
1469 | boottool="$rootdir/tools/scramble -zvm" | 1470 | boottool="$rootdir/tools/scramble -creative=zvm" |
1470 | bootoutput="rockbox.zvmboot" | 1471 | bootoutput="rockbox.zvmboot" |
1471 | # architecture, manufacturer and model for the target-tree build | 1472 | # architecture, manufacturer and model for the target-tree build |
1472 | t_cpu="arm" | 1473 | t_cpu="arm" |
@@ -1998,7 +1999,7 @@ sed > Makefile \ | |||
1998 | -e "s,@VOICETOOLSET@,${voicetoolset},g" \ | 1999 | -e "s,@VOICETOOLSET@,${voicetoolset},g" \ |
1999 | -e "s,@LANGS@,${buildlangs},g" \ | 2000 | -e "s,@LANGS@,${buildlangs},g" \ |
2000 | <<EOF | 2001 | <<EOF |
2001 | ## Automaticly generated. http://www.rockbox.org/ | 2002 | ## Automatically generated. http://www.rockbox.org/ |
2002 | 2003 | ||
2003 | ifndef V | 2004 | ifndef V |
2004 | SILENT=@ | 2005 | SILENT=@ |
diff --git a/tools/creative.c b/tools/creative.c new file mode 100644 index 0000000000..5dc65ab992 --- /dev/null +++ b/tools/creative.c | |||
@@ -0,0 +1,159 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2008 by Maurus Cuelenaere | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
20 | #include "creative.h" | ||
21 | #include "hmac-sha1.h" | ||
22 | #include <stdio.h> | ||
23 | #include <stdbool.h> | ||
24 | |||
25 | /* | ||
26 | Create a Zen Vision:M FRESCUE structure file | ||
27 | */ | ||
28 | |||
29 | |||
30 | static int make_ciff_file(char *inbuf, int length, char *outbuf, int device) | ||
31 | { | ||
32 | memcpy(outbuf, "FFIC", 4); | ||
33 | int2le(length+90, &outbuf[4]); | ||
34 | memcpy(&outbuf[8], "FNIC", 4); | ||
35 | int2le(96, &outbuf[0xC]); | ||
36 | memcpy(&outbuf[0x10], devices[device].cinf, devices[device].cinf_size); | ||
37 | memset(&outbuf[0x10+devices[device].cinf_size], 0, 96 - devices[device].cinf_size); | ||
38 | memcpy(&outbuf[0x70], "ATAD", 4); | ||
39 | int2le(length+32, &outbuf[0x74]); | ||
40 | memcpy(&outbuf[0x78], "H\0j\0u\0k\0e\0b\0o\0x\0\x32\0.\0j\0r\0m", 32); /*Unicode encoded*/ | ||
41 | memcpy(&outbuf[0x98], inbuf, length); | ||
42 | memcpy(&outbuf[0x98+length], "LLUN", 4); | ||
43 | int2le(20, &outbuf[0x98+length+4]); | ||
44 | /* Do checksum */ | ||
45 | char key[20]; | ||
46 | hmac_sha((char*)devices[device].null, strlen(devices[device].null), outbuf, 0x98+length, key, 20); | ||
47 | memcpy(&outbuf[0x98+length+8], key, 20); | ||
48 | return length+0x90+0x1C+8; | ||
49 | } | ||
50 | |||
51 | static int make_jrm_file(char *inbuf, int length, char *outbuf) | ||
52 | { | ||
53 | int i; | ||
54 | unsigned int sum = 0; | ||
55 | /* Calculate checksum for later use in header */ | ||
56 | for(i=0; i<length; i+= 4) | ||
57 | sum += le2int(&inbuf[i]) + (le2int(&inbuf[i])>>16); | ||
58 | |||
59 | /* Clear the header area to zero */ | ||
60 | memset(outbuf, 0, 0x18); | ||
61 | |||
62 | /* Header (EDOC) */ | ||
63 | memcpy(outbuf, "EDOC", 4); | ||
64 | /* Total Size */ | ||
65 | int2le(length+0x20, &outbuf[0x4]); | ||
66 | /* 4 bytes of zero */ | ||
67 | |||
68 | /* Address = 0x900000 */ | ||
69 | int2le(0x900000, &outbuf[0xC]); | ||
70 | /* Size */ | ||
71 | int2le(length, &outbuf[0x10]); | ||
72 | /* Checksum */ | ||
73 | int2le(sum, &outbuf[0x14]); | ||
74 | outbuf[0x16] = 0; | ||
75 | outbuf[0x17] = 0; | ||
76 | /* Data starts here... */ | ||
77 | memcpy(&outbuf[0x18], inbuf, length); | ||
78 | |||
79 | /* Second block starts here ... */ | ||
80 | /* Address = 0x0 */ | ||
81 | /* Size */ | ||
82 | int2le(0x4, &outbuf[0x18+length+0x4]); | ||
83 | /* Checksum */ | ||
84 | outbuf[0x18+length+0x8] = 0xA9; | ||
85 | outbuf[0x18+length+0x9] = 0xD9; | ||
86 | /* Data: MOV PC, 0x900000 */ | ||
87 | outbuf[0x18+length+0xC] = 0x09; | ||
88 | outbuf[0x18+length+0xD] = 0xF6; | ||
89 | outbuf[0x18+length+0xE] = 0xA0; | ||
90 | outbuf[0x18+length+0xF] = 0xE3; | ||
91 | |||
92 | return length+0x18+0x10; | ||
93 | } | ||
94 | |||
95 | int zvm_encode(char *iname, char *oname, int device) | ||
96 | { | ||
97 | size_t len; | ||
98 | int length; | ||
99 | FILE *file; | ||
100 | unsigned char *outbuf; | ||
101 | unsigned char *buf; | ||
102 | int i; | ||
103 | |||
104 | file = fopen(iname, "rb"); | ||
105 | if (!file) { | ||
106 | perror(iname); | ||
107 | return -1; | ||
108 | } | ||
109 | fseek(file, 0, SEEK_END); | ||
110 | length = ftell(file); | ||
111 | |||
112 | fseek(file, 0, SEEK_SET); | ||
113 | |||
114 | buf = (unsigned char*)malloc(length); | ||
115 | if ( !buf ) { | ||
116 | printf("out of memory!\n"); | ||
117 | return -1; | ||
118 | } | ||
119 | |||
120 | len = fread(buf, 1, length, file); | ||
121 | if(len < length) { | ||
122 | perror(iname); | ||
123 | return -2; | ||
124 | } | ||
125 | fclose(file); | ||
126 | |||
127 | outbuf = (unsigned char*)malloc(length+0x300); | ||
128 | if ( !outbuf ) { | ||
129 | free(buf); | ||
130 | printf("out of memory!\n"); | ||
131 | return -1; | ||
132 | } | ||
133 | length = make_jrm_file(buf, len, outbuf); | ||
134 | free(buf); | ||
135 | buf = (unsigned char*)malloc(length+0x200); | ||
136 | memset(buf, 0, length+0x200); | ||
137 | length = make_ciff_file(outbuf, length, buf, device); | ||
138 | free(outbuf); | ||
139 | |||
140 | file = fopen(oname, "wb"); | ||
141 | if (!file) { | ||
142 | free(buf); | ||
143 | perror(oname); | ||
144 | return -3; | ||
145 | } | ||
146 | |||
147 | len = fwrite(buf, 1, length, file); | ||
148 | if(len < length) { | ||
149 | free(buf); | ||
150 | perror(oname); | ||
151 | return -4; | ||
152 | } | ||
153 | |||
154 | free(buf); | ||
155 | |||
156 | fclose(file); | ||
157 | |||
158 | return 0; | ||
159 | } | ||
diff --git a/tools/creative.h b/tools/creative.h new file mode 100644 index 0000000000..c28001a0e7 --- /dev/null +++ b/tools/creative.h | |||
@@ -0,0 +1,53 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2008 by Maurus Cuelenaere | ||
11 | * | ||
12 | * All files in this archive are subject to the GNU General Public License. | ||
13 | * See the file COPYING in the source tree root for full license agreement. | ||
14 | * | ||
15 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
16 | * KIND, either express or implied. | ||
17 | * | ||
18 | ****************************************************************************/ | ||
19 | |||
20 | #ifndef CREATIVE_H_ | ||
21 | #define CREATIVE_H_ | ||
22 | |||
23 | enum | ||
24 | { | ||
25 | ZENVISIONM = 0, | ||
26 | ZENVISIONM60 = 1, | ||
27 | ZENVISION = 2, | ||
28 | ZENV = 3 | ||
29 | }; | ||
30 | |||
31 | static struct device_info | ||
32 | { | ||
33 | const char* cinf; /*Must be Unicode encoded*/ | ||
34 | const int cinf_size; | ||
35 | const char* null; | ||
36 | } device_info; | ||
37 | |||
38 | static const char null_key_v1[] = "CTL:N0MAD|PDE0.SIGN."; | ||
39 | static const char null_key_v2[] = "CTL:N0MAD|PDE0.DPMP."; | ||
40 | static const char null_key_v3[] = "CTL:Z3N07|PDE0.DPMP."; | ||
41 | static const char null_key_v4[] = "CTL:N0MAD|PDE0.DPFP."; | ||
42 | |||
43 | static const struct device_info devices[] = | ||
44 | { | ||
45 | {"C\0r\0e\0a\0t\0i\0v\0e\0 \0Z\0e\0n\0 \0V\0i\0s\0i\0o\0n\0:\0M", 42, null_key_v2}, | ||
46 | {"C\0r\0e\0a\0t\0i\0v\0e\0 \0Z\0e\0n\0 \0V\0i\0s\0i\0o\0n\0:\0M\0 \0G\0o\0!", 50, null_key_v2}, | ||
47 | {"C\0r\0e\0a\0t\0i\0v\0e\0 \0Z\0e\0n\0 \0V\0i\0s\0i\0o\0n\0 \0©\0T\0L", 48, null_key_v2}, | ||
48 | {"C\0r\0e\0a\0t\0i\0v\0e\0 \0Z\0E\0N\0 \0V", 42, null_key_v4} | ||
49 | }; | ||
50 | |||
51 | int zvm_encode(char *iname, char *oname, int device); | ||
52 | |||
53 | #endif /*CREATIVE_H_*/ | ||
diff --git a/tools/hmac-sha1.c b/tools/hmac-sha1.c new file mode 100644 index 0000000000..1b4b3b5abd --- /dev/null +++ b/tools/hmac-sha1.c | |||
@@ -0,0 +1,463 @@ | |||
1 | /* | ||
2 | * sha1.c | ||
3 | * | ||
4 | * Description: | ||
5 | * This file implements the Secure Hashing Algorithm 1 as | ||
6 | * defined in FIPS PUB 180-1 published April 17, 1995. | ||
7 | * | ||
8 | * The SHA-1, produces a 160-bit message digest for a given | ||
9 | * data stream. It should take about 2**n steps to find a | ||
10 | * message with the same digest as a given message and | ||
11 | * 2**(n/2) to find any two messages with the same digest, | ||
12 | * when n is the digest size in bits. Therefore, this | ||
13 | * algorithm can serve as a means of providing a | ||
14 | * "fingerprint" for a message. | ||
15 | * | ||
16 | * Portability Issues: | ||
17 | * SHA-1 is defined in terms of 32-bit "words". This code | ||
18 | * uses <stdint.h> (included via "sha1.h" to define 32 and 8 | ||
19 | * bit unsigned integer types. If your C compiler does not | ||
20 | * support 32 bit unsigned integers, this code is not | ||
21 | * appropriate. | ||
22 | * | ||
23 | * Caveats: | ||
24 | * SHA-1 is designed to work with messages less than 2^64 bits | ||
25 | * long. Although SHA-1 allows a message digest to be generated | ||
26 | * for messages of any number of bits less than 2^64, this | ||
27 | * implementation only works with messages with a length that is | ||
28 | * a multiple of the size of an 8-bit character. | ||
29 | * | ||
30 | */ | ||
31 | |||
32 | #include "hmac-sha1.h" | ||
33 | |||
34 | /* | ||
35 | * Define the SHA1 circular left shift macro | ||
36 | */ | ||
37 | #define SHA1CircularShift(bits,word) \ | ||
38 | (((word) << (bits)) | ((word) >> (32-(bits)))) | ||
39 | |||
40 | /* Local Function Prototyptes */ | ||
41 | void SHA1PadMessage(SHA1Context *); | ||
42 | void SHA1ProcessMessageBlock(SHA1Context *); | ||
43 | |||
44 | /* | ||
45 | * SHA1Reset | ||
46 | * | ||
47 | * Description: | ||
48 | * This function will initialize the SHA1Context in preparation | ||
49 | * for computing a new SHA1 message digest. | ||
50 | * | ||
51 | * Parameters: | ||
52 | * context: [in/out] | ||
53 | * The context to reset. | ||
54 | * | ||
55 | * Returns: | ||
56 | * sha Error Code. | ||
57 | * | ||
58 | */ | ||
59 | int SHA1Reset(SHA1Context *context) | ||
60 | { | ||
61 | if (!context) | ||
62 | { | ||
63 | return shaNull; | ||
64 | } | ||
65 | |||
66 | context->Length_Low = 0; | ||
67 | context->Length_High = 0; | ||
68 | context->Message_Block_Index = 0; | ||
69 | |||
70 | context->Intermediate_Hash[0] = 0x67452301; | ||
71 | context->Intermediate_Hash[1] = 0xEFCDAB89; | ||
72 | context->Intermediate_Hash[2] = 0x98BADCFE; | ||
73 | context->Intermediate_Hash[3] = 0x10325476; | ||
74 | context->Intermediate_Hash[4] = 0xC3D2E1F0; | ||
75 | |||
76 | context->Computed = 0; | ||
77 | context->Corrupted = 0; | ||
78 | |||
79 | return shaSuccess; | ||
80 | } | ||
81 | |||
82 | /* | ||
83 | * SHA1Result | ||
84 | * | ||
85 | * Description: | ||
86 | * This function will return the 160-bit message digest into the | ||
87 | * Message_Digest array provided by the caller. | ||
88 | * NOTE: The first octet of hash is stored in the 0th element, | ||
89 | * the last octet of hash in the 19th element. | ||
90 | * | ||
91 | * Parameters: | ||
92 | * context: [in/out] | ||
93 | * The context to use to calculate the SHA-1 hash. | ||
94 | * Message_Digest: [out] | ||
95 | * Where the digest is returned. | ||
96 | * | ||
97 | * Returns: | ||
98 | * sha Error Code. | ||
99 | * | ||
100 | */ | ||
101 | int SHA1Result( SHA1Context *context, | ||
102 | uint8_t Message_Digest[SHA1HashSize]) | ||
103 | { | ||
104 | int i; | ||
105 | |||
106 | if (!context || !Message_Digest) | ||
107 | { | ||
108 | return shaNull; | ||
109 | } | ||
110 | |||
111 | if (context->Corrupted) | ||
112 | { | ||
113 | return context->Corrupted; | ||
114 | } | ||
115 | |||
116 | if (!context->Computed) | ||
117 | { | ||
118 | SHA1PadMessage(context); | ||
119 | for(i=0; i<64; ++i) | ||
120 | { | ||
121 | /* message may be sensitive, clear it out */ | ||
122 | context->Message_Block[i] = 0; | ||
123 | } | ||
124 | context->Length_Low = 0; /* and clear length */ | ||
125 | context->Length_High = 0; | ||
126 | context->Computed = 1; | ||
127 | } | ||
128 | |||
129 | for(i = 0; i < SHA1HashSize; ++i) | ||
130 | { | ||
131 | Message_Digest[i] = context->Intermediate_Hash[i>>2] | ||
132 | >> 8 * ( 3 - ( i & 0x03 ) ); | ||
133 | } | ||
134 | |||
135 | return shaSuccess; | ||
136 | } | ||
137 | |||
138 | /* | ||
139 | * SHA1Input | ||
140 | * | ||
141 | * Description: | ||
142 | * This function accepts an array of octets as the next portion | ||
143 | * of the message. | ||
144 | * | ||
145 | * Parameters: | ||
146 | * context: [in/out] | ||
147 | * The SHA context to update | ||
148 | * message_array: [in] | ||
149 | * An array of characters representing the next portion of | ||
150 | * the message. | ||
151 | * length: [in] | ||
152 | * The length of the message in message_array | ||
153 | * | ||
154 | * Returns: | ||
155 | * sha Error Code. | ||
156 | * | ||
157 | */ | ||
158 | int SHA1Input( SHA1Context *context, | ||
159 | const uint8_t *message_array, | ||
160 | unsigned length) | ||
161 | { | ||
162 | if (!length) | ||
163 | { | ||
164 | return shaSuccess; | ||
165 | } | ||
166 | |||
167 | if (!context || !message_array) | ||
168 | { | ||
169 | return shaNull; | ||
170 | } | ||
171 | |||
172 | if (context->Computed) | ||
173 | { | ||
174 | context->Corrupted = shaStateError; | ||
175 | return shaStateError; | ||
176 | } | ||
177 | |||
178 | if (context->Corrupted) | ||
179 | { | ||
180 | return context->Corrupted; | ||
181 | } | ||
182 | while(length-- && !context->Corrupted) | ||
183 | { | ||
184 | context->Message_Block[context->Message_Block_Index++] = | ||
185 | (*message_array & 0xFF); | ||
186 | |||
187 | context->Length_Low += 8; | ||
188 | if (context->Length_Low == 0) | ||
189 | { | ||
190 | context->Length_High++; | ||
191 | if (context->Length_High == 0) | ||
192 | { | ||
193 | /* Message is too long */ | ||
194 | context->Corrupted = 1; | ||
195 | } | ||
196 | } | ||
197 | |||
198 | if (context->Message_Block_Index == 64) | ||
199 | { | ||
200 | SHA1ProcessMessageBlock(context); | ||
201 | } | ||
202 | |||
203 | message_array++; | ||
204 | } | ||
205 | |||
206 | return shaSuccess; | ||
207 | } | ||
208 | |||
209 | /* | ||
210 | * SHA1ProcessMessageBlock | ||
211 | * | ||
212 | * Description: | ||
213 | * This function will process the next 512 bits of the message | ||
214 | * stored in the Message_Block array. | ||
215 | * | ||
216 | * Parameters: | ||
217 | * None. | ||
218 | * | ||
219 | * Returns: | ||
220 | * Nothing. | ||
221 | * | ||
222 | * Comments: | ||
223 | * Many of the variable names in this code, especially the | ||
224 | * single character names, were used because those were the | ||
225 | * names used in the publication. | ||
226 | * | ||
227 | * | ||
228 | */ | ||
229 | void SHA1ProcessMessageBlock(SHA1Context *context) | ||
230 | { | ||
231 | const uint32_t K[] = { /* Constants defined in SHA-1 */ | ||
232 | 0x5A827999, | ||
233 | 0x6ED9EBA1, | ||
234 | 0x8F1BBCDC, | ||
235 | 0xCA62C1D6 | ||
236 | }; | ||
237 | int t; /* Loop counter */ | ||
238 | uint32_t temp; /* Temporary word value */ | ||
239 | uint32_t W[80]; /* Word sequence */ | ||
240 | uint32_t A, B, C, D, E; /* Word buffers */ | ||
241 | |||
242 | /* | ||
243 | * Initialize the first 16 words in the array W | ||
244 | */ | ||
245 | for(t = 0; t < 16; t++) | ||
246 | { | ||
247 | W[t] = context->Message_Block[t * 4] << 24; | ||
248 | W[t] |= context->Message_Block[t * 4 + 1] << 16; | ||
249 | W[t] |= context->Message_Block[t * 4 + 2] << 8; | ||
250 | W[t] |= context->Message_Block[t * 4 + 3]; | ||
251 | } | ||
252 | |||
253 | for(t = 16; t < 80; t++) | ||
254 | { | ||
255 | W[t] = SHA1CircularShift(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); | ||
256 | } | ||
257 | |||
258 | A = context->Intermediate_Hash[0]; | ||
259 | B = context->Intermediate_Hash[1]; | ||
260 | C = context->Intermediate_Hash[2]; | ||
261 | D = context->Intermediate_Hash[3]; | ||
262 | E = context->Intermediate_Hash[4]; | ||
263 | |||
264 | for(t = 0; t < 20; t++) | ||
265 | { | ||
266 | temp = SHA1CircularShift(5,A) + | ||
267 | ((B & C) | ((~B) & D)) + E + W[t] + K[0]; | ||
268 | E = D; | ||
269 | D = C; | ||
270 | C = SHA1CircularShift(30,B); | ||
271 | B = A; | ||
272 | A = temp; | ||
273 | } | ||
274 | |||
275 | for(t = 20; t < 40; t++) | ||
276 | { | ||
277 | temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[1]; | ||
278 | E = D; | ||
279 | D = C; | ||
280 | C = SHA1CircularShift(30,B); | ||
281 | B = A; | ||
282 | A = temp; | ||
283 | } | ||
284 | |||
285 | for(t = 40; t < 60; t++) | ||
286 | { | ||
287 | temp = SHA1CircularShift(5,A) + | ||
288 | ((B & C) | (B & D) | (C & D)) + E + W[t] + K[2]; | ||
289 | E = D; | ||
290 | D = C; | ||
291 | C = SHA1CircularShift(30,B); | ||
292 | B = A; | ||
293 | A = temp; | ||
294 | } | ||
295 | |||
296 | for(t = 60; t < 80; t++) | ||
297 | { | ||
298 | temp = SHA1CircularShift(5,A) + (B ^ C ^ D) + E + W[t] + K[3]; | ||
299 | E = D; | ||
300 | D = C; | ||
301 | C = SHA1CircularShift(30,B); | ||
302 | B = A; | ||
303 | A = temp; | ||
304 | } | ||
305 | |||
306 | context->Intermediate_Hash[0] += A; | ||
307 | context->Intermediate_Hash[1] += B; | ||
308 | context->Intermediate_Hash[2] += C; | ||
309 | context->Intermediate_Hash[3] += D; | ||
310 | context->Intermediate_Hash[4] += E; | ||
311 | |||
312 | context->Message_Block_Index = 0; | ||
313 | } | ||
314 | |||
315 | |||
316 | /* | ||
317 | * SHA1PadMessage | ||
318 | * | ||
319 | * Description: | ||
320 | * According to the standard, the message must be padded to an even | ||
321 | * 512 bits. The first padding bit must be a '1'. The last 64 | ||
322 | * bits represent the length of the original message. All bits in | ||
323 | * between should be 0. This function will pad the message | ||
324 | * according to those rules by filling the Message_Block array | ||
325 | * accordingly. It will also call the ProcessMessageBlock function | ||
326 | * provided appropriately. When it returns, it can be assumed that | ||
327 | * the message digest has been computed. | ||
328 | * | ||
329 | * Parameters: | ||
330 | * context: [in/out] | ||
331 | * The context to pad | ||
332 | * ProcessMessageBlock: [in] | ||
333 | * The appropriate SHA*ProcessMessageBlock function | ||
334 | * Returns: | ||
335 | * Nothing. | ||
336 | * | ||
337 | */ | ||
338 | |||
339 | void SHA1PadMessage(SHA1Context *context) | ||
340 | { | ||
341 | /* | ||
342 | * Check to see if the current message block is too small to hold | ||
343 | * the initial padding bits and length. If so, we will pad the | ||
344 | * block, process it, and then continue padding into a second | ||
345 | * block. | ||
346 | */ | ||
347 | if (context->Message_Block_Index > 55) | ||
348 | { | ||
349 | context->Message_Block[context->Message_Block_Index++] = 0x80; | ||
350 | while(context->Message_Block_Index < 64) | ||
351 | { | ||
352 | context->Message_Block[context->Message_Block_Index++] = 0; | ||
353 | } | ||
354 | |||
355 | SHA1ProcessMessageBlock(context); | ||
356 | |||
357 | while(context->Message_Block_Index < 56) | ||
358 | { | ||
359 | context->Message_Block[context->Message_Block_Index++] = 0; | ||
360 | } | ||
361 | } | ||
362 | else | ||
363 | { | ||
364 | context->Message_Block[context->Message_Block_Index++] = 0x80; | ||
365 | while(context->Message_Block_Index < 56) | ||
366 | { | ||
367 | context->Message_Block[context->Message_Block_Index++] = 0; | ||
368 | } | ||
369 | } | ||
370 | |||
371 | /* | ||
372 | * Store the message length as the last 8 octets | ||
373 | */ | ||
374 | context->Message_Block[56] = context->Length_High >> 24; | ||
375 | context->Message_Block[57] = context->Length_High >> 16; | ||
376 | context->Message_Block[58] = context->Length_High >> 8; | ||
377 | context->Message_Block[59] = context->Length_High; | ||
378 | context->Message_Block[60] = context->Length_Low >> 24; | ||
379 | context->Message_Block[61] = context->Length_Low >> 16; | ||
380 | context->Message_Block[62] = context->Length_Low >> 8; | ||
381 | context->Message_Block[63] = context->Length_Low; | ||
382 | |||
383 | SHA1ProcessMessageBlock(context); | ||
384 | } | ||
385 | #define SHA_DIGESTSIZE 20 | ||
386 | |||
387 | #define SHA_BLOCKSIZE 64 | ||
388 | |||
389 | static void truncate | ||
390 | ( | ||
391 | char* d1, /* data to be truncated */ | ||
392 | char* d2, /* truncated data */ | ||
393 | int len /* length in bytes to keep */ | ||
394 | ) | ||
395 | { | ||
396 | int i ; | ||
397 | for (i = 0 ; i < len ; i++) d2[i] = d1[i]; | ||
398 | } | ||
399 | |||
400 | |||
401 | /* Function to compute the digest */ | ||
402 | void | ||
403 | hmac_sha | ||
404 | ( | ||
405 | char* k, /* secret key */ | ||
406 | int lk, /* length of the key in bytes */ | ||
407 | char* d, /* data */ | ||
408 | int ld, /* length of data in bytes */ | ||
409 | char* out, /* output buffer, at least "t" bytes */ | ||
410 | int t | ||
411 | ) | ||
412 | { | ||
413 | SHA1Context ictx, octx ; | ||
414 | char isha[SHA_DIGESTSIZE], osha[SHA_DIGESTSIZE] ; | ||
415 | char key[SHA_DIGESTSIZE] ; | ||
416 | char buf[SHA_BLOCKSIZE] ; | ||
417 | int i ; | ||
418 | |||
419 | if (lk > SHA_BLOCKSIZE) { | ||
420 | |||
421 | SHA1Context tctx ; | ||
422 | |||
423 | SHA1Reset(&tctx) ; | ||
424 | SHA1Input(&tctx, k, lk) ; | ||
425 | SHA1Result(&tctx, key) ; | ||
426 | |||
427 | k = key ; | ||
428 | lk = SHA_DIGESTSIZE ; | ||
429 | } | ||
430 | |||
431 | /**** Inner Digest ****/ | ||
432 | |||
433 | SHA1Reset(&ictx) ; | ||
434 | |||
435 | /* Pad the key for inner digest */ | ||
436 | for (i = 0 ; i < lk ; ++i) buf[i] = k[i] ^ 0x36 ; | ||
437 | for (i = lk ; i < SHA_BLOCKSIZE ; ++i) buf[i] = 0x36 ; | ||
438 | |||
439 | SHA1Input(&ictx, buf, SHA_BLOCKSIZE) ; | ||
440 | SHA1Input(&ictx, d, ld) ; | ||
441 | |||
442 | SHA1Result(&ictx, isha) ; | ||
443 | |||
444 | /**** Outter Digest ****/ | ||
445 | |||
446 | SHA1Reset(&octx) ; | ||
447 | |||
448 | /* Pad the key for outter digest */ | ||
449 | |||
450 | |||
451 | for (i = 0 ; i < lk ; ++i) buf[i] = k[i] ^ 0x5C ; | ||
452 | for (i = lk ; i < SHA_BLOCKSIZE ; ++i) buf[i] = 0x5C ; | ||
453 | |||
454 | SHA1Input(&octx, buf, SHA_BLOCKSIZE) ; | ||
455 | SHA1Input(&octx, isha, SHA_DIGESTSIZE) ; | ||
456 | |||
457 | SHA1Result(&octx, osha) ; | ||
458 | |||
459 | /* truncate and print the results */ | ||
460 | t = t > SHA_DIGESTSIZE ? SHA_DIGESTSIZE : t ; | ||
461 | truncate(osha, out, t) ; | ||
462 | |||
463 | } | ||
diff --git a/tools/hmac-sha1.h b/tools/hmac-sha1.h new file mode 100644 index 0000000000..149b5bac46 --- /dev/null +++ b/tools/hmac-sha1.h | |||
@@ -0,0 +1,84 @@ | |||
1 | /* | ||
2 | * sha1.h | ||
3 | * | ||
4 | * Description: | ||
5 | * This is the header file for code which implements the Secure | ||
6 | * Hashing Algorithm 1 as defined in FIPS PUB 180-1 published | ||
7 | * April 17, 1995. | ||
8 | * | ||
9 | * Many of the variable names in this code, especially the | ||
10 | * single character names, were used because those were the names | ||
11 | * used in the publication. | ||
12 | * | ||
13 | * Please read the file sha1.c for more information. | ||
14 | * | ||
15 | */ | ||
16 | |||
17 | #ifndef _SHA1_H_ | ||
18 | #define _SHA1_H_ | ||
19 | |||
20 | #include <stdint.h> | ||
21 | /* | ||
22 | * If you do not have the ISO standard stdint.h header file, then you | ||
23 | * must typdef the following: | ||
24 | * name meaning | ||
25 | * uint32_t unsigned 32 bit integer | ||
26 | * uint8_t unsigned 8 bit integer (i.e., unsigned char) | ||
27 | * int_least16_t integer of >= 16 bits | ||
28 | * | ||
29 | */ | ||
30 | |||
31 | #ifndef _SHA_enum_ | ||
32 | #define _SHA_enum_ | ||
33 | enum | ||
34 | { | ||
35 | shaSuccess = 0, | ||
36 | shaNull, /* Null pointer parameter */ | ||
37 | shaInputTooLong, /* input data too long */ | ||
38 | shaStateError /* called Input after Result */ | ||
39 | }; | ||
40 | #endif | ||
41 | #define SHA1HashSize 20 | ||
42 | |||
43 | /* | ||
44 | * This structure will hold context information for the SHA-1 | ||
45 | * hashing operation | ||
46 | */ | ||
47 | typedef struct SHA1Context | ||
48 | { | ||
49 | uint32_t Intermediate_Hash[SHA1HashSize/4]; /* Message Digest */ | ||
50 | |||
51 | uint32_t Length_Low; /* Message length in bits */ | ||
52 | uint32_t Length_High; /* Message length in bits */ | ||
53 | |||
54 | /* Index into message block array */ | ||
55 | int_least16_t Message_Block_Index; | ||
56 | uint8_t Message_Block[64]; /* 512-bit message blocks */ | ||
57 | |||
58 | int Computed; /* Is the digest computed? */ | ||
59 | int Corrupted; /* Is the message digest corrupted? */ | ||
60 | } SHA1Context; | ||
61 | |||
62 | /* | ||
63 | * Function Prototypes | ||
64 | */ | ||
65 | |||
66 | int SHA1Reset( SHA1Context *); | ||
67 | int SHA1Input( SHA1Context *, | ||
68 | const uint8_t *, | ||
69 | unsigned int); | ||
70 | int SHA1Result( SHA1Context *, | ||
71 | uint8_t Message_Digest[SHA1HashSize]); | ||
72 | |||
73 | void | ||
74 | hmac_sha | ||
75 | ( | ||
76 | char* k, | ||
77 | int lk, | ||
78 | char* d, | ||
79 | int ld, | ||
80 | char* out, | ||
81 | int t | ||
82 | ); | ||
83 | |||
84 | #endif | ||
diff --git a/tools/scramble.c b/tools/scramble.c index b49bde10a2..91f46be816 100644 --- a/tools/scramble.c +++ b/tools/scramble.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include "gigabeats.h" | 26 | #include "gigabeats.h" |
27 | #include "mi4.h" | 27 | #include "mi4.h" |
28 | #include "telechips.h" | 28 | #include "telechips.h" |
29 | #include "creative.h" | ||
29 | #include "iaudio_bl_flash.h" | 30 | #include "iaudio_bl_flash.h" |
30 | 31 | ||
31 | int iaudio_encode(char *iname, char *oname, char *idstring); | 32 | int iaudio_encode(char *iname, char *oname, char *idstring); |
@@ -102,7 +103,7 @@ void usage(void) | |||
102 | "\t-ipod3g ipod firmware partition format (3rd Gen)\n" | 103 | "\t-ipod3g ipod firmware partition format (3rd Gen)\n" |
103 | "\t-ipod4g ipod firmware partition format (4th Gen, Mini, Nano, Photo/Color)\n" | 104 | "\t-ipod4g ipod firmware partition format (4th Gen, Mini, Nano, Photo/Color)\n" |
104 | "\t-ipod5g ipod firmware partition format (5th Gen - aka Video)\n" | 105 | "\t-ipod5g ipod firmware partition format (5th Gen - aka Video)\n" |
105 | "\t-zvm Zen Vision:M FRESCUE structure format\n" | 106 | "\t-creative=X Creative firmware structure format\n" |
106 | "\t-gigabeat Toshiba Gigabeat F/X format\n" | 107 | "\t-gigabeat Toshiba Gigabeat F/X format\n" |
107 | "\t-gigabeats Toshiba Gigabeat S format\n" | 108 | "\t-gigabeats Toshiba Gigabeat S format\n" |
108 | "\t-mi4v2 PortalPlayer .mi4 format (revision 010201)\n" | 109 | "\t-mi4v2 PortalPlayer .mi4 format (revision 010201)\n" |
@@ -332,10 +333,21 @@ int main (int argc, char** argv) | |||
332 | oname = argv[3]; | 333 | oname = argv[3]; |
333 | return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */ | 334 | return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */ |
334 | } | 335 | } |
335 | else if(!strcmp(argv[1], "-zvm")) { | 336 | else if(!strncmp(argv[1], "-creative=", 10)) { |
336 | iname = argv[2]; | 337 | iname = argv[2]; |
337 | oname = argv[3]; | 338 | oname = argv[3]; |
338 | return zvm_encode(iname, oname); | 339 | if(!strcmp(&argv[1][10], "zvm")) |
340 | return zvm_encode(iname, oname, ZENVISIONM); | ||
341 | else if(!strcmp(&argv[1][10], "zvm60")) | ||
342 | return zvm_encode(iname, oname, ZENVISIONM60); | ||
343 | else if(!strcmp(&argv[1][10], "zenvision")) | ||
344 | return zvm_encode(iname, oname, ZENVISION); | ||
345 | else if(!strcmp(&argv[1][10], "zenv")) | ||
346 | return zvm_encode(iname, oname, ZENV); | ||
347 | else { | ||
348 | fprintf(stderr, "unsupported Creative device: %s\n", &argv[1][10]); | ||
349 | return 2; | ||
350 | } | ||
339 | } | 351 | } |
340 | else if(!strncmp(argv[1], "-mi4", 4)) { | 352 | else if(!strncmp(argv[1], "-mi4", 4)) { |
341 | int mi4magic; | 353 | int mi4magic; |
@@ -752,96 +764,3 @@ int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc) | |||
752 | return 0; | 764 | return 0; |
753 | } | 765 | } |
754 | 766 | ||
755 | |||
756 | /* Create an Zen Vision:M FRESCUE structure file | ||
757 | */ | ||
758 | |||
759 | int zvm_encode(char *iname, char *oname) | ||
760 | { | ||
761 | size_t len; | ||
762 | int length; | ||
763 | FILE *file; | ||
764 | unsigned int sum = 0; | ||
765 | unsigned char *outbuf; | ||
766 | int i; | ||
767 | |||
768 | file = fopen(iname, "rb"); | ||
769 | if (!file) { | ||
770 | perror(iname); | ||
771 | return -1; | ||
772 | } | ||
773 | fseek(file,0,SEEK_END); | ||
774 | length = ftell(file); | ||
775 | |||
776 | fseek(file,0,SEEK_SET); | ||
777 | |||
778 | outbuf = malloc(length+0x18+0x10); | ||
779 | |||
780 | if ( !outbuf ) { | ||
781 | printf("out of memory!\n"); | ||
782 | return -1; | ||
783 | } | ||
784 | |||
785 | len = fread(outbuf+0x18, 1, length, file); | ||
786 | if(len < length) { | ||
787 | perror(iname); | ||
788 | return -2; | ||
789 | } | ||
790 | fclose(file); | ||
791 | |||
792 | /* Calculate checksum for later use in header */ | ||
793 | for(i=0; i<length; i+= 4) | ||
794 | sum += le2int(&outbuf[0x18+i]) + (le2int(&outbuf[0x18+i])>>16); | ||
795 | |||
796 | /* Clear the header area to zero */ | ||
797 | memset(outbuf, 0, 0x18); | ||
798 | |||
799 | /* Header (EDOC) */ | ||
800 | memcpy((char*)outbuf, "EDOC", 4); | ||
801 | /* Total Size */ | ||
802 | int2le(length+0x20, &outbuf[0x4]); | ||
803 | /* 4 bytes of zero */ | ||
804 | |||
805 | /* Address = 0x900000 */ | ||
806 | int2le(0x900000, &outbuf[0xC]); | ||
807 | /* Size */ | ||
808 | int2le(length, &outbuf[0x10]); | ||
809 | /* Checksum */ | ||
810 | int2le(sum, &outbuf[0x14]); | ||
811 | outbuf[0x16] = 0; | ||
812 | outbuf[0x17] = 0; | ||
813 | /* Data starts here... */ | ||
814 | |||
815 | /* Second block starts here ... */ | ||
816 | /* Address = 0x0 */ | ||
817 | /* Size */ | ||
818 | int2le(0x4, &outbuf[0x18+length+0x4]); | ||
819 | /* Checksum */ | ||
820 | outbuf[0x18+length+0x8] = 0xB7; | ||
821 | outbuf[0x18+length+0x9] = 0xD5; | ||
822 | /* Data: LDR PC, =0x900000 */ | ||
823 | outbuf[0x18+length+0xC] = 0x18; | ||
824 | outbuf[0x18+length+0xD] = 0xF0; | ||
825 | outbuf[0x18+length+0xE] = 0x9F; | ||
826 | outbuf[0x18+length+0xF] = 0xE5; | ||
827 | |||
828 | |||
829 | file = fopen(oname, "wb"); | ||
830 | if (!file) { | ||
831 | perror(oname); | ||
832 | return -3; | ||
833 | } | ||
834 | |||
835 | len = fwrite(outbuf, 1, length+0x28, file); | ||
836 | if(len < length+0x18) { | ||
837 | perror(oname); | ||
838 | return -4; | ||
839 | } | ||
840 | |||
841 | free(outbuf); | ||
842 | |||
843 | fclose(file); | ||
844 | |||
845 | return 0; | ||
846 | } | ||
847 | |||