summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog27
-rw-r--r--docs/reference/tmpl/device.sgml1
-rw-r--r--src/Makefile.am36
-rw-r--r--src/itdb_device.c30
-rw-r--r--src/itdb_device.h4
-rw-r--r--src/itdb_itunesdb.c159
-rw-r--r--src/itdb_sha1.c247
-rw-r--r--src/itdb_sha1.h37
-rw-r--r--src/sha1.c450
-rw-r--r--src/sha1.h62
-rw-r--r--tests/Makefile.am9
-rw-r--r--tests/test-checksum.c181
-rw-r--r--tests/test-fw-id.c65
13 files changed, 1281 insertions, 27 deletions
diff --git a/ChangeLog b/ChangeLog
index aa6996f..5cd1fa0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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;
+}