summaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
Diffstat (limited to 'apps')
-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
4 files changed, 355 insertions, 0 deletions
diff --git a/apps/filetypes.c b/apps/filetypes.c
index ffa7161..ed3d938 100644
--- a/apps/filetypes.c
+++ b/apps/filetypes.c
@@ -111,6 +111,9 @@ static const struct filetype inbuilt_filetypes[] = {
#ifdef BOOTFILE_EXT
{ BOOTFILE_EXT, FILE_ATTR_MOD, Icon_Firmware, VOICE_EXT_AJZ },
#endif
+#ifdef BOOTFILE_EXT2
+ { BOOTFILE_EXT2, FILE_ATTR_MOD, Icon_Firmware, VOICE_EXT_AJZ },
+#endif
};
void tree_get_filetypes(const struct filetype** types, int* count)
diff --git a/apps/plugins/SOURCES b/apps/plugins/SOURCES
index 4cfc3a8..a15564d 100644
--- a/apps/plugins/SOURCES
+++ b/apps/plugins/SOURCES
@@ -29,6 +29,10 @@ firmware_flash.c
rockbox_flash.c
#endif /* CONFIG_CPU */
+#if defined(IPOD_NANO2G) && !defined(SIMULATOR)
+crypt_firmware.c
+#endif
+
#if (CONFIG_CODEC == SWCODEC) && defined(HAVE_RECORDING) && \
(defined(HAVE_LINE_IN) || defined(HAVE_MIC_IN))
pitch_detector.c
diff --git a/apps/plugins/crypt_firmware.c b/apps/plugins/crypt_firmware.c
new file mode 100644
index 0000000..6bfeeab
--- /dev/null
+++ b/apps/plugins/crypt_firmware.c
@@ -0,0 +1,346 @@
+/***************************************************************************
+ *
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ *
+ * $Id: $
+ *
+ * Rockbox plugin copyright (C) 2009 Dave Chapman.
+ * Based on encryption code (C) 2009 Michael Sparmann
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+/*
+
+ This viewer plugin is for the encryption/decryption of iPod Nano
+ (2nd generation) firmware images using the hardware AES crypto unit
+ in such devices.
+
+ Encrypted images are stored with the modelname "nn2x" and extension
+ ".ipodx" Unencrypted images use "nn2g" and ".ipod".
+
+ Heavily based on Payloads/CryptFirmware/main.c from iBugger.
+
+ The (C) from that file is as follows:
+
+ Copyright 2009 TheSeven
+
+ This file is part of TheSeven's iBugger.
+
+ TheSeven's iBugger is free software: you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation, either version 2 of the
+ License, or (at your option) any later version.
+
+ TheSeven's iBugger is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with TheSeven's iBugger. If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "plugin.h"
+
+PLUGIN_HEADER
+
+static void aes_encrypt(void* data, uint32_t size)
+{
+ uint32_t ptr, i;
+ uint32_t go = 1;
+ PWRCONEXT &= ~0x400;
+ AESTYPE = 1;
+ AESUNKREG0 = 1;
+ AESUNKREG0 = 0;
+ AESCONTROL = 1;
+ AESKEYLEN = 9;
+ AESOUTSIZE = size;
+ AESAUXSIZE = 0x10;
+ AESINSIZE = 0x10;
+ AESSIZE3 = 0x10;
+ for (ptr = 0; ptr < (size >> 2); ptr += 4)
+ {
+ AESOUTADDR = (uint32_t)data + (ptr << 2);
+ AESINADDR = (uint32_t)data + (ptr << 2);
+ AESAUXADDR = (uint32_t)data + (ptr << 2);
+ if (ptr != 0)
+ for (i = 0; i < 4; i++)
+ ((uint32_t*)data)[ptr + i] ^= ((uint32_t*)data)[ptr + i - 4];
+ AESSTATUS = 6;
+ AESGO = go;
+ go = 3;
+ while ((AESSTATUS & 6) == 0);
+ }
+ AESCONTROL = 0;
+ PWRCONEXT |= 0x400;
+}
+
+static void aes_decrypt(void* data, uint32_t size)
+{
+ uint32_t ptr, i;
+ uint32_t go = 1;
+ PWRCONEXT &= ~0x400;
+ AESTYPE = 1;
+ AESUNKREG0 = 1;
+ AESUNKREG0 = 0;
+ AESCONTROL = 1;
+ AESKEYLEN = 8;
+ AESOUTSIZE = size;
+ AESAUXSIZE = 0x10;
+ AESINSIZE = 0x10;
+ AESSIZE3 = 0x10;
+ for (ptr = (size >> 2) - 4; ; ptr -= 4)
+ {
+ AESOUTADDR = (uint32_t)data + (ptr << 2);
+ AESINADDR = (uint32_t)data + (ptr << 2);
+ AESAUXADDR = (uint32_t)data + (ptr << 2);
+ AESSTATUS = 6;
+ AESGO = go;
+ go = 3;
+ while ((AESSTATUS & 6) == 0);
+ if (ptr == 0) break;
+ for (i = 0; i < 4; i++)
+ ((uint32_t*)data)[ptr + i] ^= ((uint32_t*)data)[ptr + i - 4];
+ }
+ AESCONTROL = 0;
+ PWRCONEXT |= 0x400;
+}
+
+static void calc_hash(uint32_t* data, uint32_t size, uint32_t* result)
+{
+ uint32_t ptr, i;
+ uint32_t ctrl = 2;
+
+ PWRCONEXT &= ~0x4;
+
+ for (ptr = 0; ptr < (size >> 2); ptr += 0x10)
+ {
+ for (i = 0; i < 0x10; i++) HASHDATAIN[i] = data[ptr + i];
+ HASHCTRL = ctrl;
+ ctrl = 0xA;
+ while ((HASHCTRL & 1) != 0);
+ }
+ for (i = 0; i < 5; i ++) result[i] = HASHRESULT[i];
+
+ PWRCONEXT |= 0x4;
+}
+
+static uint32_t get_uint32be(unsigned char* buf)
+{
+ return (uint32_t)((buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]);
+}
+
+static void put_uint32be(unsigned char* buf, uint32_t x)
+{
+ buf[0] = (x & 0xff000000) >> 24;
+ buf[1] = (x & 0xff0000) >> 16;
+ buf[2] = (x & 0xff00) >> 8;
+ buf[3] = x & 0xff;
+}
+
+static uint32_t calc_checksum(uint32_t sum, unsigned char* buf, int len)
+{
+ int i;
+
+ for (i = 0; i < len ; i++) {
+ sum += buf[i];
+ }
+
+ return sum;
+}
+
+enum plugin_status plugin_start(const void* parameter)
+{
+ int fd;
+ int length;
+ int n;
+ ssize_t buf_size;
+ uint32_t* buf;
+ int size;
+ uint32_t sum;
+ uint32_t hash[0x200];
+ char outputfilename[MAX_PATH];
+
+ fd = rb->open(parameter,O_RDONLY);
+
+ if (fd < 0) {
+ rb->splash(HZ*2, "Cannot open file");
+ return PLUGIN_ERROR;
+ }
+
+ length = rb->filesize(fd);
+
+ if (length < 12) {
+ rb->splash(HZ*2, "File too small");
+ return PLUGIN_ERROR;
+ }
+
+ if (length > buf_size) {
+ rb->splash(HZ*2, "File too big");
+ return PLUGIN_ERROR;
+ }
+
+ /* Get the audio buffer */
+ buf = rb->plugin_get_audio_buffer((size_t *)&buf_size);
+
+ /* Use uncached alias for buf - equivalent to buf |= 0x40000000 */
+ buf += 0x10000000;
+
+ n = rb->read(fd, buf, length);
+ if (n < length) {
+ rb->splash(HZ*2, "Cannot read file");
+ return PLUGIN_ERROR;
+ }
+ rb->close(fd);
+
+ size = length - 8; /* Size of firmware image */
+
+ if (calc_checksum(MODEL_NUMBER, (unsigned char*)(buf + 2), size) !=
+ get_uint32be((unsigned char*)buf)) {
+ rb->splash(HZ*2, "Bad checksum in input file");
+ return PLUGIN_ERROR;
+ }
+
+ n = rb->strlen(parameter);
+ if (memcmp(buf+1,"nn2g",4)==0) {
+ /* Encrypting - Input file should be .ipod, output file is .ipodx */
+
+ if ((n < 6) || (rb->strcmp(parameter+n-5,".ipod") != 0)) {
+ rb->splash(HZ*2, "Input filename must be .ipod");
+ return PLUGIN_ERROR;
+ }
+
+ if (n + 2 > MAX_PATH) {
+ rb->splash(HZ*2, "Filename too long");
+ return PLUGIN_ERROR;
+ }
+
+ size = (size + 0x3f) & ~0x3f; /* Pad to multiple of 64 bytes */
+ if (size > (length - 8)) {
+ rb->memset(&buf[length/4], 0, size - (length - 8));
+ }
+
+ rb->strlcpy(outputfilename, parameter, MAX_PATH);
+ outputfilename[n] = 'x';
+ outputfilename[n+1] = 0;
+
+ /* Everything is OK, now do the encryption */
+
+ /* 1 - Calculate hashes */
+
+ rb->memset(hash, 0, sizeof(hash));
+
+ hash[1] = 2;
+ hash[2] = 1;
+ hash[3] = 0x40;
+ hash[5] = size;
+
+ calc_hash(buf + 2, size, &hash[7]);
+ calc_hash(hash, 0x200, &hash[0x75]);
+
+ /* 2 - Do the encryption */
+
+ rb->splash(0, "Encrypting...");
+ aes_encrypt(buf + 2, size);
+
+ /* 3 - Update the Rockbox header */
+
+ sum = calc_checksum(MODEL_NUMBER, (unsigned char*)hash, sizeof(hash));
+ sum = calc_checksum(sum, (unsigned char*)(buf + 2), size);
+ put_uint32be((unsigned char*)buf, sum);
+ memcpy(buf + 1, "nn2x", 4);
+
+ /* 4 - Write to disk */
+ fd = rb->open(outputfilename,O_WRONLY|O_CREAT|O_TRUNC);
+
+ if (fd < 0) {
+ rb->splash(HZ*2, "Could not open output file");
+ return PLUGIN_ERROR;
+ }
+
+ n = rb->write(fd, buf, 8);
+ n = rb->write(fd, hash, sizeof(hash));
+ n = rb->write(fd, buf + 2, size);
+
+ rb->close(fd);
+ } else if (memcmp(buf + 1,"nn2x",4)==0) {
+ /* Decrypting - Input file should be .ipodx, output file is .ipod */
+
+ if ((n < 7) || (rb->strcmp(parameter+n-6,".ipodx") != 0)) {
+ rb->splash(HZ*2, "Input filename must be .ipodx");
+ return PLUGIN_ERROR;
+ }
+
+ rb->strlcpy(outputfilename, parameter, MAX_PATH);
+ outputfilename[n-1] = 0; /* Remove "x" at end of filename */
+
+ /* Everything is OK, now do the decryption */
+
+ size -= 0x800; /* Remove hash size from firmware size */
+
+ /* 1 - Decrypt */
+
+ rb->splash(0, "Decrypting...");
+
+ aes_decrypt(&buf[0x202], size);
+
+ /* 2 - Calculate hashes to verify decryption */
+
+ rb->lcd_clear_display();
+ rb->splash(0, "Calculating hash...");
+
+ rb->memset(hash, 0, sizeof(hash));
+
+ hash[1] = 2;
+ hash[2] = 1;
+ hash[3] = 0x40;
+ hash[5] = size;
+
+ calc_hash(&buf[0x202], size, &hash[7]);
+ calc_hash(hash, 0x200, &hash[0x75]);
+
+ if ((memcmp(hash + 7, buf + 9, 20) != 0) ||
+ (memcmp(hash + 75, buf + 77, 20) != 0)) {
+ rb->splash(HZ*2, "Decryption failed - bad hash");
+ return PLUGIN_ERROR;
+ }
+
+ /* 3 - Update the Rockbox header */
+
+ sum = calc_checksum(MODEL_NUMBER, (unsigned char*)(&buf[0x202]), size);
+ put_uint32be((unsigned char*)buf, sum);
+ memcpy(buf + 1, "nn2g", 4);
+
+ /* 4 - Write to disk */
+ fd = rb->open(outputfilename,O_WRONLY|O_CREAT|O_TRUNC);
+
+ if (fd < 0) {
+ rb->splash(HZ*2, "Could not open output file");
+ return PLUGIN_ERROR;
+ }
+
+ n = rb->write(fd, buf, 8);
+ n = rb->write(fd, &buf[0x202], size);
+
+ rb->close(fd);
+ } else {
+ rb->splash(HZ*2,"Invalid input file");
+ return PLUGIN_ERROR;
+ }
+
+ return PLUGIN_OK;
+}
diff --git a/apps/plugins/viewers.config b/apps/plugins/viewers.config
index a572c6a..e3b15fe 100644
--- a/apps/plugins/viewers.config
+++ b/apps/plugins/viewers.config
@@ -58,3 +58,5 @@ link,viewers/shortcuts_view,-
*,viewers/shortcuts_append,-
*,apps/md5sum,-
lua,viewers/lua,-
+ipod,viewers/crypt_firmware,-
+ipodx,viewers/crypt_firmware,-