summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Chapman <dave@dchapman.com>2009-10-10 11:46:23 +0000
committerDave Chapman <dave@dchapman.com>2009-10-10 11:46:23 +0000
commit4fe2ee02215730c2217135ef1e6dd4585a0c2439 (patch)
tree46a481cd84da1ccf6524c904789ee5bdf2322512
parente51dbc0f4f4779f6d0ea510b487c79faca3c128f (diff)
downloadrockbox-4fe2ee02215730c2217135ef1e6dd4585a0c2439.tar.gz
rockbox-4fe2ee02215730c2217135ef1e6dd4585a0c2439.zip
Add crypt_firmware plugin for Nano2G - this uses the hardware crypto unit to encrypt (or decrypt) a firmware image for writing to a Nano 2G's firmware partition with ipodpatcher (patch for ipodpatcher is at FS#10609). Also introduce BOOTFILE_EXT2 define for an alternative firmware file extension and add .ipodx for the Nano 2G (.ipod is for unencrypted images, similar to older ipods, and .ipodx is for encrypted images and include the 2KB hash block and modelname 'nn2x').
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@23068 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/filetypes.c3
-rw-r--r--apps/plugins/SOURCES4
-rw-r--r--apps/plugins/crypt_firmware.c346
-rw-r--r--apps/plugins/viewers.config2
-rw-r--r--firmware/export/config-ipodnano2g.h3
-rw-r--r--firmware/export/s5l8700.h26
6 files changed, 384 insertions, 0 deletions
diff --git a/apps/filetypes.c b/apps/filetypes.c
index ffa7161693..ed3d938fe9 100644
--- a/apps/filetypes.c
+++ b/apps/filetypes.c
@@ -111,6 +111,9 @@ static const struct filetype inbuilt_filetypes[] = {
111#ifdef BOOTFILE_EXT 111#ifdef BOOTFILE_EXT
112 { BOOTFILE_EXT, FILE_ATTR_MOD, Icon_Firmware, VOICE_EXT_AJZ }, 112 { BOOTFILE_EXT, FILE_ATTR_MOD, Icon_Firmware, VOICE_EXT_AJZ },
113#endif 113#endif
114#ifdef BOOTFILE_EXT2
115 { BOOTFILE_EXT2, FILE_ATTR_MOD, Icon_Firmware, VOICE_EXT_AJZ },
116#endif
114}; 117};
115 118
116void tree_get_filetypes(const struct filetype** types, int* count) 119void tree_get_filetypes(const struct filetype** types, int* count)
diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES
index 4cfc3a8b0f..a15564d0be 100644
--- a/apps/plugins/SOURCES
+++ b/apps/plugins/SOURCES
@@ -29,6 +29,10 @@ firmware_flash.c
29rockbox_flash.c 29rockbox_flash.c
30#endif /* CONFIG_CPU */ 30#endif /* CONFIG_CPU */
31 31
32#if defined(IPOD_NANO2G) && !defined(SIMULATOR)
33crypt_firmware.c
34#endif
35
32#if (CONFIG_CODEC == SWCODEC) && defined(HAVE_RECORDING) && \ 36#if (CONFIG_CODEC == SWCODEC) && defined(HAVE_RECORDING) && \
33 (defined(HAVE_LINE_IN) || defined(HAVE_MIC_IN)) 37 (defined(HAVE_LINE_IN) || defined(HAVE_MIC_IN))
34pitch_detector.c 38pitch_detector.c
diff --git a/apps/plugins/crypt_firmware.c b/apps/plugins/crypt_firmware.c
new file mode 100644
index 0000000000..6bfeeabe00
--- /dev/null
+++ b/apps/plugins/crypt_firmware.c
@@ -0,0 +1,346 @@
1/***************************************************************************
2 *
3 * __________ __ ___.
4 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
5 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
6 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
7 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
8 * \/ \/ \/ \/ \/
9 *
10 * $Id: $
11 *
12 * Rockbox plugin copyright (C) 2009 Dave Chapman.
13 * Based on encryption code (C) 2009 Michael Sparmann
14 *
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
19 *
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
22 *
23 ****************************************************************************/
24
25/*
26
27 This viewer plugin is for the encryption/decryption of iPod Nano
28 (2nd generation) firmware images using the hardware AES crypto unit
29 in such devices.
30
31 Encrypted images are stored with the modelname "nn2x" and extension
32 ".ipodx" Unencrypted images use "nn2g" and ".ipod".
33
34 Heavily based on Payloads/CryptFirmware/main.c from iBugger.
35
36 The (C) from that file is as follows:
37
38 Copyright 2009 TheSeven
39
40 This file is part of TheSeven's iBugger.
41
42 TheSeven's iBugger is free software: you can redistribute it and/or
43 modify it under the terms of the GNU General Public License as
44 published by the Free Software Foundation, either version 2 of the
45 License, or (at your option) any later version.
46
47 TheSeven's iBugger is distributed in the hope that it will be useful,
48 but WITHOUT ANY WARRANTY; without even the implied warranty of
49 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
50 See the GNU General Public License for more details.
51
52 You should have received a copy of the GNU General Public License along
53 with TheSeven's iBugger. If not, see <http://www.gnu.org/licenses/>.
54
55*/
56
57#include "plugin.h"
58
59PLUGIN_HEADER
60
61static void aes_encrypt(void* data, uint32_t size)
62{
63 uint32_t ptr, i;
64 uint32_t go = 1;
65 PWRCONEXT &= ~0x400;
66 AESTYPE = 1;
67 AESUNKREG0 = 1;
68 AESUNKREG0 = 0;
69 AESCONTROL = 1;
70 AESKEYLEN = 9;
71 AESOUTSIZE = size;
72 AESAUXSIZE = 0x10;
73 AESINSIZE = 0x10;
74 AESSIZE3 = 0x10;
75 for (ptr = 0; ptr < (size >> 2); ptr += 4)
76 {
77 AESOUTADDR = (uint32_t)data + (ptr << 2);
78 AESINADDR = (uint32_t)data + (ptr << 2);
79 AESAUXADDR = (uint32_t)data + (ptr << 2);
80 if (ptr != 0)
81 for (i = 0; i < 4; i++)
82 ((uint32_t*)data)[ptr + i] ^= ((uint32_t*)data)[ptr + i - 4];
83 AESSTATUS = 6;
84 AESGO = go;
85 go = 3;
86 while ((AESSTATUS & 6) == 0);
87 }
88 AESCONTROL = 0;
89 PWRCONEXT |= 0x400;
90}
91
92static void aes_decrypt(void* data, uint32_t size)
93{
94 uint32_t ptr, i;
95 uint32_t go = 1;
96 PWRCONEXT &= ~0x400;
97 AESTYPE = 1;
98 AESUNKREG0 = 1;
99 AESUNKREG0 = 0;
100 AESCONTROL = 1;
101 AESKEYLEN = 8;
102 AESOUTSIZE = size;
103 AESAUXSIZE = 0x10;
104 AESINSIZE = 0x10;
105 AESSIZE3 = 0x10;
106 for (ptr = (size >> 2) - 4; ; ptr -= 4)
107 {
108 AESOUTADDR = (uint32_t)data + (ptr << 2);
109 AESINADDR = (uint32_t)data + (ptr << 2);
110 AESAUXADDR = (uint32_t)data + (ptr << 2);
111 AESSTATUS = 6;
112 AESGO = go;
113 go = 3;
114 while ((AESSTATUS & 6) == 0);
115 if (ptr == 0) break;
116 for (i = 0; i < 4; i++)
117 ((uint32_t*)data)[ptr + i] ^= ((uint32_t*)data)[ptr + i - 4];
118 }
119 AESCONTROL = 0;
120 PWRCONEXT |= 0x400;
121}
122
123static void calc_hash(uint32_t* data, uint32_t size, uint32_t* result)
124{
125 uint32_t ptr, i;
126 uint32_t ctrl = 2;
127
128 PWRCONEXT &= ~0x4;
129
130 for (ptr = 0; ptr < (size >> 2); ptr += 0x10)
131 {
132 for (i = 0; i < 0x10; i++) HASHDATAIN[i] = data[ptr + i];
133 HASHCTRL = ctrl;
134 ctrl = 0xA;
135 while ((HASHCTRL & 1) != 0);
136 }
137 for (i = 0; i < 5; i ++) result[i] = HASHRESULT[i];
138
139 PWRCONEXT |= 0x4;
140}
141
142static uint32_t get_uint32be(unsigned char* buf)
143{
144 return (uint32_t)((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]);
145}
146
147static void put_uint32be(unsigned char* buf, uint32_t x)
148{
149 buf[0] = (x & 0xff000000) >> 24;
150 buf[1] = (x & 0xff0000) >> 16;
151 buf[2] = (x & 0xff00) >> 8;
152 buf[3] = x & 0xff;
153}
154
155static uint32_t calc_checksum(uint32_t sum, unsigned char* buf, int len)
156{
157 int i;
158
159 for (i = 0; i < len ; i++) {
160 sum += buf[i];
161 }
162
163 return sum;
164}
165
166enum plugin_status plugin_start(const void* parameter)
167{
168 int fd;
169 int length;
170 int n;
171 ssize_t buf_size;
172 uint32_t* buf;
173 int size;
174 uint32_t sum;
175 uint32_t hash[0x200];
176 char outputfilename[MAX_PATH];
177
178 fd = rb->open(parameter,O_RDONLY);
179
180 if (fd < 0) {
181 rb->splash(HZ*2, "Cannot open file");
182 return PLUGIN_ERROR;
183 }
184
185 length = rb->filesize(fd);
186
187 if (length < 12) {
188 rb->splash(HZ*2, "File too small");
189 return PLUGIN_ERROR;
190 }
191
192 if (length > buf_size) {
193 rb->splash(HZ*2, "File too big");
194 return PLUGIN_ERROR;
195 }
196
197 /* Get the audio buffer */
198 buf = rb->plugin_get_audio_buffer((size_t *)&buf_size);
199
200 /* Use uncached alias for buf - equivalent to buf |= 0x40000000 */
201 buf += 0x10000000;
202
203 n = rb->read(fd, buf, length);
204 if (n < length) {
205 rb->splash(HZ*2, "Cannot read file");
206 return PLUGIN_ERROR;
207 }
208 rb->close(fd);
209
210 size = length - 8; /* Size of firmware image */
211
212 if (calc_checksum(MODEL_NUMBER, (unsigned char*)(buf + 2), size) !=
213 get_uint32be((unsigned char*)buf)) {
214 rb->splash(HZ*2, "Bad checksum in input file");
215 return PLUGIN_ERROR;
216 }
217
218 n = rb->strlen(parameter);
219 if (memcmp(buf+1,"nn2g",4)==0) {
220 /* Encrypting - Input file should be .ipod, output file is .ipodx */
221
222 if ((n < 6) || (rb->strcmp(parameter+n-5,".ipod") != 0)) {
223 rb->splash(HZ*2, "Input filename must be .ipod");
224 return PLUGIN_ERROR;
225 }
226
227 if (n + 2 > MAX_PATH) {
228 rb->splash(HZ*2, "Filename too long");
229 return PLUGIN_ERROR;
230 }
231
232 size = (size + 0x3f) & ~0x3f; /* Pad to multiple of 64 bytes */
233 if (size > (length - 8)) {
234 rb->memset(&buf[length/4], 0, size - (length - 8));
235 }
236
237 rb->strlcpy(outputfilename, parameter, MAX_PATH);
238 outputfilename[n] = 'x';
239 outputfilename[n+1] = 0;
240
241 /* Everything is OK, now do the encryption */
242
243 /* 1 - Calculate hashes */
244
245 rb->memset(hash, 0, sizeof(hash));
246
247 hash[1] = 2;
248 hash[2] = 1;
249 hash[3] = 0x40;
250 hash[5] = size;
251
252 calc_hash(buf + 2, size, &hash[7]);
253 calc_hash(hash, 0x200, &hash[0x75]);
254
255 /* 2 - Do the encryption */
256
257 rb->splash(0, "Encrypting...");
258 aes_encrypt(buf + 2, size);
259
260 /* 3 - Update the Rockbox header */
261
262 sum = calc_checksum(MODEL_NUMBER, (unsigned char*)hash, sizeof(hash));
263 sum = calc_checksum(sum, (unsigned char*)(buf + 2), size);
264 put_uint32be((unsigned char*)buf, sum);
265 memcpy(buf + 1, "nn2x", 4);
266
267 /* 4 - Write to disk */
268 fd = rb->open(outputfilename,O_WRONLY|O_CREAT|O_TRUNC);
269
270 if (fd < 0) {
271 rb->splash(HZ*2, "Could not open output file");
272 return PLUGIN_ERROR;
273 }
274
275 n = rb->write(fd, buf, 8);
276 n = rb->write(fd, hash, sizeof(hash));
277 n = rb->write(fd, buf + 2, size);
278
279 rb->close(fd);
280 } else if (memcmp(buf + 1,"nn2x",4)==0) {
281 /* Decrypting - Input file should be .ipodx, output file is .ipod */
282
283 if ((n < 7) || (rb->strcmp(parameter+n-6,".ipodx") != 0)) {
284 rb->splash(HZ*2, "Input filename must be .ipodx");
285 return PLUGIN_ERROR;
286 }
287
288 rb->strlcpy(outputfilename, parameter, MAX_PATH);
289 outputfilename[n-1] = 0; /* Remove "x" at end of filename */
290
291 /* Everything is OK, now do the decryption */
292
293 size -= 0x800; /* Remove hash size from firmware size */
294
295 /* 1 - Decrypt */
296
297 rb->splash(0, "Decrypting...");
298
299 aes_decrypt(&buf[0x202], size);
300
301 /* 2 - Calculate hashes to verify decryption */
302
303 rb->lcd_clear_display();
304 rb->splash(0, "Calculating hash...");
305
306 rb->memset(hash, 0, sizeof(hash));
307
308 hash[1] = 2;
309 hash[2] = 1;
310 hash[3] = 0x40;
311 hash[5] = size;
312
313 calc_hash(&buf[0x202], size, &hash[7]);
314 calc_hash(hash, 0x200, &hash[0x75]);
315
316 if ((memcmp(hash + 7, buf + 9, 20) != 0) ||
317 (memcmp(hash + 75, buf + 77, 20) != 0)) {
318 rb->splash(HZ*2, "Decryption failed - bad hash");
319 return PLUGIN_ERROR;
320 }
321
322 /* 3 - Update the Rockbox header */
323
324 sum = calc_checksum(MODEL_NUMBER, (unsigned char*)(&buf[0x202]), size);
325 put_uint32be((unsigned char*)buf, sum);
326 memcpy(buf + 1, "nn2g", 4);
327
328 /* 4 - Write to disk */
329 fd = rb->open(outputfilename,O_WRONLY|O_CREAT|O_TRUNC);
330
331 if (fd < 0) {
332 rb->splash(HZ*2, "Could not open output file");
333 return PLUGIN_ERROR;
334 }
335
336 n = rb->write(fd, buf, 8);
337 n = rb->write(fd, &buf[0x202], size);
338
339 rb->close(fd);
340 } else {
341 rb->splash(HZ*2,"Invalid input file");
342 return PLUGIN_ERROR;
343 }
344
345 return PLUGIN_OK;
346}
diff --git a/apps/plugins/viewers.config b/apps/plugins/viewers.config
index a572c6abfa..e3b15fe116 100644
--- a/apps/plugins/viewers.config
+++ b/apps/plugins/viewers.config
@@ -58,3 +58,5 @@ link,viewers/shortcuts_view,-
58*,viewers/shortcuts_append,- 58*,viewers/shortcuts_append,-
59*,apps/md5sum,- 59*,apps/md5sum,-
60lua,viewers/lua,- 60lua,viewers/lua,-
61ipod,viewers/crypt_firmware,-
62ipodx,viewers/crypt_firmware,-
diff --git a/firmware/export/config-ipodnano2g.h b/firmware/export/config-ipodnano2g.h
index 641e88860b..d9c5cbf3ea 100644
--- a/firmware/export/config-ipodnano2g.h
+++ b/firmware/export/config-ipodnano2g.h
@@ -159,6 +159,9 @@
159#define BOOTFILE "rockbox." BOOTFILE_EXT 159#define BOOTFILE "rockbox." BOOTFILE_EXT
160#define BOOTDIR "/.rockbox" 160#define BOOTDIR "/.rockbox"
161 161
162/* Alternative bootfile extension - this is for encrypted images */
163#define BOOTFILE_EXT2 "ipodx"
164
162#define BOOTLOADER_ENTRYPOINT 0x001F0000 165#define BOOTLOADER_ENTRYPOINT 0x001F0000
163#define FLASH_ENTRYPOINT 0x00001000 166#define FLASH_ENTRYPOINT 0x00001000
164#define FLASH_MAGIC 0xfbfbfbf1 167#define FLASH_MAGIC 0xfbfbfbf1
diff --git a/firmware/export/s5l8700.h b/firmware/export/s5l8700.h
index f652a62a2e..f9e015baff 100644
--- a/firmware/export/s5l8700.h
+++ b/firmware/export/s5l8700.h
@@ -120,6 +120,7 @@
120#define RSTSR (*(REG32_PTR_T)(0x3C500034)) /* Reset status register */ 120#define RSTSR (*(REG32_PTR_T)(0x3C500034)) /* Reset status register */
121#define DSPCLKMD (*(REG32_PTR_T)(0x3C500038)) /* DSP clock mode register */ 121#define DSPCLKMD (*(REG32_PTR_T)(0x3C500038)) /* DSP clock mode register */
122#define CLKCON2 (*(REG32_PTR_T)(0x3C50003C)) /* clock control register 2 */ 122#define CLKCON2 (*(REG32_PTR_T)(0x3C50003C)) /* clock control register 2 */
123#define PWRCONEXT (*(REG32_PTR_T)(0x3C500040))
123 124
124/* 06. INTERRUPT CONTROLLER UNIT */ 125/* 06. INTERRUPT CONTROLLER UNIT */
125#define SRCPND (*(REG32_PTR_T)(0x39C00000)) /* Indicates the interrupt request status. */ 126#define SRCPND (*(REG32_PTR_T)(0x39C00000)) /* Indicates the interrupt request status. */
@@ -670,3 +671,28 @@
670#define REG_ONE (*(REG32_PTR_T)(0x3D100000)) /* Receive the first 32 bits from a fuse box */ 671#define REG_ONE (*(REG32_PTR_T)(0x3D100000)) /* Receive the first 32 bits from a fuse box */
671#define REG_TWO (*(REG32_PTR_T)(0x3D100004)) /* Receive the other 8 bits from a fuse box */ 672#define REG_TWO (*(REG32_PTR_T)(0x3D100004)) /* Receive the other 8 bits from a fuse box */
672 673
674
675/* Hardware AES crypto unit - S5L8701 only */
676#if CONFIG_CPU==S5L8701
677
678#define ICONSRCPND (*(REG32_PTR_T)(0x39C00000))
679#define ICONINTPND (*(REG32_PTR_T)(0x39C00010))
680#define AESCONTROL (*(REG32_PTR_T)(0x39800000))
681#define AESGO (*(REG32_PTR_T)(0x39800004))
682#define AESUNKREG0 (*(REG32_PTR_T)(0x39800008))
683#define AESSTATUS (*(REG32_PTR_T)(0x3980000C))
684#define AESUNKREG1 (*(REG32_PTR_T)(0x39800010))
685#define AESKEYLEN (*(REG32_PTR_T)(0x39800014))
686#define AESOUTSIZE (*(REG32_PTR_T)(0x39800018))
687#define AESOUTADDR (*(REG32_PTR_T)(0x39800020))
688#define AESINSIZE (*(REG32_PTR_T)(0x39800024))
689#define AESINADDR (*(REG32_PTR_T)(0x39800028))
690#define AESAUXSIZE (*(REG32_PTR_T)(0x3980002C))
691#define AESAUXADDR (*(REG32_PTR_T)(0x39800030))
692#define AESSIZE3 (*(REG32_PTR_T)(0x39800034))
693#define AESTYPE (*(REG32_PTR_T)(0x3980006C))
694#define HASHCTRL (*(REG32_PTR_T)(0x3C600000))
695#define HASHRESULT ((REG32_PTR_T)(0x3C600020))
696#define HASHDATAIN ((REG32_PTR_T)(0x3C600040))
697
698#endif /* CONFIG_CPU==S5L8701 */