summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDominik Riebeling <Dominik.Riebeling@gmail.com>2022-03-11 20:34:50 +0100
committerDominik Riebeling <Dominik.Riebeling@gmail.com>2022-03-12 20:40:08 +0100
commit748b00a7fcd0e9d820fd04fdf13422eaad4c2dd4 (patch)
tree521962473cf2b3b0f563a42bced3b5a6eef2aac0
parent08afedf1f51194eea3c121245cfdfba7bb936323 (diff)
downloadrockbox-748b00a7fcd0e9d820fd04fdf13422eaad4c2dd4.tar.gz
rockbox-748b00a7fcd0e9d820fd04fdf13422eaad4c2dd4.zip
ipodpatcher: Split executable only parts out.
Allow building both as library and executable at the same time. Change-Id: Idc40354fdedaeace727043936352fc17232bf16e
-rw-r--r--utils/CMakeLists.txt11
-rw-r--r--utils/ipodpatcher/ipodpatcher-aupd.c398
-rw-r--r--utils/ipodpatcher/ipodpatcher.c355
3 files changed, 409 insertions, 355 deletions
diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt
index 9797d020d3..d874f083b5 100644
--- a/utils/CMakeLists.txt
+++ b/utils/CMakeLists.txt
@@ -82,6 +82,17 @@ if(APPLE)
82endif() 82endif()
83 83
84 84
85add_executable(ipodpatcher-bin
86 ipodpatcher/main.c
87 ipodpatcher/ipodpatcher-aupd.c
88 )
89target_link_libraries(ipodpatcher-bin ipodpatcher)
90target_compile_definitions(ipodpatcher-bin PRIVATE VERSION="none")
91set_target_properties(ipodpatcher-bin PROPERTIES OUTPUT_NAME ipodpatcher)
92if(APPLE)
93 target_link_libraries(ipodpatcher-bin ${FRAMEWORK_IOKIT} ${FRAMEWORK_COREFOUNDATION})
94endif()
95
85add_library(ipodpatcher 96add_library(ipodpatcher
86 ipodpatcher/arc4.h 97 ipodpatcher/arc4.h
87 ipodpatcher/arc4.c 98 ipodpatcher/arc4.c
diff --git a/utils/ipodpatcher/ipodpatcher-aupd.c b/utils/ipodpatcher/ipodpatcher-aupd.c
new file mode 100644
index 0000000000..69b027284c
--- /dev/null
+++ b/utils/ipodpatcher/ipodpatcher-aupd.c
@@ -0,0 +1,398 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2006-2007 Dave Chapman
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
22#include <stdio.h>
23#include <unistd.h>
24#include <fcntl.h>
25#include <string.h>
26#include <stdlib.h>
27#include <inttypes.h>
28#include <stdbool.h>
29#include <sys/types.h>
30#include <sys/stat.h>
31
32#include "ipodpatcher.h"
33
34#include "arc4.h"
35
36static inline int le2int(unsigned char* buf)
37{
38 int32_t res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
39
40 return res;
41}
42
43static inline void int2le(unsigned int val, unsigned char* addr)
44{
45 addr[0] = val & 0xFF;
46 addr[1] = (val >> 8) & 0xff;
47 addr[2] = (val >> 16) & 0xff;
48 addr[3] = (val >> 24) & 0xff;
49}
50
51static inline uint32_t getuint32le(unsigned char* buf)
52{
53 int32_t res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
54
55 return res;
56}
57
58/* testMarker and GetSecurityBlockKey based on code from BadBlocks and
59 Kingstone, posted at http://ipodlinux.org/Flash_Decryption
60
61*/
62
63static bool testMarker(int marker)
64{
65 int mask, decrypt, temp1, temp2;
66
67 mask = (marker&0xff)|((marker&0xff)<<8)|((marker&0xff)<<16)|((marker&0xff)<<24);
68 decrypt = marker ^ mask;
69 temp1=(int)((unsigned int)decrypt>>24);
70 temp2=decrypt<<8;
71
72 if (temp1==0)
73 return false;
74
75 temp2=(int)((unsigned int)temp2>>24);
76 decrypt=decrypt<<16;
77 decrypt=(int)((unsigned int)decrypt>>24);
78
79 if ((temp1 < temp2) && (temp2 < decrypt))
80 {
81 temp1 = temp1 & 0xf;
82 temp2 = temp2 & 0xf;
83 decrypt = decrypt & 0xf;
84
85 if ((temp1 > temp2) && (temp2 > decrypt) && (decrypt != 0))
86 {
87 return true;
88 }
89 }
90 return false;
91}
92
93static int GetSecurityBlockKey(unsigned char *data, unsigned char* this_key)
94{
95 int constant = 0x54c3a298;
96 int key=0;
97 int nkeys = 0;
98 int aMarker=0;
99 int pos=0;
100 int c, count;
101 int temp1;
102 static const int offset[8]={0x5,0x25,0x6f,0x69,0x15,0x4d,0x40,0x34};
103
104 for (c = 0; c < 8; c++)
105 {
106 pos = offset[c]*4;
107 aMarker = getuint32le(data + pos);
108
109 if (testMarker(aMarker))
110 {
111 if (c<7)
112 pos =(offset[c+1]*4)+4;
113 else
114 pos =(offset[0]*4)+4;
115
116 key=0;
117
118 temp1=aMarker;
119
120 for (count=0;count<2;count++){
121 int word = getuint32le(data + pos);
122 temp1 = aMarker;
123 temp1 = temp1^word;
124 temp1 = temp1^constant;
125 key = temp1;
126 pos = pos+4;
127 }
128 int r1=0x6f;
129 int r2=0;
130 int r12;
131 int r14;
132 unsigned int r_tmp;
133
134 for (count=2;count<128;count=count+2){
135 r2=getuint32le(data+count*4);
136 r12=getuint32le(data+(count*4)+4);
137 r_tmp=(unsigned int)r12>>16;
138 r14=r2 | ((int)r_tmp);
139 r2=r2&0xffff;
140 r2=r2 | r12;
141 r1=r1^r14;
142 r1=r1+r2;
143 }
144 key=key^r1;
145
146 // Invert key, little endian
147 this_key[0] = key & 0xff;
148 this_key[1] = (key >> 8) & 0xff;
149 this_key[2] = (key >> 16) & 0xff;
150 this_key[3] = (key >> 24) & 0xff;
151 nkeys++;
152 }
153 }
154 return nkeys;
155}
156
157static int find_key(struct ipod_t* ipod, int aupd, unsigned char* key)
158{
159 int n;
160
161 /* Firstly read the security block and find the RC4 key. This is
162 in the sector preceeding the AUPD image. */
163
164 if(ipod->sectorbuf == NULL) {
165 fprintf(stderr,"[ERR] Buffer not initialized.");
166 return -1;
167 }
168 fprintf(stderr, "[INFO] Reading security block at offset 0x%08x\n",ipod->ipod_directory[aupd].devOffset-ipod->sector_size);
169 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[aupd].devOffset-ipod->sector_size) < 0) {
170 return -1;
171 }
172
173 if ((n = ipod_read(ipod, 512)) < 0) {
174 return -1;
175 }
176
177 n = GetSecurityBlockKey(ipod->sectorbuf, key);
178
179 if (n != 1)
180 {
181 fprintf(stderr, "[ERR] %d keys found in security block, can not continue\n",n);
182 return -1;
183 }
184
185 return 0;
186}
187
188int read_aupd(struct ipod_t* ipod, char* filename)
189{
190 int length;
191 int i;
192 int outfile;
193 int n;
194 int aupd;
195 struct rc4_key_t rc4;
196 unsigned char key[4];
197 unsigned long chksum=0;
198
199 if(ipod->sectorbuf == NULL) {
200 fprintf(stderr,"[ERR] Buffer not initialized.");
201 return -1;
202 }
203 aupd = 0;
204 while ((aupd < ipod->nimages) && (ipod->ipod_directory[aupd].ftype != FTYPE_AUPD))
205 {
206 aupd++;
207 }
208
209 if (aupd == ipod->nimages)
210 {
211 fprintf(stderr,"[ERR] No AUPD image in firmware partition.\n");
212 return -1;
213 }
214
215 length = ipod->ipod_directory[aupd].len;
216
217 fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length);
218
219 if (find_key(ipod, aupd, key) < 0)
220 {
221 return -1;
222 }
223
224 fprintf(stderr, "[INFO] Decrypting AUPD image with key %02x%02x%02x%02x\n",key[0],key[1],key[2],key[3]);
225
226 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[aupd].devOffset) < 0) {
227 return -1;
228 }
229
230 i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1);
231
232 if ((n = ipod_read(ipod,i)) < 0) {
233 return -1;
234 }
235
236 if (n < i) {
237 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
238 i,n);
239 return -1;
240 }
241
242 /* Perform the decryption - this is standard (A)RC4 */
243 matrixArc4Init(&rc4, key, 4);
244 matrixArc4(&rc4, ipod->sectorbuf, ipod->sectorbuf, length);
245
246 chksum = 0;
247 for (i = 0; i < (int)length; i++) {
248 /* add 8 unsigned bits but keep a 32 bit sum */
249 chksum += ipod->sectorbuf[i];
250 }
251
252 if (chksum != ipod->ipod_directory[aupd].chksum)
253 {
254 fprintf(stderr,"[ERR] Decryption failed - checksum error\n");
255 return -1;
256 }
257 fprintf(stderr,"[INFO] Decrypted OK (checksum matches header)\n");
258
259 outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0666);
260 if (outfile < 0) {
261 fprintf(stderr,"[ERR] Couldn't open file %s\n",filename);
262 return -1;
263 }
264
265 n = write(outfile,ipod->sectorbuf,length);
266 if (n != length) {
267 fprintf(stderr,"[ERR] Write error - %d\n",n);
268 }
269 close(outfile);
270
271 return 0;
272}
273
274int write_aupd(struct ipod_t* ipod, char* filename)
275{
276 unsigned int length;
277 int i;
278 int x;
279 int n;
280 int infile;
281 int newsize;
282 int aupd;
283 unsigned long chksum=0;
284 struct rc4_key_t rc4;
285 unsigned char key[4];
286
287 if(ipod->sectorbuf == NULL) {
288 fprintf(stderr,"[ERR] Buffer not initialized.");
289 return -1;
290 }
291 /* First check that the input file is the correct type for this ipod. */
292 infile=open(filename,O_RDONLY);
293 if (infile < 0) {
294 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
295 return -1;
296 }
297
298 length = filesize(infile);
299 newsize=(length+ipod->sector_size-1)&~(ipod->sector_size-1);
300
301 fprintf(stderr,"[INFO] Padding input file from 0x%08x to 0x%08x bytes\n",
302 length,newsize);
303
304 if (newsize > BUFFER_SIZE) {
305 fprintf(stderr,"[ERR] Input file too big for buffer\n");
306 if (infile >= 0) close(infile);
307 return -1;
308 }
309
310 /* Find aupd image number */
311 aupd = 0;
312 while ((aupd < ipod->nimages) && (ipod->ipod_directory[aupd].ftype != FTYPE_AUPD))
313 {
314 aupd++;
315 }
316
317 if (aupd == ipod->nimages)
318 {
319 fprintf(stderr,"[ERR] No AUPD image in firmware partition.\n");
320 return -1;
321 }
322
323 if (length != ipod->ipod_directory[aupd].len)
324 {
325 fprintf(stderr,"[ERR] AUPD image (%d bytes) differs in size to %s (%d bytes).\n",
326 ipod->ipod_directory[aupd].len, filename, length);
327 return -1;
328 }
329
330 if (find_key(ipod, aupd, key) < 0)
331 {
332 return -1;
333 }
334
335 fprintf(stderr, "[INFO] Encrypting AUPD image with key %02x%02x%02x%02x\n",key[0],key[1],key[2],key[3]);
336
337 /* We now know we have enough space, so write it. */
338
339 fprintf(stderr,"[INFO] Reading input file...\n");
340 n = read(infile,ipod->sectorbuf,length);
341 if (n < 0) {
342 fprintf(stderr,"[ERR] Couldn't read input file\n");
343 close(infile);
344 return -1;
345 }
346 close(infile);
347
348 /* Pad the data with zeros */
349 memset(ipod->sectorbuf+length,0,newsize-length);
350
351 /* Calculate the new checksum (before we encrypt) */
352 chksum = 0;
353 for (i = 0; i < (int)length; i++) {
354 /* add 8 unsigned bits but keep a 32 bit sum */
355 chksum += ipod->sectorbuf[i];
356 }
357
358 /* Perform the encryption - this is standard (A)RC4 */
359 matrixArc4Init(&rc4, key, 4);
360 matrixArc4(&rc4, ipod->sectorbuf, ipod->sectorbuf, length);
361
362 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[aupd].devOffset) < 0) {
363 fprintf(stderr,"[ERR] Seek failed\n");
364 return -1;
365 }
366
367 if ((n = ipod_write(ipod,newsize)) < 0) {
368 perror("[ERR] Write failed\n");
369 return -1;
370 }
371
372 if (n < newsize) {
373 fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n"
374 ,newsize,n);
375 return -1;
376 }
377 fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n);
378
379 x = ipod->diroffset % ipod->sector_size;
380
381 /* Read directory */
382 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
383
384 n=ipod_read(ipod, ipod->sector_size);
385 if (n < 0) { return -1; }
386
387 /* Update checksum */
388 fprintf(stderr,"[INFO] Updating checksum to 0x%08x (was 0x%08x)\n",(unsigned int)chksum,le2int(ipod->sectorbuf + x + aupd*40 + 28));
389 int2le(chksum,ipod->sectorbuf+x+aupd*40+28);
390
391 /* Write directory */
392 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
393 n=ipod_write(ipod, ipod->sector_size);
394 if (n < 0) { return -1; }
395
396 return 0;
397}
398
diff --git a/utils/ipodpatcher/ipodpatcher.c b/utils/ipodpatcher/ipodpatcher.c
index e047e52abe..e7c0cc3358 100644
--- a/utils/ipodpatcher/ipodpatcher.c
+++ b/utils/ipodpatcher/ipodpatcher.c
@@ -45,10 +45,6 @@
45#include "ipodnano2g.h" 45#include "ipodnano2g.h"
46#endif 46#endif
47 47
48#ifndef RBUTIL
49#include "arc4.h"
50#endif
51
52int ipod_verbose = 0; 48int ipod_verbose = 0;
53 49
54 50
@@ -1997,354 +1993,3 @@ void ipod_get_ramsize(struct ipod_t* ipod)
1997 } 1993 }
1998} 1994}
1999 1995
2000#ifndef RBUTIL
2001
2002static inline uint32_t getuint32le(unsigned char* buf)
2003{
2004 int32_t res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
2005
2006 return res;
2007}
2008
2009/* testMarker and GetSecurityBlockKey based on code from BadBlocks and
2010 Kingstone, posted at http://ipodlinux.org/Flash_Decryption
2011
2012*/
2013
2014static bool testMarker(int marker)
2015{
2016 int mask, decrypt, temp1, temp2;
2017
2018 mask = (marker&0xff)|((marker&0xff)<<8)|((marker&0xff)<<16)|((marker&0xff)<<24);
2019 decrypt = marker ^ mask;
2020 temp1=(int)((unsigned int)decrypt>>24);
2021 temp2=decrypt<<8;
2022
2023 if (temp1==0)
2024 return false;
2025
2026 temp2=(int)((unsigned int)temp2>>24);
2027 decrypt=decrypt<<16;
2028 decrypt=(int)((unsigned int)decrypt>>24);
2029
2030 if ((temp1 < temp2) && (temp2 < decrypt))
2031 {
2032 temp1 = temp1 & 0xf;
2033 temp2 = temp2 & 0xf;
2034 decrypt = decrypt & 0xf;
2035
2036 if ((temp1 > temp2) && (temp2 > decrypt) && (decrypt != 0))
2037 {
2038 return true;
2039 }
2040 }
2041 return false;
2042}
2043
2044static int GetSecurityBlockKey(unsigned char *data, unsigned char* this_key)
2045{
2046 int constant = 0x54c3a298;
2047 int key=0;
2048 int nkeys = 0;
2049 int aMarker=0;
2050 int pos=0;
2051 int c, count;
2052 int temp1;
2053 static const int offset[8]={0x5,0x25,0x6f,0x69,0x15,0x4d,0x40,0x34};
2054
2055 for (c = 0; c < 8; c++)
2056 {
2057 pos = offset[c]*4;
2058 aMarker = getuint32le(data + pos);
2059
2060 if (testMarker(aMarker))
2061 {
2062 if (c<7)
2063 pos =(offset[c+1]*4)+4;
2064 else
2065 pos =(offset[0]*4)+4;
2066
2067 key=0;
2068
2069 temp1=aMarker;
2070
2071 for (count=0;count<2;count++){
2072 int word = getuint32le(data + pos);
2073 temp1 = aMarker;
2074 temp1 = temp1^word;
2075 temp1 = temp1^constant;
2076 key = temp1;
2077 pos = pos+4;
2078 }
2079 int r1=0x6f;
2080 int r2=0;
2081 int r12;
2082 int r14;
2083 unsigned int r_tmp;
2084
2085 for (count=2;count<128;count=count+2){
2086 r2=getuint32le(data+count*4);
2087 r12=getuint32le(data+(count*4)+4);
2088 r_tmp=(unsigned int)r12>>16;
2089 r14=r2 | ((int)r_tmp);
2090 r2=r2&0xffff;
2091 r2=r2 | r12;
2092 r1=r1^r14;
2093 r1=r1+r2;
2094 }
2095 key=key^r1;
2096
2097 // Invert key, little endian
2098 this_key[0] = key & 0xff;
2099 this_key[1] = (key >> 8) & 0xff;
2100 this_key[2] = (key >> 16) & 0xff;
2101 this_key[3] = (key >> 24) & 0xff;
2102 nkeys++;
2103 }
2104 }
2105 return nkeys;
2106}
2107
2108static int find_key(struct ipod_t* ipod, int aupd, unsigned char* key)
2109{
2110 int n;
2111
2112 /* Firstly read the security block and find the RC4 key. This is
2113 in the sector preceeding the AUPD image. */
2114
2115 if(ipod->sectorbuf == NULL) {
2116 fprintf(stderr,"[ERR] Buffer not initialized.");
2117 return -1;
2118 }
2119 fprintf(stderr, "[INFO] Reading security block at offset 0x%08x\n",ipod->ipod_directory[aupd].devOffset-ipod->sector_size);
2120 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[aupd].devOffset-ipod->sector_size) < 0) {
2121 return -1;
2122 }
2123
2124 if ((n = ipod_read(ipod, 512)) < 0) {
2125 return -1;
2126 }
2127
2128 n = GetSecurityBlockKey(ipod->sectorbuf, key);
2129
2130 if (n != 1)
2131 {
2132 fprintf(stderr, "[ERR] %d keys found in security block, can not continue\n",n);
2133 return -1;
2134 }
2135
2136 return 0;
2137}
2138
2139int read_aupd(struct ipod_t* ipod, char* filename)
2140{
2141 int length;
2142 int i;
2143 int outfile;
2144 int n;
2145 int aupd;
2146 struct rc4_key_t rc4;
2147 unsigned char key[4];
2148 unsigned long chksum=0;
2149
2150 if(ipod->sectorbuf == NULL) {
2151 fprintf(stderr,"[ERR] Buffer not initialized.");
2152 return -1;
2153 }
2154 aupd = 0;
2155 while ((aupd < ipod->nimages) && (ipod->ipod_directory[aupd].ftype != FTYPE_AUPD))
2156 {
2157 aupd++;
2158 }
2159
2160 if (aupd == ipod->nimages)
2161 {
2162 fprintf(stderr,"[ERR] No AUPD image in firmware partition.\n");
2163 return -1;
2164 }
2165
2166 length = ipod->ipod_directory[aupd].len;
2167
2168 fprintf(stderr,"[INFO] Reading firmware (%d bytes)\n",length);
2169
2170 if (find_key(ipod, aupd, key) < 0)
2171 {
2172 return -1;
2173 }
2174
2175 fprintf(stderr, "[INFO] Decrypting AUPD image with key %02x%02x%02x%02x\n",key[0],key[1],key[2],key[3]);
2176
2177 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[aupd].devOffset) < 0) {
2178 return -1;
2179 }
2180
2181 i = (length+ipod->sector_size-1) & ~(ipod->sector_size-1);
2182
2183 if ((n = ipod_read(ipod,i)) < 0) {
2184 return -1;
2185 }
2186
2187 if (n < i) {
2188 fprintf(stderr,"[ERR] Short read - requested %d bytes, received %d\n",
2189 i,n);
2190 return -1;
2191 }
2192
2193 /* Perform the decryption - this is standard (A)RC4 */
2194 matrixArc4Init(&rc4, key, 4);
2195 matrixArc4(&rc4, ipod->sectorbuf, ipod->sectorbuf, length);
2196
2197 chksum = 0;
2198 for (i = 0; i < (int)length; i++) {
2199 /* add 8 unsigned bits but keep a 32 bit sum */
2200 chksum += ipod->sectorbuf[i];
2201 }
2202
2203 if (chksum != ipod->ipod_directory[aupd].chksum)
2204 {
2205 fprintf(stderr,"[ERR] Decryption failed - checksum error\n");
2206 return -1;
2207 }
2208 fprintf(stderr,"[INFO] Decrypted OK (checksum matches header)\n");
2209
2210 outfile = open(filename,O_CREAT|O_TRUNC|O_WRONLY|O_BINARY,0666);
2211 if (outfile < 0) {
2212 fprintf(stderr,"[ERR] Couldn't open file %s\n",filename);
2213 return -1;
2214 }
2215
2216 n = write(outfile,ipod->sectorbuf,length);
2217 if (n != length) {
2218 fprintf(stderr,"[ERR] Write error - %d\n",n);
2219 }
2220 close(outfile);
2221
2222 return 0;
2223}
2224
2225int write_aupd(struct ipod_t* ipod, char* filename)
2226{
2227 unsigned int length;
2228 int i;
2229 int x;
2230 int n;
2231 int infile;
2232 int newsize;
2233 int aupd;
2234 unsigned long chksum=0;
2235 struct rc4_key_t rc4;
2236 unsigned char key[4];
2237
2238 if(ipod->sectorbuf == NULL) {
2239 fprintf(stderr,"[ERR] Buffer not initialized.");
2240 return -1;
2241 }
2242 /* First check that the input file is the correct type for this ipod. */
2243 infile=open(filename,O_RDONLY);
2244 if (infile < 0) {
2245 fprintf(stderr,"[ERR] Couldn't open input file %s\n",filename);
2246 return -1;
2247 }
2248
2249 length = filesize(infile);
2250 newsize=(length+ipod->sector_size-1)&~(ipod->sector_size-1);
2251
2252 fprintf(stderr,"[INFO] Padding input file from 0x%08x to 0x%08x bytes\n",
2253 length,newsize);
2254
2255 if (newsize > BUFFER_SIZE) {
2256 fprintf(stderr,"[ERR] Input file too big for buffer\n");
2257 if (infile >= 0) close(infile);
2258 return -1;
2259 }
2260
2261 /* Find aupd image number */
2262 aupd = 0;
2263 while ((aupd < ipod->nimages) && (ipod->ipod_directory[aupd].ftype != FTYPE_AUPD))
2264 {
2265 aupd++;
2266 }
2267
2268 if (aupd == ipod->nimages)
2269 {
2270 fprintf(stderr,"[ERR] No AUPD image in firmware partition.\n");
2271 return -1;
2272 }
2273
2274 if (length != ipod->ipod_directory[aupd].len)
2275 {
2276 fprintf(stderr,"[ERR] AUPD image (%d bytes) differs in size to %s (%d bytes).\n",
2277 ipod->ipod_directory[aupd].len, filename, length);
2278 return -1;
2279 }
2280
2281 if (find_key(ipod, aupd, key) < 0)
2282 {
2283 return -1;
2284 }
2285
2286 fprintf(stderr, "[INFO] Encrypting AUPD image with key %02x%02x%02x%02x\n",key[0],key[1],key[2],key[3]);
2287
2288 /* We now know we have enough space, so write it. */
2289
2290 fprintf(stderr,"[INFO] Reading input file...\n");
2291 n = read(infile,ipod->sectorbuf,length);
2292 if (n < 0) {
2293 fprintf(stderr,"[ERR] Couldn't read input file\n");
2294 close(infile);
2295 return -1;
2296 }
2297 close(infile);
2298
2299 /* Pad the data with zeros */
2300 memset(ipod->sectorbuf+length,0,newsize-length);
2301
2302 /* Calculate the new checksum (before we encrypt) */
2303 chksum = 0;
2304 for (i = 0; i < (int)length; i++) {
2305 /* add 8 unsigned bits but keep a 32 bit sum */
2306 chksum += ipod->sectorbuf[i];
2307 }
2308
2309 /* Perform the encryption - this is standard (A)RC4 */
2310 matrixArc4Init(&rc4, key, 4);
2311 matrixArc4(&rc4, ipod->sectorbuf, ipod->sectorbuf, length);
2312
2313 if (ipod_seek(ipod, ipod->fwoffset+ipod->ipod_directory[aupd].devOffset) < 0) {
2314 fprintf(stderr,"[ERR] Seek failed\n");
2315 return -1;
2316 }
2317
2318 if ((n = ipod_write(ipod,newsize)) < 0) {
2319 perror("[ERR] Write failed\n");
2320 return -1;
2321 }
2322
2323 if (n < newsize) {
2324 fprintf(stderr,"[ERR] Short write - requested %d bytes, received %d\n"
2325 ,newsize,n);
2326 return -1;
2327 }
2328 fprintf(stderr,"[INFO] Wrote %d bytes to firmware partition\n",n);
2329
2330 x = ipod->diroffset % ipod->sector_size;
2331
2332 /* Read directory */
2333 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
2334
2335 n=ipod_read(ipod, ipod->sector_size);
2336 if (n < 0) { return -1; }
2337
2338 /* Update checksum */
2339 fprintf(stderr,"[INFO] Updating checksum to 0x%08x (was 0x%08x)\n",(unsigned int)chksum,le2int(ipod->sectorbuf + x + aupd*40 + 28));
2340 int2le(chksum,ipod->sectorbuf+x+aupd*40+28);
2341
2342 /* Write directory */
2343 if (ipod_seek(ipod, ipod->start + ipod->diroffset - x) < 0) { return -1; }
2344 n=ipod_write(ipod, ipod->sector_size);
2345 if (n < 0) { return -1; }
2346
2347 return 0;
2348}
2349
2350#endif