summaryrefslogtreecommitdiff
path: root/utils/ipodpatcher/ipodpatcher.c
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 /utils/ipodpatcher/ipodpatcher.c
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
Diffstat (limited to 'utils/ipodpatcher/ipodpatcher.c')
-rw-r--r--utils/ipodpatcher/ipodpatcher.c355
1 files changed, 0 insertions, 355 deletions
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