Blame src/itdb_hash58.c

Packit 29108b
/*
Packit 29108b
|  Copyright (C) 2007 Christophe Fergeau <teuf@gnome.org>
Packit 29108b
|
Packit 29108b
|  The code in this file is heavily based on the proof-of-concept code
Packit 29108b
|  written by wtbw
Packit 29108b
|
Packit 29108b
| Redistribution and use in source and binary forms, with or without
Packit 29108b
| modification, are permitted provided that the following conditions are met:
Packit 29108b
|
Packit 29108b
|   1. Redistributions of source code must retain the above copyright
Packit 29108b
| notice, this list of conditions and the following disclaimer.
Packit 29108b
|   2. Redistributions in binary form must reproduce the above copyright
Packit 29108b
| notice, this list of conditions and the following disclaimer in the
Packit 29108b
| documentation and/or other materials provided with the distribution.
Packit 29108b
|   3. The name of the author may not be used to endorse or promote
Packit 29108b
| products derived from this software without specific prior written
Packit 29108b
| permission.
Packit 29108b
|
Packit 29108b
| THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
Packit 29108b
| IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
Packit 29108b
| OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
Packit 29108b
| IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
Packit 29108b
| INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
Packit 29108b
| BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
Packit 29108b
| OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
Packit 29108b
| ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
Packit 29108b
| OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
Packit 29108b
| OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
Packit 29108b
| OF SUCH DAMAGE.
Packit 29108b
|
Packit 29108b
|
Packit 29108b
|  iTunes and iPod are trademarks of Apple
Packit 29108b
|
Packit 29108b
|  This product is not supported/written/published by Apple!
Packit 29108b
*/
Packit 29108b
#ifdef HAVE_CONFIG_H
Packit 29108b
#include <config.h>
Packit 29108b
#endif
Packit 29108b
#include <glib.h>
Packit 29108b
#include <string.h>
Packit 29108b
#include "itdb.h"
Packit 29108b
#include "db-itunes-parser.h"
Packit 29108b
#include "itdb_private.h"
Packit 29108b
Packit 29108b
static const unsigned char table1[256] = {
Packit 29108b
	0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 
Packit 29108b
	0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
Packit 29108b
	0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 
Packit 29108b
	0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
Packit 29108b
	0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 
Packit 29108b
	0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
Packit 29108b
	0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 
Packit 29108b
	0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
Packit 29108b
	0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 
Packit 29108b
	0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
Packit 29108b
	0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 
Packit 29108b
	0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
Packit 29108b
	0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 
Packit 29108b
	0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
Packit 29108b
	0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 
Packit 29108b
	0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
Packit 29108b
	0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 
Packit 29108b
	0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
Packit 29108b
	0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 
Packit 29108b
	0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
Packit 29108b
	0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 
Packit 29108b
	0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
Packit 29108b
	0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 
Packit 29108b
	0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
Packit 29108b
	0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 
Packit 29108b
	0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
Packit 29108b
	0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 
Packit 29108b
	0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
Packit 29108b
	0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 
Packit 29108b
	0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
Packit 29108b
	0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 
Packit 29108b
	0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
Packit 29108b
};
Packit 29108b
Packit 29108b
static const unsigned char table2[256] = {
Packit 29108b
	0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 
Packit 29108b
	0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
Packit 29108b
	0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 
Packit 29108b
	0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
Packit 29108b
	0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 
Packit 29108b
	0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
Packit 29108b
	0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 
Packit 29108b
	0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
Packit 29108b
	0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 
Packit 29108b
	0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
Packit 29108b
	0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 
Packit 29108b
	0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
Packit 29108b
	0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 
Packit 29108b
	0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
Packit 29108b
	0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 
Packit 29108b
	0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
Packit 29108b
	0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 
Packit 29108b
	0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
Packit 29108b
	0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 
Packit 29108b
	0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
Packit 29108b
	0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 
Packit 29108b
	0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
Packit 29108b
	0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 
Packit 29108b
	0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
Packit 29108b
	0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 
Packit 29108b
	0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
Packit 29108b
	0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 
Packit 29108b
	0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
Packit 29108b
	0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 
Packit 29108b
	0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
Packit 29108b
	0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 
Packit 29108b
	0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
Packit 29108b
};
Packit 29108b
Packit 29108b
static const unsigned char fixed[18] = {
Packit 29108b
    0x67, 0x23, 0xFE, 0x30, 0x45, 0x33, 0xF8, 0x90, 0x99,
Packit 29108b
    0x21, 0x07, 0xC1, 0xD0, 0x12, 0xB2, 0xA1, 0x07, 0x81
Packit 29108b
};
Packit 29108b
Packit 29108b
#ifndef HAVE_G_CHECKSUM_RESET
Packit 29108b
#define g_checksum_reset(checksum)                      \
Packit 29108b
G_STMT_START {                                          \
Packit 29108b
    g_checksum_free(checksum);                          \
Packit 29108b
    (checksum) = g_checksum_new (G_CHECKSUM_SHA1);      \
Packit 29108b
} G_STMT_END
Packit 29108b
#endif
Packit 29108b
Packit 29108b
static int gcd(int a, int b){
Packit 29108b
    while (TRUE)
Packit 29108b
    {
Packit 29108b
        a = a % b;
Packit 29108b
        if( a == 0 )
Packit 29108b
            return b;
Packit 29108b
        b = b % a;
Packit 29108b
        if( b == 0 )
Packit 29108b
            return a;
Packit 29108b
    }
Packit 29108b
}
Packit 29108b
Packit 29108b
static int lcm(int a, int b)
Packit 29108b
{
Packit 29108b
    if(a==0 || b==0)
Packit 29108b
        return 1;
Packit 29108b
Packit 29108b
    return (a*b)/gcd(a,b);
Packit 29108b
}
Packit 29108b
Packit 29108b
static unsigned char *generate_key (const unsigned char *firewire_id)
Packit 29108b
{
Packit 29108b
    unsigned char *key;
Packit 29108b
    unsigned char y[16];
Packit 29108b
    GChecksum *checksum;
Packit 29108b
    gsize checksum_len;
Packit 29108b
    int i;
Packit 29108b
Packit 29108b
    /* take LCM of each two bytes in the FWID in turn */
Packit 29108b
    for (i=0; i<4; i++){
Packit 29108b
        int a = firewire_id[i*2];
Packit 29108b
        int b = firewire_id[i*2+1];
Packit 29108b
        int cur_lcm = lcm(a,b);
Packit 29108b
Packit 29108b
        unsigned char hi = (cur_lcm & 0xFF00) >> 8;
Packit 29108b
        unsigned char lo = cur_lcm & 0xFF;
Packit 29108b
Packit 29108b
        y[i*4    ] = table1[hi];
Packit 29108b
        y[i*4 + 1] = table2[hi];
Packit 29108b
        y[i*4 + 2] = table1[lo];
Packit 29108b
        y[i*4 + 3] = table2[lo];
Packit 29108b
    }
Packit 29108b
Packit 29108b
    /* hash */
Packit 29108b
    checksum = g_checksum_new (G_CHECKSUM_SHA1);
Packit 29108b
    g_checksum_update (checksum, fixed, sizeof (fixed));
Packit 29108b
    g_checksum_update (checksum, y, sizeof (y));
Packit 29108b
Packit 29108b
    key = g_new0 (unsigned char, 64);
Packit 29108b
    checksum_len = 64;
Packit 29108b
    g_checksum_get_digest (checksum, key, &checksum_len);
Packit 29108b
    g_checksum_free (checksum);
Packit 29108b
Packit 29108b
    return key;
Packit 29108b
}
Packit 29108b
Packit 29108b
static unsigned char *itdb_compute_hash (const unsigned char *firewire_id,
Packit 29108b
					 const unsigned char *itdb,
Packit 29108b
					 unsigned long size, 
Packit 29108b
					 gsize *len)
Packit 29108b
{
Packit 29108b
    unsigned char *key;
Packit 29108b
    unsigned char *hash;
Packit 29108b
    GChecksum *checksum;
Packit 29108b
    int i;
Packit 29108b
    const gsize CHECKSUM_LEN = g_checksum_type_get_length (G_CHECKSUM_SHA1);
Packit 29108b
    gsize digest_len;
Packit 29108b
    
Packit 29108b
    key = generate_key(firewire_id);
Packit 29108b
    if (key == NULL) {
Packit 29108b
	return NULL;
Packit 29108b
    }
Packit 29108b
Packit 29108b
    /* hmac sha1 */
Packit 29108b
    for (i=0; i < 64; i++)
Packit 29108b
    {
Packit 29108b
        key[i] ^= 0x36;
Packit 29108b
    }
Packit 29108b
Packit 29108b
    /* 20 bytes for the checksum, and 1 trailing \0 */
Packit 29108b
    hash = g_new0 (unsigned char, CHECKSUM_LEN+1);
Packit 29108b
    checksum = g_checksum_new (G_CHECKSUM_SHA1);
Packit 29108b
    g_checksum_update (checksum, key, 64);
Packit 29108b
    g_checksum_update (checksum, itdb, size);
Packit 29108b
    digest_len = CHECKSUM_LEN;
Packit 29108b
    g_checksum_get_digest (checksum, hash, &digest_len);
Packit 29108b
    g_assert (digest_len == CHECKSUM_LEN);
Packit 29108b
Packit 29108b
    for (i=0; i < 64; i++)
Packit 29108b
        key[i] ^= 0x36 ^ 0x5c;
Packit 29108b
Packit 29108b
    g_checksum_reset (checksum);
Packit 29108b
    g_checksum_update (checksum, key, 64);
Packit 29108b
    g_checksum_update (checksum, hash, digest_len);
Packit 29108b
    g_checksum_get_digest (checksum, hash, &digest_len);
Packit 29108b
    g_checksum_free (checksum);
Packit 29108b
    g_assert (digest_len == CHECKSUM_LEN);
Packit 29108b
Packit 29108b
    g_free (key);
Packit 29108b
Packit 29108b
    if (len != NULL) {
Packit 29108b
	*len = digest_len;
Packit 29108b
    }
Packit 29108b
Packit 29108b
    return hash;
Packit 29108b
}
Packit 29108b
Packit 29108b
gboolean itdb_hash58_write_hash (Itdb_Device *device, 
Packit 29108b
				 unsigned char *itdb_data, 
Packit 29108b
				 gsize itdb_len,
Packit 29108b
				 GError **error)
Packit 29108b
{
Packit 29108b
    unsigned char firewire_id[20];
Packit 29108b
    guchar backup18[8];
Packit 29108b
    guchar backup32[20];
Packit 29108b
    unsigned char *checksum;
Packit 29108b
    gsize len;
Packit 29108b
    MhbdHeader *header;
Packit 29108b
   
Packit 29108b
    g_assert (itdb_device_get_checksum_type (device) == ITDB_CHECKSUM_HASH58);
Packit 29108b
Packit 29108b
    if (!itdb_device_get_hex_uuid(device, firewire_id)) {
Packit 29108b
	g_set_error (error, 0, -1, "Couldn't find the iPod firewire ID");
Packit 29108b
	return FALSE;
Packit 29108b
    }
Packit 29108b
Packit 29108b
    if (itdb_len < 0x6c) {
Packit 29108b
	g_set_error (error, 0, -1, "iTunesDB file too small to write checksum");
Packit 29108b
	return FALSE;
Packit 29108b
    }
Packit 29108b
Packit 29108b
    header = (MhbdHeader *)itdb_data;
Packit 29108b
    g_assert (strncmp (header->header_id, "mhbd", strlen ("mhbd")) == 0);
Packit 29108b
    memcpy (backup18, &header->db_id, sizeof (backup18));
Packit 29108b
    memcpy (backup32, &header->unk_0x32, sizeof (backup32));
Packit 29108b
Packit 29108b
    /* Those fields must be zero'ed out for the sha1 calculation */
Packit 29108b
    memset(&header->db_id, 0, sizeof (header->db_id));
Packit 29108b
    memset(&header->unk_0x32, 0, sizeof (header->unk_0x32));
Packit 29108b
    memset(&header->hash58, 0, sizeof (header->hash58));
Packit 29108b
Packit 29108b
    header->hashing_scheme = GUINT16_FROM_LE (ITDB_CHECKSUM_HASH58);
Packit 29108b
Packit 29108b
    checksum = itdb_compute_hash (firewire_id, itdb_data, itdb_len, &len;;
Packit 29108b
    if (checksum == NULL) {
Packit 29108b
	g_set_error (error, 0, -1, "Failed to compute checksum");
Packit 29108b
	return FALSE;
Packit 29108b
    }
Packit 29108b
    g_assert (len <= sizeof (header->hash58));
Packit 29108b
    memcpy (&header->hash58, checksum, len);
Packit 29108b
    g_free (checksum);
Packit 29108b
Packit 29108b
    memcpy (&header->db_id, backup18, sizeof (backup18));
Packit 29108b
    memcpy (&header->unk_0x32, backup32, sizeof (backup32));
Packit 29108b
Packit 29108b
    return TRUE;
Packit 29108b
}
Packit 29108b