1 /*
2 |  Copyright (C) 2002 Corey Donohoe <atmos at atmos.org>
3 |  Copyright (C) 2002-2007 Jorg Schuler <jcsjcs at users sourceforge net>
4 |  Part of the gtkpod project.
5 |
6 |  URL: http://www.gtkpod.org/
7 |  URL: http://gtkpod.sourceforge.net/
8 |
9 |  SHA1 routine: David Puckett <niekze at yahoo.com>
10 |  SHA1 implemented from FIPS-160 standard
11 |  <http://www.itl.nist.gov/fipspubs/fip180-1.htm>
12 |
13 |  This program is free software; you can redistribute it and/or modify
14 |  it under the terms of the GNU General Public License as published by
15 |  the Free Software Foundation; either version 2 of the License, or
16 |  (at your option) any later version.
17 |
18 |  This program is distributed in the hope that it will be useful,
19 |  but WITHOUT ANY WARRANTY; without even the implied warranty of
20 |  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 |  GNU General Public License for more details.
22 |
23 |  You should have received a copy of the GNU General Public License
24 |  along with this program; if not, write to the Free Software
25 |  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 |
27 |  iTunes and iPod are trademarks of Apple
28 |
29 |  This product is not supported/written/published by Apple!
30 |
31 |  $Id$
32 */
33 
34 #include <errno.h>
35 #include <limits.h>
36 #include <stdio.h>
37 #include <string.h>
38 #include <sys/stat.h>
39 #include <sys/types.h>
40 #include <unistd.h>
41 #include <glib.h>
42 #include "charset.h"
43 #include "sha1.h"
44 #include "file.h"
45 #include "prefs.h"
46 #include "misc.h"
47 #include "misc_track.h"
48 #include "display.h"
49 #include "display_itdb.h"
50 
51 
52 typedef guint32 chunk;
53 union _block
54 {
55    guint8 charblock[64];
56    chunk chunkblock[16];
57 };
58 typedef union _block block;
59 
60 union _hblock
61 {
62    guint8 charblock[20];
63    chunk chunkblock[5];
64 };
65 typedef union _hblock hblock;
66 
67 struct _sha1
68 {
69    block *blockdata;
70    hblock *H;
71 };
72 typedef struct _sha1 sha1;
73 
74 static guint8 *sha1_hash(const guint8 * text, guint32 len);
75 static void process_block_sha1(sha1 * message);
76 
77 #if BYTE_ORDER == LITTLE_ENDIAN
78 static void little_endian(hblock * stupidblock, int blocks);
79 #endif
80 
81 /**
82  * Create and manage a string hash for files on disk
83  */
84 
85 /**
86  * NR_PATH_MAX_BLOCKS
87  * A seed of sorts for SHA1, if collisions occur increasing this value
88  * should give more unique data to SHA1 as more of the file is read
89  * This value is multiplied by PATH_MAX_MD5 to determine how many bytes are read
90  */
91 #define NR_PATH_MAX_BLOCKS 4
92 #define PATH_MAX_SHA1 4096
93 
94 /* Set up or destory the sha1 hash table */
setup_sha1()95 void setup_sha1()
96 {
97     struct itdbs_head *itdbs_head;
98 
99     g_return_if_fail (gtkpod_window);
100     itdbs_head = g_object_get_data (G_OBJECT (gtkpod_window),
101 				    "itdbs_head");
102 
103     /* gets called before itdbs are set up -> fail silently */
104     if (itdbs_head)
105     {
106 	if (prefs_get_int("sha1"))  /* SHA1 hashing turned on */
107 	{
108 	    gp_sha1_hash_tracks();
109 
110 	    /* Display duplicates */
111 	    gp_duplicate_remove(NULL, NULL);
112 	}
113 	else
114 	    gp_sha1_free_hash();
115     }
116 }
117 
118 /**
119  * get_filesize_for_file_descriptor - get the filesize on disk for the given
120  * file descriptor
121  * @fp - the filepointer we want the filesize for
122  * Returns - the filesize in bytes
123  */
124 static guint32
get_filesize_for_file_descriptor(FILE * fp)125 get_filesize_for_file_descriptor(FILE *fp)
126 {
127     off_t result = 0;
128     struct stat stat_info;
129     int file_no = fileno(fp);
130 
131     if((fstat(file_no, &stat_info) == 0))	/* returns 0 on success */
132 	result = (int)stat_info.st_size;
133     return (guint32)result;
134 }
135 
136 /**
137  * sha1_hash_on_file - read PATH_MAX_SHA1 * NR_PATH_MAX_BLOCKS bytes
138  * from the file and ask sha1 for a hash of it, convert this hash to a
139  * string of hex output @fp - an open file descriptor to read from
140  * Returns - A Hash String - you handle memory returned
141  */
142 static gchar *
sha1_hash_on_file(FILE * fp)143 sha1_hash_on_file(FILE * fp)
144 {
145    gchar *result = NULL;
146 
147    if (fp)
148    {
149        int fsize = 0;
150        int chunk_size = PATH_MAX_SHA1 * NR_PATH_MAX_BLOCKS;
151 
152        fsize = get_filesize_for_file_descriptor(fp);
153        if(fsize < chunk_size)
154 	   chunk_size = fsize;
155 
156        if(fsize > 0)
157        {
158 	   guint32 fsize_normal;
159 	   guint8 *hash = NULL;
160 	   int bread = 0, x = 0, last = 0;
161 	   guchar file_chunk[chunk_size + sizeof(int)];
162 
163 	   /* allocate the digest we're returning */
164 	   result = g_malloc0(sizeof(gchar) * 41);
165 
166 	   /* put filesize in the first 32 bits */
167 	   fsize_normal = GINT32_TO_LE (fsize);
168 	   memcpy(file_chunk, &fsize_normal, sizeof(guint32));
169 
170 	   /* read chunk_size from fp */
171 	   bread = fread(&file_chunk[sizeof(int)], sizeof(gchar),
172 			    chunk_size, fp);
173 
174 	   /* create hash from our data */
175 	   hash = sha1_hash(file_chunk, (bread + sizeof(int)));
176 
177 	   /* put it in a format we like */
178 	   for (x = 0; x < 20; x++)
179 	       last += snprintf(&result[last], 4, "%02x", hash[x]);
180 
181 	   /* free the hash value sha1_hash gave us */
182 	   g_free(hash);
183        }
184        else
185        {
186 	  gtkpod_warning(_("Hashed file is 0 bytes long\n"));
187        }
188    }
189    return (result);
190 }
191 
192 /**
193  * Generate a unique hash for the Track passed in
194  * @s - The Track data structure, we want to hash based on the file on disk
195  * Returns - an SHA1 hash in string format, is the hex output from the hash
196  */
197 static gchar *
sha1_hash_track(Track * s)198 sha1_hash_track(Track * s)
199 {
200    ExtraTrackData *etr;
201    gchar *result = NULL;
202    gchar *filename;
203 
204    g_return_val_if_fail (s, NULL);
205    etr = s->userdata;
206    g_return_val_if_fail (etr, NULL);
207 
208    if (etr->sha1_hash != NULL)
209    {
210        result = g_strdup(etr->sha1_hash);
211    }
212    else
213    {
214        filename = get_file_name_from_source (s, SOURCE_PREFER_LOCAL);
215        if (filename)
216        {
217 	   result = sha1_hash_on_filename (filename, FALSE);
218 	   g_free(filename);
219        }
220    }
221    return (result);
222 }
223 
224 
225 /* @silent: don't print any warning */
sha1_hash_on_filename(gchar * name,gboolean silent)226 gchar *sha1_hash_on_filename (gchar *name, gboolean silent)
227 {
228     gchar *result = NULL;
229 
230     if (name)
231     {
232 	FILE *fpit = fopen (name, "r");
233 	if (!fpit)
234 	{
235 	    if (!silent)
236 	    {
237 		gchar *name_utf8=charset_to_utf8 (name);
238 		gtkpod_warning (
239 		    _("Could not open '%s' to calculate SHA1 checksum: %s\n"),
240 		    name_utf8, strerror(errno));
241 		g_free (name_utf8);
242 	    }
243 	}
244 	else
245 	{
246 	    result = sha1_hash_on_file (fpit);
247 	    fclose (fpit);
248 	}
249     }
250     return result;
251 }
252 
253 
254 /**
255  * Free up the dynamically allocated memory in @itdb's hash table
256  */
sha1_free_eitdb(ExtraiTunesDBData * eitdb)257 void sha1_free_eitdb (ExtraiTunesDBData *eitdb)
258 {
259     g_return_if_fail (eitdb);
260 
261     if (eitdb->sha1hash)
262     {
263 	g_hash_table_destroy (eitdb->sha1hash);
264 	eitdb->sha1hash = NULL;
265     }
266 }
267 
268 /**
269  * Free up the dynamically allocated memory in @itdb's hash table
270  */
sha1_free(iTunesDB * itdb)271 void sha1_free (iTunesDB *itdb)
272 {
273     g_return_if_fail (itdb);
274     g_return_if_fail (itdb->userdata);
275 
276     sha1_free_eitdb (itdb->userdata);
277 }
278 
279 /**
280  * Check to see if a track has already been added to the ipod
281  * @s - the Track we want to know about. If the track does not exist, it
282  * is inserted into the hash.
283  * Returns a pointer to the duplicate track.
284  */
sha1_track_exists_insert(iTunesDB * itdb,Track * s)285 Track *sha1_track_exists_insert (iTunesDB *itdb, Track * s)
286 {
287     ExtraiTunesDBData *eitdb;
288     ExtraTrackData *etr;
289     gchar *val = NULL;
290     Track *track = NULL;
291 
292     g_return_val_if_fail (itdb, NULL);
293     eitdb = itdb->userdata;
294     g_return_val_if_fail (eitdb, NULL);
295 
296     g_return_val_if_fail (s, NULL);
297     etr = s->userdata;
298     g_return_val_if_fail (etr, NULL);
299 
300     if (prefs_get_int("sha1"))
301     {
302 	if (eitdb->sha1hash == NULL)
303 	{
304 	    eitdb->sha1hash = g_hash_table_new_full(g_str_hash,
305 						   g_str_equal,
306 						   g_free, NULL);
307 	}
308 	val = sha1_hash_track (s);
309 	if (val != NULL)
310 	{
311 	    track = g_hash_table_lookup (eitdb->sha1hash, val);
312 	    if (track)
313 	    {
314 		g_free(val);
315 	    }
316 	    else
317 	    {   /* if it doesn't exist we register it in the hash */
318 		g_free (etr->sha1_hash);
319 		etr->sha1_hash = g_strdup (val);
320 		/* val is used in the next line -- we don't have to
321 		 * g_free() it */
322 		g_hash_table_insert (eitdb->sha1hash, val, s);
323 	    }
324 	}
325     }
326     return track;
327 }
328 
329 /**
330  * Check to see if a track has already been added to the ipod
331  * @s - the Track we want to know about.
332  * Returns a pointer to the duplicate track.
333  */
sha1_track_exists(iTunesDB * itdb,Track * s)334 Track *sha1_track_exists (iTunesDB *itdb, Track *s)
335 {
336     ExtraiTunesDBData *eitdb;
337     Track *track = NULL;
338 
339     g_return_val_if_fail (itdb, NULL);
340     eitdb = itdb->userdata;
341     g_return_val_if_fail (eitdb, NULL);
342 
343     if (prefs_get_int("sha1") && eitdb->sha1hash)
344     {
345 	gchar *val = sha1_hash_track (s);
346 	if (val)
347 	{
348 	    track = g_hash_table_lookup (eitdb->sha1hash, val);
349 	    g_free (val);
350 	}
351     }
352     return track;
353 }
354 
355 /**
356  * Check to see if a track has already been added to the ipod
357  * @file - the Track we want to know about.
358  * Returns a pointer to the duplicate track using sha1 for
359  * identification. If sha1 checksums are off, NULL is returned.
360  */
sha1_file_exists(iTunesDB * itdb,gchar * file,gboolean silent)361 Track *sha1_file_exists (iTunesDB *itdb, gchar *file, gboolean silent)
362 {
363     ExtraiTunesDBData *eitdb;
364     Track *track = NULL;
365 
366     g_return_val_if_fail (file, NULL);
367     g_return_val_if_fail (itdb, NULL);
368     eitdb = itdb->userdata;
369     g_return_val_if_fail (eitdb, NULL);
370 
371     if (prefs_get_int("sha1") && eitdb->sha1hash)
372     {
373 	gchar *val = sha1_hash_on_filename (file, silent);
374 	if (val)
375 	{
376 	    track = g_hash_table_lookup (eitdb->sha1hash, val);
377 	    g_free (val);
378 	}
379     }
380     return track;
381 }
382 
383 
384 /**
385  * Check to see if a track has already been added to the ipod
386  * @sha1 - the sha1 we want to know about.
387  * Returns a pointer to the duplicate track using sha1 for
388  * identification. If sha1 checksums are off, NULL is returned.
389  */
sha1_sha1_exists(iTunesDB * itdb,gchar * sha1)390 Track *sha1_sha1_exists (iTunesDB *itdb, gchar *sha1)
391 {
392     ExtraiTunesDBData *eitdb;
393     Track *track = NULL;
394 
395     g_return_val_if_fail (sha1, NULL);
396     g_return_val_if_fail (itdb, NULL);
397     eitdb = itdb->userdata;
398     g_return_val_if_fail (eitdb, NULL);
399 
400     if (prefs_get_int("sha1") && eitdb->sha1hash)
401     {
402 	track = g_hash_table_lookup (eitdb->sha1hash, sha1);
403     }
404     return track;
405 }
406 
407 /**
408  * Free the specified track from the ipod's unique file hash
409  * @s - The Track that's being freed from the ipod
410  */
sha1_track_remove(Track * s)411 void sha1_track_remove (Track *s)
412 {
413     ExtraiTunesDBData *eitdb;
414 
415     g_return_if_fail (s);
416     g_return_if_fail (s->itdb);
417     eitdb = s->itdb->userdata;
418     g_return_if_fail (eitdb);
419 
420     if (prefs_get_int("sha1") && eitdb->sha1hash)
421     {
422 	gchar *val = sha1_hash_track (s);
423 	if (val)
424 	{
425 	    Track *track = g_hash_table_lookup (eitdb->sha1hash, val);
426 	    if (track)
427 	    {
428 		if (track == s) /* only remove if it's the same track */
429 		    g_hash_table_remove (eitdb->sha1hash, val);
430 	    }
431 	    g_free(val);
432 	}
433     }
434 }
435 
436 /* sha1_hash - hash value the input data with a given size.
437  * @text - the data we're reading to seed sha1
438  * @len - the length of the data for our seed
439  * Returns a unique 20 char array.
440  */
441 static guint8 *
sha1_hash(const guint8 * text,guint32 len)442 sha1_hash(const guint8 * text, guint32 len)
443 {
444    chunk x;
445    chunk temp_len = len;
446    const guint8 *temp_text = text;
447    guint8 *digest;
448    sha1 *message;
449 
450    digest = g_malloc0(sizeof(guint8) * 21);
451    message = g_malloc0(sizeof(sha1));
452    message->blockdata = g_malloc0(sizeof(block));
453    message->H = g_malloc(sizeof(hblock));
454 
455    message->H->chunkblock[0] = 0x67452301;
456    message->H->chunkblock[1] = 0xefcdab89;
457    message->H->chunkblock[2] = 0x98badcfe;
458    message->H->chunkblock[3] = 0x10325476;
459    message->H->chunkblock[4] = 0xc3d2e1f0;
460    while (temp_len >= 64)
461    {
462       for (x = 0; x < 64; x++)
463          message->blockdata->charblock[x] = temp_text[x];
464 #if BYTE_ORDER == LITTLE_ENDIAN
465       little_endian((hblock *) message->blockdata, 16);
466 #endif
467       process_block_sha1(message);
468       temp_len -= 64;
469       temp_text += 64;
470    }
471    for (x = 0; x < temp_len; x++)
472       message->blockdata->charblock[x] = temp_text[x];
473    message->blockdata->charblock[temp_len] = 0x80;
474    for (x = temp_len + 1; x < 64; x++)
475       message->blockdata->charblock[x] = 0x00;
476 #if BYTE_ORDER == LITTLE_ENDIAN
477    little_endian((hblock *) message->blockdata, 16);
478 #endif
479    if (temp_len > 54)
480    {
481       process_block_sha1(message);
482       for (x = 0; x < 60; x++)
483          message->blockdata->charblock[x] = 0x00;
484    }
485    message->blockdata->chunkblock[15] = len * 8;
486    process_block_sha1(message);
487 #if BYTE_ORDER == LITTLE_ENDIAN
488    little_endian(message->H, 5);
489 #endif
490    for (x = 0; x < 20; x++)
491       digest[x] = message->H->charblock[x];
492    digest[20] = 0x00;
493    g_free(message->blockdata);
494    g_free(message->H);
495    g_free(message);
496    return (digest);
497 }
498 
499 /*
500  * process_block_sha1 - process one 512-bit block of data
501  * @message - the sha1 struct we're doing working on
502  */
503 static void
process_block_sha1(sha1 * message)504 process_block_sha1(sha1 * message)
505 {
506    chunk x;
507    chunk w[80];                 /* test block */
508    chunk A;                     /* A - E: used for hash calc */
509    chunk B;
510    chunk C;
511    chunk D;
512    chunk E;
513    chunk T;                     /* temp guint32 */
514    chunk K[] = { 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 };
515 
516    for (x = 0; x < 16; x++)
517       w[x] = message->blockdata->chunkblock[x];
518    for (x = 16; x < 80; x++)
519    {
520       w[x] = w[x - 3] ^ w[x - 8] ^ w[x - 14] ^ w[x - 16];
521       w[x] = (w[x] << 1) | (w[x] >> 31);
522    }
523    A = message->H->chunkblock[0];
524    B = message->H->chunkblock[1];
525    C = message->H->chunkblock[2];
526    D = message->H->chunkblock[3];
527    E = message->H->chunkblock[4];
528    for (x = 0; x < 80; x++)
529    {
530       T = ((A << 5) | (A >> 27)) + E + w[x] + K[x / 20];
531       if (x < 20)
532          T += (B & C) | ((~B) & D);
533       else if (x < 40 || x >= 60)
534          T += B ^ C ^ D;
535       else
536          T += ((C | D) & B) | (C & D);
537       E = D;
538       D = C;
539       C = (B << 30) | (B >> 2);
540       B = A;
541       A = T;
542    }
543    message->H->chunkblock[0] += A;
544    message->H->chunkblock[1] += B;
545    message->H->chunkblock[2] += C;
546    message->H->chunkblock[3] += D;
547    message->H->chunkblock[4] += E;
548 }
549 
550 #if BYTE_ORDER == LITTLE_ENDIAN
551 /*
552  * little_endian - swap the significants bits to cater to bigendian
553  * @stupidblock - the block of data we're swapping
554  * @blocks - the number of blocks we're swapping
555  */
556 static void
little_endian(hblock * stupidblock,int blocks)557 little_endian(hblock * stupidblock, int blocks)
558 {
559    int x;
560    for (x = 0; x < blocks; x++)
561    {
562   	stupidblock->chunkblock[x] = (stupidblock->charblock[x * 4] << 24 | stupidblock->charblock[x * 4 + 1] << 16 | stupidblock->charblock[x * 4 +2] << 8 | stupidblock->charblock[x * 4 + 3]);
563    }
564 }
565 #endif
566 
567 
568