diff options
-rw-r--r-- | ChangeLog | 27 | ||||
-rw-r--r-- | docs/reference/tmpl/device.sgml | 1 | ||||
-rw-r--r-- | src/Makefile.am | 36 | ||||
-rw-r--r-- | src/itdb_device.c | 30 | ||||
-rw-r--r-- | src/itdb_device.h | 4 | ||||
-rw-r--r-- | src/itdb_itunesdb.c | 159 | ||||
-rw-r--r-- | src/itdb_sha1.c | 247 | ||||
-rw-r--r-- | src/itdb_sha1.h | 37 | ||||
-rw-r--r-- | src/sha1.c | 450 | ||||
-rw-r--r-- | src/sha1.h | 62 | ||||
-rw-r--r-- | tests/Makefile.am | 9 | ||||
-rw-r--r-- | tests/test-checksum.c | 181 | ||||
-rw-r--r-- | tests/test-fw-id.c | 65 |
13 files changed, 1281 insertions, 27 deletions
@@ -1,3 +1,30 @@ +2007-09-24 Jorg Schuler <jcsjcs at users.sourceforge.net> + + ** code courtesy of Christophe Fergeau ** + + * src/itdb_itunesdb.c (mk_mhbd): write extended header needed + for new iPod Nanos (3G Video) and iPod Classics. + + src/itdb_device.c + src/itdb_device.h: Code to parse SysInfoExtended and SysInfo + for the FireWireGUID. You must either copy the iPod + description XML file to Device/SysInfoExtended or add a line + 'FirewireGuid: 000A27....' to Device/SysInfo. You can get + your FirewireGuid by using the tests/test-fw-id test program. + + * src/sha1.c + src/sha1.h + src/itdb_sha1.c + src/itdb_sha1.h + New files for obscure hash generation code. + + * src/Makefile.am: added new files. + + * tests/test-checksum.c + tests/test-fw-id.c + tests/Makefile.am: test programs to retrieve the + FirewireGuid and calculate/write the obscure hash. + 2007-09-15 Jorg Schuler <jcsjcs at users.sourceforge.net> * src/itdb_device.c: diff --git a/docs/reference/tmpl/device.sgml b/docs/reference/tmpl/device.sgml index 43aab27..6307097 100644 --- a/docs/reference/tmpl/device.sgml +++ b/docs/reference/tmpl/device.sgml @@ -227,6 +227,7 @@ These functions are for reading and setting information about the iPod. @ITDB_IPOD_MODEL_NANO_BLUE: @ITDB_IPOD_MODEL_NANO_GREEN: @ITDB_IPOD_MODEL_NANO_PINK: +@ITDB_IPOD_MODEL_NANO_RED: @ITDB_IPOD_MODEL_IPHONE_1: @ITDB_IPOD_MODEL_SHUFFLE_SILVER: @ITDB_IPOD_MODEL_SHUFFLE_PINK: diff --git a/src/Makefile.am b/src/Makefile.am index 0a3db65..e0fbe33 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,34 +1,38 @@ lib_LTLIBRARIES = libgpod.la libgpod_la_SOURCES = \ + db-artwork-debug.c \ + db-artwork-debug.h \ + db-artwork-parser.c \ + db-artwork-parser.h \ + db-artwork-writer.c \ + db-image-parser.c \ + db-image-parser.h \ + db-itunes-parser.h \ + db-parse-context.c \ + db-parse-context.h \ + glib-compat.h \ itdb.h \ itdb_artwork.c \ + itdb_device.c \ + itdb_device.h \ + itdb_endianness.h \ itdb_itunesdb.c \ + itdb_photoalbum.c \ itdb_playlist.c \ itdb_private.h \ - itdb_photoalbum.c \ + itdb_sha1.c \ + itdb_sha1.h \ + itdb_sysinfo.c \ itdb_track.c \ - db-artwork-parser.c \ - db-artwork-parser.h \ - db-parse-context.c \ - db-parse-context.h \ - db-artwork-debug.c \ - db-artwork-debug.h \ - db-image-parser.c \ - db-image-parser.h \ - db-itunes-parser.h \ - db-artwork-writer.c \ ithumb-writer.c \ - itdb_device.c \ - itdb_device.h \ - itdb_endianness.h \ pixmaps.c \ pixmaps.h \ - glib-compat.h + sha1.c libgpod_la_headers = itdb.h -libgpod_la_noinst_headers = itdb_private.h hal-common.h +libgpod_la_noinst_headers = itdb_private.h hal-common.h sha1.h itdb-sha1.h libgpod_la_LDFLAGS = -version-info $(LIBGPOD_SO_VERSION) -no-undefined libgpodincludedir = $(includedir)/gpod-1.0/gpod diff --git a/src/itdb_device.c b/src/itdb_device.c index 10ae719..6b4ee77 100644 --- a/src/itdb_device.c +++ b/src/itdb_device.c @@ -223,6 +223,7 @@ static const gchar *ipod_model_name_table [] = { N_("Nano (Blue)"), N_("Nano (Green)"), N_("Nano (Pink)"), + N_("Nano (Red)"), N_("iPhone (1)"), N_("Shuffle (Silver)"), N_("Shuffle (Pink)"), @@ -471,13 +472,14 @@ gboolean itdb_device_read_sysinfo (Itdb_Device *device) g_free (sysinfo_path); } g_free (dev_path); + + itdb_device_read_sysinfo_xml (device, NULL); + /* indicate that sysinfo is identical to what is on the iPod */ device->sysinfo_changed = FALSE; return result; } - - /* used by itdb_device_write_sysinfo() */ static void write_sysinfo_entry (const gchar *key, const gchar *value, @@ -925,7 +927,6 @@ const gchar *itdb_info_get_ipod_generation_string (Itdb_IpodGeneration generatio * * Return value: true if @device can display artwork. */ - gboolean itdb_device_supports_artwork (Itdb_Device *device) { if (device == NULL) { @@ -1035,3 +1036,26 @@ static void itdb_device_set_timezone_info (Itdb_Device *device) device->timezone_shift += 3600; } } + +/** + * itdb_device_get_firewire_id + * @device: an #Itdb_Device + * + * Returns the Firewire ID for @device, this is useful to calculate the + * iTunesDB checksum which is expected by newer iPod models + * (iPod classic/fat nanos) + * + * Return value: the guint64 firewire id, or 0 if we don't know it + **/ +guint64 itdb_device_get_firewire_id (Itdb_Device *device) +{ + gchar *fwid; + + g_assert (device->sysinfo != NULL); + + fwid = g_hash_table_lookup (device->sysinfo, "FirewireGuid"); + if (fwid == NULL) { + return 0; + } + return g_ascii_strtoull (fwid, NULL, 16); +} diff --git a/src/itdb_device.h b/src/itdb_device.h index 2c11630..904dca3 100644 --- a/src/itdb_device.h +++ b/src/itdb_device.h @@ -100,6 +100,10 @@ struct _Itdb_ArtworkFormat G_GNUC_INTERNAL const Itdb_ArtworkFormat *itdb_device_get_artwork_formats (Itdb_Device *device); G_GNUC_INTERNAL gint itdb_device_musicdirs_number (Itdb_Device *device); G_GNUC_INTERNAL void itdb_device_autodetect_endianess (Itdb_Device *device); +G_GNUC_INTERNAL gboolean itdb_device_read_sysinfo_xml (Itdb_Device *device, + GError **error); +G_GNUC_INTERNAL guint64 itdb_device_get_firewire_id (Itdb_Device *device); + G_END_DECLS #endif diff --git a/src/itdb_itunesdb.c b/src/itdb_itunesdb.c index 1ed0c1c..a411052 100644 --- a/src/itdb_itunesdb.c +++ b/src/itdb_itunesdb.c @@ -110,12 +110,15 @@ #include "db-artwork-parser.h" #include "itdb_device.h" #include "itdb_private.h" +#include "itdb_sha1.h" + #include <errno.h> #include <fcntl.h> #include <glib-object.h> #include <glib/gi18n-lib.h> #include <stdio.h> #include <string.h> +#include <sys/mman.h> #include <sys/stat.h> #include <sys/statvfs.h> #include <sys/types.h> @@ -3401,7 +3404,7 @@ static void mk_mhbd (FExport *fexp, guint32 children) cts = fexp->wcontents; put_header (cts, "mhbd"); - put32lint (cts, 104); /* header size */ + put32lint (cts, 188); /* header size */ put32lint (cts, -1); /* size of whole mhdb -- fill in later */ put32lint (cts, 1); /* ? */ /* Version number: 0x01: iTunes 2 @@ -3416,13 +3419,33 @@ static void mk_mhbd (FExport *fexp, guint32 children) 0x10: iTunes 6.0.1(?) 0x11: iTunes 6.0.2 0x12 = iTunes 6.0.5. - 0x13 = iTunes 7 */ - fexp->itdb->version = 0x13; + 0x13 = iTunes 7 + 0x14 = iTunes 7.1 + 0x15 = iTunes 7.2 + 0x19 = iTunes 7.4 + Be aware that newer ipods won't work if the library version number is too + old + */ + fexp->itdb->version = 0x19; put32lint (cts, fexp->itdb->version); put32lint (cts, children); put64lint (cts, fexp->itdb->id); - put32lint (cts, 2); /* ? */ - put32_n0 (cts, 17); /* dummy space */ + /* 0x20 */ + put16lint (cts, 2); /* always seems to be 2 */ + put16_n0 (cts, 7); /* unknown */ + /* 0x30 */ + put16lint (cts, 1); /* ? but iPod Classic/fat Nanos won't display any song + * if it's not 1 */ + put16_n0 (cts, 10); /* unknown */ + /* 0x46 */ + put16lint (cts, 0); /* langauge */ + put64lint (cts, 0); /* library persistent ID */ + /* 0x50 */ + put32lint (cts, 0); /* unknown: seen: 0x05 for nano 3G */ + put32lint (cts, 0); /* unknown: seen: 0x4d for nano 3G */ + put32_n0 (cts, 5); /* 20 bytes hash */ + put32lint (cts, 0); /* timezone offset in seconds */ + put32_n0 (cts, 19); /* dummy space */ } /* Fill in the length of a standard header */ @@ -4920,6 +4943,122 @@ gboolean itdb_write_file (Itdb_iTunesDB *itdb, const gchar *filename, return result; } +static unsigned char * +calculate_db_checksum (const char *itdb_path, guint64 fwid) +{ + int fd; + struct stat stat_buf; + int result; + unsigned char *itdb_data; + unsigned char *checksum; + + fd = open (itdb_path, O_RDONLY); + if (fd < 0) { + g_warning ("Couldn't open %s", itdb_path); + return NULL; + } + + result = fstat (fd, &stat_buf); + if (result != 0) { + g_warning ("Couldn't stat %s", itdb_path); + close (fd); + return NULL; + } + + if (stat_buf.st_size < 0x80) { + g_warning ("%s is too small", itdb_path); + close (fd); + return NULL; + } + + itdb_data = mmap (NULL, stat_buf.st_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE, fd, 0); + if (itdb_data == MAP_FAILED) { + g_warning ("Couldn't mmap %s", itdb_path); + close (fd); + return NULL; + } + + /* Those fields must be zero'ed out for the sha1 calculation */ + memset(itdb_data+0x18, 0, 8); + memset(itdb_data+0x32, 0, 20); + memset(itdb_data+0x58, 0, 20); + + checksum = itdb_compute_hash (fwid, itdb_data, stat_buf.st_size); + + munmap (itdb_data, stat_buf.st_size); + close (fd); + + return checksum; +} + +static gboolean itdb_write_checksum_to_file (const char *path, + const unsigned char *checksum, + size_t size) +{ + FILE *f; + int result; + size_t count; + + f = fopen (path, "rb+"); + if (f == NULL) { + return FALSE; + } + + result = fseek (f, 0x58, SEEK_SET); + if (result != 0) { + fclose (f); + return FALSE; + } + + count = fwrite (checksum, size, 1, f); + fclose (f); + + return (count == 1); +} + +static gboolean itdb_write_checksum (Itdb_iTunesDB *db) +{ + guint64 fwid; + char *itdb_path; + unsigned char *checksum; + gboolean result; + + if (db->device == NULL) { + return FALSE; + } + + fwid = itdb_device_get_firewire_id (db->device); + if (fwid == 0) { + return FALSE; + } + + itdb_path = itdb_get_itunesdb_path (itdb_get_mountpoint (db)); + checksum = calculate_db_checksum (itdb_path, fwid); + + if (checksum == NULL) { + g_free (itdb_path); + return FALSE; + } + + result = itdb_write_checksum_to_file (itdb_path, checksum, + strlen ((char *)checksum)); + g_free (itdb_path); + + { + unsigned int i; + g_print ("Checksum: "); + for (i = 0; i < strlen ((char *)checksum); i++) { + g_print ("%02x ", checksum[i]); + } + } + g_print ("\n"); + g_free (checksum); + + return result; +} + /** * itdb_write: * @itdb: the #Itdb_iTunesDB to write to disk @@ -4965,8 +5104,16 @@ gboolean itdb_write (Itdb_iTunesDB *itdb, GError **error) g_free (itunes_filename); g_free (itunes_path); - if (result == TRUE) + if (result != FALSE) { + /* Set checksum (ipods require it starting from iPod Classic + * and fat Nanos) + */ + result = itdb_write_checksum (itdb); + if (!result) { + g_warning ("Couldn't set checksum"); + } + /* Write SysInfo file if it has changed */ if (itdb->device->sysinfo_changed) { diff --git a/src/itdb_sha1.c b/src/itdb_sha1.c new file mode 100644 index 0000000..5ad8751 --- /dev/null +++ b/src/itdb_sha1.c @@ -0,0 +1,247 @@ +/* +| Copyright (C) 2007 Christophe Fergeau <teuf@gnome.org> +| +| The code in this file is heavily based on the proof-of-concept code +| written by wtbw +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| +| 1. Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| 2. Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| 3. The name of the author may not be used to endorse or promote +| products derived from this software without specific prior written +| permission. +| +| THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +| IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +| OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +| IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +| INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +| BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +| OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +| OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +| OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +| OF SUCH DAMAGE. +| +| +| iTunes and iPod are trademarks of Apple +| +| This product is not supported/written/published by Apple! +*/ + +#include <glib.h> +#include "itdb_sha1.h" +#include "sha1.h" + +static const unsigned char invTable[256] = { + 0x74, 0x85, 0x96, 0xA7, 0xB8, 0xC9, 0xDA, 0xEB, + 0xFC, 0x0D, 0x1E, 0x2F, 0x40, 0x51, 0x62, 0x73, + 0x84, 0x95, 0xA6, 0xB7, 0xC8, 0xD9, 0xEA, 0xFB, + 0x0C, 0x1D, 0x2E, 0x3F, 0x50, 0x61, 0x72, 0x83, + 0x94, 0xA5, 0xB6, 0xC7, 0xD8, 0xE9, 0xFA, 0x0B, + 0x1C, 0x2D, 0x3E, 0x4F, 0x60, 0x71, 0x82, 0x93, + 0xA4, 0xB5, 0xC6, 0xD7, 0xE8, 0xF9, 0x0A, 0x1B, + 0x2C, 0x3D, 0x4E, 0x5F, 0x70, 0x81, 0x92, 0xA3, + 0xB4, 0xC5, 0xD6, 0xE7, 0xF8, 0x09, 0x1A, 0x2B, + 0x3C, 0x4D, 0x5E, 0x6F, 0x80, 0x91, 0xA2, 0xB3, + 0xC4, 0xD5, 0xE6, 0xF7, 0x08, 0x19, 0x2A, 0x3B, + 0x4C, 0x5D, 0x6E, 0x7F, 0x90, 0xA1, 0xB2, 0xC3, + 0xD4, 0xE5, 0xF6, 0x07, 0x18, 0x29, 0x3A, 0x4B, + 0x5C, 0x6D, 0x7E, 0x8F, 0xA0, 0xB1, 0xC2, 0xD3, + 0xE4, 0xF5, 0x06, 0x17, 0x28, 0x39, 0x4A, 0x5B, + 0x6C, 0x7D, 0x8E, 0x9F, 0xB0, 0xC1, 0xD2, 0xE3, + 0xF4, 0x05, 0x16, 0x27, 0x38, 0x49, 0x5A, 0x6B, + 0x7C, 0x8D, 0x9E, 0xAF, 0xC0, 0xD1, 0xE2, 0xF3, + 0x04, 0x15, 0x26, 0x37, 0x48, 0x59, 0x6A, 0x7B, + 0x8C, 0x9D, 0xAE, 0xBF, 0xD0, 0xE1, 0xF2, 0x03, + 0x14, 0x25, 0x36, 0x47, 0x58, 0x69, 0x7A, 0x8B, + 0x9C, 0xAD, 0xBE, 0xCF, 0xE0, 0xF1, 0x02, 0x13, + 0x24, 0x35, 0x46, 0x57, 0x68, 0x79, 0x8A, 0x9B, + 0xAC, 0xBD, 0xCE, 0xDF, 0xF0, 0x01, 0x12, 0x23, + 0x34, 0x45, 0x56, 0x67, 0x78, 0x89, 0x9A, 0xAB, + 0xBC, 0xCD, 0xDE, 0xEF, 0x00, 0x11, 0x22, 0x33, + 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xAA, 0xBB, + 0xCC, 0xDD, 0xEE, 0xFF, 0x10, 0x21, 0x32, 0x43, + 0x54, 0x65, 0x76, 0x87, 0x98, 0xA9, 0xBA, 0xCB, + 0xDC, 0xED, 0xFE, 0x0F, 0x20, 0x31, 0x42, 0x53, + 0x64, 0x75, 0x86, 0x97, 0xA8, 0xB9, 0xCA, 0xDB, + 0xEC, 0xFD, 0x0E, 0x1F, 0x30, 0x41, 0x52, 0x63 +}; + +static const unsigned char table1[256] = { + 0x3A, 0x3F, 0x3E, 0x72, 0xBD, 0xA2, 0xD6, 0xB4, + 0x63, 0xC0, 0x6E, 0x62, 0x59, 0x1E, 0xE2, 0x71, + 0xB5, 0x0D, 0xE8, 0x0C, 0x25, 0x38, 0xCE, 0x23, + 0x7C, 0xB7, 0xAD, 0x16, 0xDF, 0x47, 0x3D, 0xB3, + 0x7E, 0x8C, 0xAA, 0x61, 0x31, 0x66, 0xBE, 0x4F, + 0x97, 0x14, 0x54, 0xF0, 0x70, 0xEB, 0x30, 0xC4, + 0x27, 0x4E, 0xFA, 0x1A, 0x2B, 0x11, 0xF4, 0x45, + 0x8E, 0x5D, 0x73, 0xED, 0x22, 0x2E, 0x7D, 0xA4, + 0x28, 0xDA, 0x2F, 0xC5, 0x92, 0x09, 0x05, 0x13, + 0x9D, 0x32, 0x51, 0x4A, 0xC8, 0xBA, 0x96, 0xA7, + 0x6A, 0x50, 0xF3, 0xBC, 0x93, 0xBF, 0xB0, 0xD2, + 0xD5, 0x82, 0x19, 0x98, 0x35, 0xCF, 0x6B, 0xB6, + 0x83, 0x56, 0x15, 0xF2, 0x9A, 0x9C, 0xCA, 0x74, + 0x34, 0x58, 0x8D, 0xA6, 0x03, 0xFF, 0x46, 0x7B, + 0xD0, 0x7A, 0x33, 0x76, 0xDD, 0xAC, 0xCB, 0x24, + 0x7F, 0xB1, 0x85, 0x60, 0xC3, 0x26, 0x8A, 0x1D, + 0x1C, 0x8F, 0x2A, 0xEF, 0x06, 0xDE, 0x67, 0x5E, + 0xE7, 0xAE, 0xD9, 0xCC, 0x07, 0x6C, 0xF8, 0x0A, + 0xD3, 0x40, 0x36, 0x1F, 0x2D, 0x95, 0x43, 0xDB, + 0x01, 0x89, 0x4B, 0xF7, 0xB9, 0x39, 0xC2, 0x52, + 0x53, 0xFD, 0x65, 0xF5, 0x68, 0xC1, 0xC7, 0x9F, + 0x4D, 0xEA, 0xAF, 0x6D, 0x10, 0x44, 0x87, 0xD8, + 0xEE, 0x1B, 0xFE, 0x3C, 0xDC, 0x84, 0x69, 0x48, + 0x6F, 0xD1, 0x57, 0x55, 0xD4, 0xA5, 0x49, 0x5B, + 0xE5, 0x0B, 0x94, 0xC9, 0x5F, 0xE1, 0x17, 0x81, + 0xBB, 0xEC, 0xD7, 0xC6, 0x02, 0x4C, 0x42, 0x75, + 0xA3, 0x99, 0xE4, 0xA1, 0x9B, 0x5A, 0xF1, 0x29, + 0xA0, 0x64, 0x9E, 0x18, 0x41, 0x80, 0x2C, 0x79, + 0x20, 0x8B, 0xAB, 0x90, 0x08, 0xB8, 0xA9, 0x77, + 0x12, 0xF9, 0x0E, 0x88, 0xE9, 0x04, 0xFB, 0x86, + 0x0F, 0xE0, 0xA8, 0x5C, 0xE6, 0x21, 0xCD, 0x3B, + 0x00, 0x78, 0xFC, 0xF6, 0xE3, 0x37, 0xB2, 0x91 +}; + +static const unsigned char table2[256] = { + 0xF3, 0xE4, 0x1B, 0x38, 0xE5, 0x6F, 0xE8, 0x9D, + 0x3E, 0x55, 0xBA, 0xC7, 0xAC, 0xEA, 0x66, 0xA2, + 0xB9, 0x7A, 0x34, 0x43, 0x02, 0x4E, 0xFE, 0x36, + 0x41, 0x57, 0x1A, 0xB1, 0x31, 0x87, 0x04, 0x52, + 0x21, 0x22, 0xE1, 0x13, 0x7F, 0x03, 0x3A, 0x90, + 0xF7, 0x69, 0x78, 0x12, 0x83, 0x0B, 0x9A, 0x97, + 0x4D, 0xB7, 0x8C, 0xBF, 0x2D, 0x94, 0xD1, 0x93, + 0x2F, 0x42, 0x23, 0xA4, 0xE0, 0x92, 0xDC, 0x68, + 0xD3, 0xDD, 0xAF, 0x91, 0x9F, 0xED, 0x3D, 0x8F, + 0xA1, 0x51, 0xD9, 0xE9, 0x70, 0x28, 0xEF, 0xB3, + 0x49, 0xA5, 0x0D, 0xC5, 0xD0, 0x60, 0xB4, 0x2B, + 0x07, 0xF8, 0xDF, 0xE6, 0x16, 0xC0, 0x30, 0x71, + 0x85, 0xFD, 0x72, 0x95, 0x29, 0x79, 0x0A, 0x7B, + 0x46, 0x11, 0x7D, 0x88, 0x1D, 0x2A, 0x48, 0x1F, + 0x45, 0x89, 0x47, 0xEE, 0xBB, 0xBE, 0x6E, 0xC3, + 0x6C, 0xCE, 0x10, 0x5A, 0x2C, 0xCA, 0xFB, 0xB2, + 0xCB, 0x1C, 0x9C, 0xEC, 0x2E, 0x56, 0x59, 0x9B, + 0xA6, 0x53, 0xAE, 0x17, 0x25, 0xC1, 0x3F, 0x6A, + 0x0F, 0x09, 0x01, 0xA3, 0xD6, 0xA0, 0xD8, 0x08, + 0xE3, 0x74, 0x06, 0x6D, 0x19, 0x98, 0x1E, 0x77, + 0x76, 0xBC, 0xEB, 0x3C, 0xB0, 0xC4, 0xC8, 0x64, + 0x0E, 0x86, 0x63, 0xD7, 0xDB, 0xBD, 0xA7, 0x82, + 0x39, 0x4F, 0x27, 0xD2, 0x5F, 0x73, 0xF4, 0x75, + 0x6B, 0xC2, 0xD5, 0x67, 0x5D, 0x80, 0xAB, 0x81, + 0xDE, 0xF0, 0xAD, 0xAA, 0xCD, 0xB6, 0xF6, 0x7C, + 0xFC, 0x33, 0x05, 0x14, 0x96, 0x15, 0xC9, 0x9E, + 0x35, 0x5C, 0x7E, 0x44, 0x54, 0x58, 0x3B, 0x40, + 0x20, 0xA8, 0x8B, 0x5E, 0x4A, 0x24, 0x99, 0x8E, + 0xF5, 0xB5, 0x62, 0x00, 0x37, 0x5B, 0x18, 0x65, + 0x8D, 0x32, 0xE2, 0xF9, 0xDA, 0x8A, 0xD4, 0xCC, + 0x26, 0xF2, 0xF1, 0xE7, 0x4B, 0xC6, 0xCF, 0xFF, + 0x4C, 0x84, 0x61, 0xFA, 0xB8, 0x0C, 0xA9, 0x50 +}; + +static const unsigned char fixed[18] = { + 0x67, 0x23, 0xFE, 0x30, 0x45, 0x33, 0xF8, 0x90, 0x99, + 0x21, 0x07, 0xC1, 0xD0, 0x12, 0xB2, 0xA1, 0x07, 0x81 +}; + + +static int gcd(int a, int b){ + while (TRUE) + { + a = a % b; + if( a == 0 ) + return b; + b = b % a; + if( b == 0 ) + return a; + } +} + +static int lcm(int a, int b) +{ + if(a==0 || b==0) + return 1; + + return (a*b)/gcd(a,b); +} + +static unsigned char *generate_key (guint64 fwid) +{ + unsigned char *key; + unsigned char y[16]; + SHA_INFO context; + int i; + guint64 fwid_be = GUINT64_TO_BE (fwid); + const unsigned char *firewire_id = (const unsigned char *)&fwid_be; + + /* take LCM of each two bytes in the FWID in turn */ + for (i=0; i<4; i++){ + int a = firewire_id[i*2]; + int b = firewire_id[i*2+1]; + int cur_lcm = lcm(a,b); + + unsigned char hi = (cur_lcm & 0xFF00) >> 8; + unsigned char lo = cur_lcm & 0xFF; + + y[i*4] = ((table1[hi] * 0xB5) - 3); + y[i*4 + 1] = ((table2[hi] * 0xB7) + 0x49); + y[i*4 + 2] = ((table1[lo] * 0xB5) - 3); + y[i*4 + 3] = ((table2[lo] * 0xB7) + 0x49); + } + + /* convert y */ + for(i=0;i<16;i++){ + y[i] = invTable[y[i]]; + } + + /* hash */ + sha_init(&context); + sha_update(&context, fixed, 18); + sha_update(&context, y, 16); + + key = g_new0 (unsigned char, 64); + sha_final(key, &context); + + return key; +} + +unsigned char *itdb_compute_hash (guint64 firewire_id, + const unsigned char *itdb, + unsigned long size) +{ + unsigned char *key; + unsigned char *hash; + SHA_INFO context; + int i; + + key = generate_key(firewire_id); + + /* hmac sha1 */ + for (i=0; i < 64; i++) + { + key[i] ^= 0x36; + } + + /* 20 bytes for the checksum, and 1 trailing \0 */ + hash = g_new0 (unsigned char, 21); + sha_init(&context); + sha_update(&context, key, 64); + sha_update(&context, itdb, size); + sha_final(hash, &context); + + for (i=0; i < 64; i++) + key[i] ^= 0x36 ^ 0x5c; + + sha_init(&context); + sha_update(&context, key, 64); + sha_update(&context, hash, 20); + sha_final(hash, &context); + + g_free (key); + + return hash; +} diff --git a/src/itdb_sha1.h b/src/itdb_sha1.h new file mode 100644 index 0000000..1effb8b --- /dev/null +++ b/src/itdb_sha1.h @@ -0,0 +1,37 @@ +/* +| Copyright (C) 2002-2007 Jorg Schuler <jcsjcs at users sourceforge net> +| Part of the gtkpod project. +| +| URL: http://www.gtkpod.org/ +| URL: http://gtkpod.sourceforge.net/ +| +| The code contained in this file is free software; you can redistribute +| it and/or modify it under the terms of the GNU Lesser General Public +| License as published by the Free Software Foundation; either version +| 2.1 of the License, or (at your option) any later version. +| +| This file 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 +| Lesser General Public License for more details. +| +| You should have received a copy of the GNU Lesser General Public +| License along with this code; if not, write to the Free Software +| Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +| +| iTunes and iPod are trademarks of Apple +| +| This product is not supported/written/published by Apple! +| +| $Id$ +*/ + +#ifndef __ITDB_SHA1_H__ +#define __ITDB_SHA1_H__ + +#include <glib.h> + +unsigned char *itdb_compute_hash (guint64 firewire_id, + const unsigned char *itdb, + unsigned long size); +#endif diff --git a/src/sha1.c b/src/sha1.c new file mode 100644 index 0000000..e92f734 --- /dev/null +++ b/src/sha1.c @@ -0,0 +1,450 @@ +/* (PD) 2001 The Bitzi Corporation + * Please see file COPYING or http://bitzi.com/publicdomain + * for more info. + * + * NIST Secure Hash Algorithm + * heavily modified by Uwe Hollerbach <uh@alumni.caltech edu> + * from Peter C. Gutmann's implementation as found in + * Applied Cryptography by Bruce Schneier + * Further modifications to include the "UNRAVEL" stuff, below + * + * This code is in the public domain + * + * $Id: sha1.c,v 1.1 2005-12-28 18:06:50 tpm Exp $ + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include <glib.h> +#define SHA_BYTE_ORDER G_BYTE_ORDER + +#include <string.h> +#include "sha1.h" + +/* UNRAVEL should be fastest & biggest */ +/* UNROLL_LOOPS should be just as big, but slightly slower */ +/* both undefined should be smallest and slowest */ + +#define UNRAVEL +/* #define UNROLL_LOOPS */ + +/* SHA f()-functions */ + +#define f1(x,y,z) ((x & y) | (~x & z)) +#define f2(x,y,z) (x ^ y ^ z) +#define f3(x,y,z) ((x & y) | (x & z) | (y & z)) +#define f4(x,y,z) (x ^ y ^ z) + +/* SHA constants */ + +#define CONST1 0x5a827999L +#define CONST2 0x6ed9eba1L +#define CONST3 0x8f1bbcdcL +#define CONST4 0xca62c1d6L + +/* truncate to 32 bits -- should be a null op on 32-bit machines */ + +#define T32(x) ((x) & 0xffffffffL) + +/* 32-bit rotate */ + +#define R32(x,n) T32(((x << n) | (x >> (32 - n)))) + +/* the generic case, for when the overall rotation is not unraveled */ + +#define FG(n) \ + T = T32(R32(A,5) + f##n(B,C,D) + E + *WP++ + CONST##n); \ + E = D; D = C; C = R32(B,30); B = A; A = T + +/* specific cases, for when the overall rotation is unraveled */ + +#define FA(n) \ + T = T32(R32(A,5) + f##n(B,C,D) + E + *WP++ + CONST##n); B = R32(B,30) + +#define FB(n) \ + E = T32(R32(T,5) + f##n(A,B,C) + D + *WP++ + CONST##n); A = R32(A,30) + +#define FC(n) \ + D = T32(R32(E,5) + f##n(T,A,B) + C + *WP++ + CONST##n); T = R32(T,30) + +#define FD(n) \ + C = T32(R32(D,5) + f##n(E,T,A) + B + *WP++ + CONST##n); E = R32(E,30) + +#define FE(n) \ + B = T32(R32(C,5) + f##n(D,E,T) + A + *WP++ + CONST##n); D = R32(D,30) + +#define FT(n) \ + A = T32(R32(B,5) + f##n(C,D,E) + T + *WP++ + CONST##n); C = R32(C,30) + +/* do SHA transformation */ + +static void +sha_transform (SHA_INFO * sha_info) +{ + int i; + SHA_BYTE *dp; + SHA_LONG T, A, B, C, D, E, W[80], *WP; + + dp = sha_info->data; + +/* +the following makes sure that at least one code block below is +traversed or an error is reported, without the necessity for nested +preprocessor if/else/endif blocks, which are a great pain in the +nether regions of the anatomy... +*/ +#undef SWAP_DONE + +#if (SHA_BYTE_ORDER == 1234) +#define SWAP_DONE + for (i = 0; i < 16; ++i) { + T = *((SHA_LONG *) dp); + dp += 4; + W[i] = ((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) | + ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff); + } +#endif /* SHA_BYTE_ORDER == 1234 */ + +#if (SHA_BYTE_ORDER == 4321) +#define SWAP_DONE + for (i = 0; i < 16; ++i) { + T = *((SHA_LONG *) dp); + dp += 4; + W[i] = T32 (T); + } +#endif /* SHA_BYTE_ORDER == 4321 */ + +#if (SHA_BYTE_ORDER == 12345678) +#define SWAP_DONE + for (i = 0; i < 16; i += 2) { + T = *((SHA_LONG *) dp); + dp += 8; + W[i] = ((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) | + ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff); + T >>= 32; + W[i + 1] = ((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) | + ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff); + } +#endif /* SHA_BYTE_ORDER == 12345678 */ + +#if (SHA_BYTE_ORDER == 87654321) +#define SWAP_DONE + for (i = 0; i < 16; i += 2) { + T = *((SHA_LONG *) dp); + dp += 8; + W[i] = T32 (T >> 32); + W[i + 1] = T32 (T); + } +#endif /* SHA_BYTE_ORDER == 87654321 */ + +#ifndef SWAP_DONE +#error Unknown byte order -- you need to add code here +#endif /* SWAP_DONE */ + + for (i = 16; i < 80; ++i) { + W[i] = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16]; +#if (SHA_VERSION == 1) + W[i] = R32 (W[i], 1); +#endif /* SHA_VERSION */ + } + A = sha_info->digest[0]; + B = sha_info->digest[1]; + C = sha_info->digest[2]; + D = sha_info->digest[3]; + E = sha_info->digest[4]; + WP = W; +#ifdef UNRAVEL + FA (1); + FB (1); + FC (1); + FD (1); + FE (1); + FT (1); + FA (1); + FB (1); + FC (1); + FD (1); + FE (1); + FT (1); + FA (1); + FB (1); + FC (1); + FD (1); + FE (1); + FT (1); + FA (1); + FB (1); + FC (2); + FD (2); + FE (2); + FT (2); + FA (2); + FB (2); + FC (2); + FD (2); + FE (2); + FT (2); + FA (2); + FB (2); + FC (2); + FD (2); + FE (2); + FT (2); + FA (2); + FB (2); + FC (2); + FD (2); + FE (3); + FT (3); + FA (3); + FB (3); + FC (3); + FD (3); + FE (3); + FT (3); + FA (3); + FB (3); + FC (3); + FD (3); + FE (3); + FT (3); + FA (3); + FB (3); + FC (3); + FD (3); + FE (3); + FT (3); + FA (4); + FB (4); + FC (4); + FD (4); + FE (4); + FT (4); + FA (4); + FB (4); + FC (4); + FD (4); + FE (4); + FT (4); + FA (4); + FB (4); + FC (4); + FD (4); + FE (4); + FT (4); + FA (4); + FB (4); + sha_info->digest[0] = T32 (sha_info->digest[0] + E); + sha_info->digest[1] = T32 (sha_info->digest[1] + T); + sha_info->digest[2] = T32 (sha_info->digest[2] + A); + sha_info->digest[3] = T32 (sha_info->digest[3] + B); + sha_info->digest[4] = T32 (sha_info->digest[4] + C); +#else /* !UNRAVEL */ +#ifdef UNROLL_LOOPS + FG (1); + FG (1); + FG (1); + FG (1); + FG (1); + FG (1); + FG (1); + FG (1); + FG (1); + FG (1); + FG (1); + FG (1); + FG (1); + FG (1); + FG (1); + FG (1); + FG (1); + FG (1); + FG (1); + FG (1); + FG (2); + FG (2); + FG (2); + FG (2); + FG (2); + FG (2); + FG (2); + FG (2); + FG (2); + FG (2); + FG (2); + FG (2); + FG (2); + FG (2); + FG (2); + FG (2); + FG (2); + FG (2); + FG (2); + FG (2); + FG (3); + FG (3); + FG (3); + FG (3); + FG (3); + FG (3); + FG (3); + FG (3); + FG (3); + FG (3); + FG (3); + FG (3); + FG (3); + FG (3); + FG (3); + FG (3); + FG (3); + FG (3); + FG (3); + FG (3); + FG (4); + FG (4); + FG (4); + FG (4); + FG (4); + FG (4); + FG (4); + FG (4); + FG (4); + FG (4); + FG (4); + FG (4); + FG (4); + FG (4); + FG (4); + FG (4); + FG (4); + FG (4); + FG (4); + FG (4); +#else /* !UNROLL_LOOPS */ + for (i = 0; i < 20; ++i) { + FG (1); + } + for (i = 20; i < 40; ++i) { + FG (2); + } + for (i = 40; i < 60; ++i) { + FG (3); + } + for (i = 60; i < 80; ++i) { + FG (4); + } +#endif /* !UNROLL_LOOPS */ + sha_info->digest[0] = T32 (sha_info->digest[0] + A); + sha_info->digest[1] = T32 (sha_info->digest[1] + B); + sha_info->digest[2] = T32 (sha_info->digest[2] + C); + sha_info->digest[3] = T32 (sha_info->digest[3] + D); + sha_info->digest[4] = T32 (sha_info->digest[4] + E); +#endif /* !UNRAVEL */ +} + +/* initialize the SHA digest */ + +void +sha_init (SHA_INFO * sha_info) +{ + sha_info->digest[0] = 0x67452301L; + sha_info->digest[1] = 0xefcdab89L; + sha_info->digest[2] = 0x98badcfeL; + sha_info->digest[3] = 0x10325476L; + sha_info->digest[4] = 0xc3d2e1f0L; + sha_info->count_lo = 0L; + sha_info->count_hi = 0L; + sha_info->local = 0; +} + +/* update the SHA digest */ + +void +sha_update (SHA_INFO * sha_info, const SHA_BYTE * buffer, int count) +{ + int i; + SHA_LONG clo; + + clo = T32 (sha_info->count_lo + ((SHA_LONG) count << 3)); + if (clo < sha_info->count_lo) { + ++sha_info->count_hi; + } + sha_info->count_lo = clo; + sha_info->count_hi += (SHA_LONG) count >> 29; + if (sha_info->local) { + i = SHA_BLOCKSIZE - sha_info->local; + if (i > count) { + i = count; + } + memcpy (((SHA_BYTE *) sha_info->data) + sha_info->local, buffer, i); + count -= i; + buffer += i; + sha_info->local += i; + if (sha_info->local == SHA_BLOCKSIZE) { + sha_transform (sha_info); + } else { + return; + } + } + while (count >= SHA_BLOCKSIZE) { + memcpy (sha_info->data, buffer, SHA_BLOCKSIZE); + buffer += SHA_BLOCKSIZE; + count -= SHA_BLOCKSIZE; + sha_transform (sha_info); + } + memcpy (sha_info->data, buffer, count); + sha_info->local = count; +} + +/* finish computing the SHA digest */ + +void +sha_final (unsigned char digest[20], SHA_INFO * sha_info) +{ + int count; + SHA_LONG lo_bit_count, hi_bit_count; + + lo_bit_count = sha_info->count_lo; + hi_bit_count = sha_info->count_hi; + count = (int) ((lo_bit_count >> 3) & 0x3f); + ((SHA_BYTE *) sha_info->data)[count++] = 0x80; + if (count > SHA_BLOCKSIZE - 8) { + memset (((SHA_BYTE *) sha_info->data) + count, 0, SHA_BLOCKSIZE - count); + sha_transform (sha_info); + memset ((SHA_BYTE *) sha_info->data, 0, SHA_BLOCKSIZE - 8); + } else { + memset (((SHA_BYTE *) sha_info->data) + count, 0, + SHA_BLOCKSIZE - 8 - count); + } + sha_info->data[56] = (unsigned char) ((hi_bit_count >> 24) & 0xff); + sha_info->data[57] = (unsigned char) ((hi_bit_count >> 16) & 0xff); + sha_info->data[58] = (unsigned char) ((hi_bit_count >> 8) & 0xff); + sha_info->data[59] = (unsigned char) ((hi_bit_count >> 0) & 0xff); + sha_info->data[60] = (unsigned char) ((lo_bit_count >> 24) & 0xff); + sha_info->data[61] = (unsigned char) ((lo_bit_count >> 16) & 0xff); + sha_info->data[62] = (unsigned char) ((lo_bit_count >> 8) & 0xff); + sha_info->data[63] = (unsigned char) ((lo_bit_count >> 0) & 0xff); + sha_transform (sha_info); + digest[0] = (unsigned char) ((sha_info->digest[0] >> 24) & 0xff); + digest[1] = (unsigned char) ((sha_info->digest[0] >> 16) & 0xff); + digest[2] = (unsigned char) ((sha_info->digest[0] >> 8) & 0xff); + digest[3] = (unsigned char) ((sha_info->digest[0]) & 0xff); + digest[4] = (unsigned char) ((sha_info->digest[1] >> 24) & 0xff); + digest[5] = (unsigned char) ((sha_info->digest[1] >> 16) & 0xff); + digest[6] = (unsigned char) ((sha_info->digest[1] >> 8) & 0xff); + digest[7] = (unsigned char) ((sha_info->digest[1]) & 0xff); + digest[8] = (unsigned char) ((sha_info->digest[2] >> 24) & 0xff); + digest[9] = (unsigned char) ((sha_info->digest[2] >> 16) & 0xff); + digest[10] = (unsigned char) ((sha_info->digest[2] >> 8) & 0xff); + digest[11] = (unsigned char) ((sha_info->digest[2]) & 0xff); + digest[12] = (unsigned char) ((sha_info->digest[3] >> 24) & 0xff); + digest[13] = (unsigned char) ((sha_info->digest[3] >> 16) & 0xff); + digest[14] = (unsigned char) ((sha_info->digest[3] >> 8) & 0xff); + digest[15] = (unsigned char) ((sha_info->digest[3]) & 0xff); + digest[16] = (unsigned char) ((sha_info->digest[4] >> 24) & 0xff); + digest[17] = (unsigned char) ((sha_info->digest[4] >> 16) & 0xff); + digest[18] = (unsigned char) ((sha_info->digest[4] >> 8) & 0xff); + digest[19] = (unsigned char) ((sha_info->digest[4]) & 0xff); +} diff --git a/src/sha1.h b/src/sha1.h new file mode 100644 index 0000000..2c8ea66 --- /dev/null +++ b/src/sha1.h @@ -0,0 +1,62 @@ +/* NIST Secure Hash Algorithm */ +/* heavily modified by Uwe Hollerbach <uh@alumni.caltech edu> */ +/* from Peter C. Gutmann's implementation as found in */ +/* Applied Cryptography by Bruce Schneier */ +/* This code is in the public domain */ +/* $Id: sha1.h,v 1.1 2005-12-28 18:06:50 tpm Exp $ */ + +#ifndef __GST_CDDA_SHA_H__ +#define __GST_CDDA_SHA_H__ + +#include <stdlib.h> +#include <stdio.h> + +/* Useful defines & typedefs */ +typedef unsigned char SHA_BYTE; /* 8-bit quantity */ +typedef unsigned long SHA_LONG; /* 32-or-more-bit quantity */ + +#define SHA_BLOCKSIZE 64 +#define SHA_DIGESTSIZE 20 + +typedef struct { + SHA_LONG digest[5]; /* message digest */ + SHA_LONG count_lo, count_hi; /* 64-bit bit count */ + SHA_BYTE data[SHA_BLOCKSIZE]; /* SHA data buffer */ + int local; /* unprocessed amount in data */ +} SHA_INFO; + +#define sha_init itdb_sha_init +#define sha_update itdb_sha_update +#define sha_final itdb_sha_final + +G_GNUC_INTERNAL void sha_init(SHA_INFO *); +G_GNUC_INTERNAL void sha_update(SHA_INFO *, const SHA_BYTE *, int); +G_GNUC_INTERNAL void sha_final(unsigned char [20], SHA_INFO *); + +#define SHA_VERSION 1 + +#ifdef HAVE_CONFIG_H +#include "config.h" + + +#ifdef WORDS_BIGENDIAN +# if SIZEOF_LONG == 4 +# define SHA_BYTE_ORDER 4321 +# elif SIZEOF_LONG == 8 +# define SHA_BYTE_ORDER 87654321 +# endif +#else +# if SIZEOF_LONG == 4 +# define SHA_BYTE_ORDER 1234 +# elif SIZEOF_LONG == 8 +# define SHA_BYTE_ORDER 12345678 +# endif +#endif + +#else + +#define SHA_BYTE_ORDER 1234 + +#endif + +#endif /* __GST_CDDA_SHA_H__ */ diff --git a/tests/Makefile.am b/tests/Makefile.am index 4d3e89f..17c9cb7 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -1,5 +1,5 @@ if HAVE_GDKPIXBUF -TESTTHUMBS=test-thumbnails test-write-thumbnails test-photos get-timezone +TESTTHUMBS=test-thumbnails test-write-thumbnails test-photos get-timezone test_thumbnails_SOURCES = test-covers.c test_thumbnails_CFLAGS = $(AM_CFLAGS) @@ -33,9 +33,14 @@ test_ls_LDADD = test_init_ipod_SOURCES = test-init-ipod.c test_init_ipod_LDADD = +test_checksum_SOURCES = test-checksum.c + +test_firewire_id_SOURCES = test-fw-id.c + get_timezone_SOURCES = get-timezone.c -noinst_PROGRAMS=test-itdb test-ls $(TESTTHUMBS) $(TESTTAGLIB) $(TESTMISC) +noinst_PROGRAMS=test-itdb test-ls test-checksum test-firewire-id \ + $(TESTTHUMBS) $(TESTTAGLIB) $(TESTMISC) INCLUDES=$(LIBGPOD_CFLAGS) -I$(top_srcdir)/src -DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" LIBS=$(LIBGPOD_LIBS) $(top_builddir)/src/libgpod.la diff --git a/tests/test-checksum.c b/tests/test-checksum.c new file mode 100644 index 0000000..3f9ef85 --- /dev/null +++ b/tests/test-checksum.c @@ -0,0 +1,181 @@ +/* +| Copyright (C) 2007 Christophe Fergeau <teuf@gnome.org> +| +| The code in this file is heavily based on the proof-of-concept code +| written by wtbw +| +| Redistribution and use in source and binary forms, with or without +| modification, are permitted provided that the following conditions are met: +| +| 1. Redistributions of source code must retain the above copyright +| notice, this list of conditions and the following disclaimer. +| 2. Redistributions in binary form must reproduce the above copyright +| notice, this list of conditions and the following disclaimer in the +| documentation and/or other materials provided with the distribution. +| 3. The name of the author may not be used to endorse or promote +| products derived from this software without specific prior written +| permission. +| +| THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +| IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +| OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +| IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +| INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +| BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +| OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +| OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +| OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY +| OF SUCH DAMAGE. +| +| +| iTunes and iPod are trademarks of Apple +| +| This product is not supported/written/published by Apple! +*/ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <glib.h> + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/stat.h> + +#include "itdb.h" +#include "itdb_sha1.h" + +static unsigned char * +calculate_db_checksum (const char *itdb_path, guint64 fwid) +{ + int fd; + struct stat stat_buf; + int result; + unsigned char *itdb_data; + unsigned char *checksum; + + fd = open (itdb_path, O_RDONLY); + if (fd < 0) { + g_warning ("Couldn't open %s", itdb_path); + return NULL; + } + + result = fstat (fd, &stat_buf); + if (result != 0) { + g_warning ("Couldn't stat %s", itdb_path); + close (fd); + return NULL; + } + + if (stat_buf.st_size < 0x80) { + g_warning ("%s is too small", itdb_path); + close (fd); + return NULL; + } + + itdb_data = mmap (NULL, stat_buf.st_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE, fd, 0); + if (itdb_data == MAP_FAILED) { + g_warning ("Couldn't mmap %s", itdb_path); + close (fd); + return NULL; + } + + /* Those fields must be zero'ed out for the sha1 calculation */ + memset(itdb_data+0x18, 0, 8); + memset(itdb_data+0x32, 0, 20); + memset(itdb_data+0x58, 0, 20); + + checksum = itdb_compute_hash (fwid, itdb_data, stat_buf.st_size); + + munmap (itdb_data, stat_buf.st_size); + close (fd); + + return checksum; +} + +static gboolean write_checksum_to_file (const char *path, + const unsigned char *checksum, + size_t size) +{ + FILE *f; + int result; + size_t count; + + f = fopen (path, "rb+"); + if (f == NULL) { + return FALSE; + } + + result = fseek (f, 0x58, SEEK_SET); + if (result != 0) { + fclose (f); + return FALSE; + } + + count = fwrite (checksum, size, 1, f); + fclose (f); + + return (count == 1); +} + +int +main (int argc, char *argv[]) +{ + char *itdb_path; + guint64 firewire_id; + unsigned char *checksum; + int i; + + if (argc < 3) { + g_print ("Usage: %s <mountpoint> <firewire_id> [write]\n" + " firewire_id in hexadecimal, e.g. 00A745....\n" + " If any third argument is given, the checksum is written back to the iTunesDB.\n", + g_basename(argv[0])); + exit (0); + } + + errno = 0; + firewire_id = strtoull (argv[2], NULL, 16); + if (errno != 0) { + g_warning ("Couldn't parse %s as a firewire ID\n", argv[2]); + exit (0); + } + + itdb_path = itdb_get_itunesdb_path (argv[1]); + checksum = calculate_db_checksum (itdb_path, firewire_id); + + if (argc >= 4) + { + gboolean success; + + success = write_checksum_to_file (itdb_path, checksum, 20); + if (!success) + { + g_warning ("Couldn't write checksum back to file '%s'\n", + argv[1]); + } + } + + g_free (itdb_path); + + if (checksum == NULL) { + g_warning ("Couldn't compute checksum"); + exit (0); + } + + for (i = 0; i < strlen ((char *)checksum); i++) { + g_print ("%02x ", checksum[i]); + } + g_print ("\n"); + g_free (checksum); + + return 0; +} diff --git a/tests/test-fw-id.c b/tests/test-fw-id.c new file mode 100644 index 0000000..9ec40e9 --- /dev/null +++ b/tests/test-fw-id.c @@ -0,0 +1,65 @@ +/* +| Copyright (C) 2007 Christophe Fergeau <teuf@gnome.org> +| +| 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 program 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 this program; if not, write to the Free Software +| Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +| +| iTunes and iPod are trademarks of Apple +| +| This product is not supported/written/published by Apple! +| +*/ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <libintl.h> + +#include "itdb.h" +#include "itdb_device.h" + +int +main (int argc, char *argv[]) +{ + Itdb_Device *device; + char *fwid; + + if (argc < 2) { + g_print ("Usage: %s <mountpoint>\n", g_basename (argv[0])); + return 1; + + } + + device = itdb_device_new (); + if (device == NULL) { + return 1; + } + + itdb_device_set_mountpoint (device, argv[1]); + + fwid = itdb_device_get_sysinfo (device, "FirewireGuid"); + if (fwid == NULL) { + g_print ("Couldn't find firewire ID\n"); + return 1; + } else { + g_print ("FireWire ID: %s\n", fwid); + } + + return 0; +} |