From c27b852d54baf70756dee6878c26e185810dcd05 Mon Sep 17 00:00:00 2001 From: 93sam <93sam@a95a6be8-091b-0410-adaf-d31e6857962f> Date: Sun, 6 Jan 2008 03:01:25 +0000 Subject: [PATCH] * genisoimage/jte.c: add support for bzip2-compressed templates * genisoimage/jte.c: fix bzip2-compressed template data to be compatible with jigdo. * genisoimage/jte.c: fix exclude list handling. * genisoimage/checksum.[ch]: Add a generic infrastructure for checksums so we can use sha1/ as well as just md5sum. Will make things much faster for generating sha1sums for images and jigdos. * genisoimage/sha1.[ch]: Add GPL-licensed SHA1 implementation. * s/mkisofs/genisoimage/ in ABOUT git-svn-id: svn://svn.debian.org/debburn/cdrkit/trunk@785 a95a6be8-091b-0410-adaf-d31e6857962f --- ABOUT | 4 +- Changelog | 11 +- debian/control | 2 +- genisoimage/CMakeLists.txt | 5 +- genisoimage/checksum.c | 164 +++++++++++++++ genisoimage/checksum.h | 56 +++++ genisoimage/jte.c | 122 +++++++---- genisoimage/jte.h | 9 + genisoimage/sha1.c | 415 +++++++++++++++++++++++++++++++++++++ genisoimage/sha1.h | 88 ++++++++ 10 files changed, 827 insertions(+), 49 deletions(-) create mode 100644 genisoimage/checksum.c create mode 100644 genisoimage/checksum.h create mode 100644 genisoimage/sha1.c create mode 100644 genisoimage/sha1.h diff --git a/ABOUT b/ABOUT index 3a6ec6b..dd5fa39 100644 --- a/ABOUT +++ b/ABOUT @@ -27,13 +27,13 @@ This package contains the following software: cdrecord by Jörg Schilling but developed independently now. -- mkisofs (an ISO-9660 filesystem image creator) +- genisoimage (an ISO-9660 filesystem image creator) By Eric Youngdale , Jörg Schilling , James Pearson and other contributors. - mkhybrid (an ISO-9660/HFS filesystem image creator) - Link to mkisofs + Link to genisoimage - several diagnostic programs for ISO-9660, originaly from cdrtools (by Jörg Schilling), diff --git a/Changelog b/Changelog index 33d6b0d..2a35f62 100644 --- a/Changelog +++ b/Changelog @@ -4,11 +4,18 @@ cdrkit (1.1.7) UNRELEASED; urgency=low * wodim.1: small fixes. [ Steve McIntyre ] + * genisoimage/jte.c: add support for bzip2-compressed templates * genisoimage/jte.c: fix bzip2-compressed template data to be compatible with jigdo. * genisoimage/jte.c: fix exclude list handling. - - -- Steve McIntyre <93sam@debian.org> Wed, 19 Sep 2007 22:03:04 +0100 + * genisoimage/checksum.[ch]: Add a generic infrastructure for + checksums so we can use sha1/ as well as just + md5sum. Will make things much faster for generating sha1sums for + images and jigdos. + * genisoimage/sha1.[ch]: Add GPL-licensed SHA1 implementation. + * s/mkisofs/genisoimage/ in ABOUT + + -- Steve McIntyre <93sam@debian.org> Sun, 06 Jan 2008 02:32:42 +0000 cdrkit (1.1.6) RELEASED; urgency=low diff --git a/debian/control b/debian/control index fa3adc8..172f288 100644 --- a/debian/control +++ b/debian/control @@ -3,7 +3,7 @@ Priority: optional Section: otherosfs Maintainer: Joerg Jaspert Uploaders: Eduard Bloch , Steve McIntyre <93sam@debian.org> -Build-Depends: debhelper (>=5.0.37.3), zlib1g-dev, autotools-dev, cmake (>= 2.4.2-1), libcap-dev [!kfreebsd-i386 !kfreebsd-amd64 !hurd-i386], libcam-dev [kfreebsd-i386 kfreebsd-amd64], libmagic-dev +Build-Depends: debhelper (>=5.0.37.3), libbz2-dev, zlib1g-dev, autotools-dev, cmake (>= 2.4.2-1), libcap-dev [!kfreebsd-i386 !kfreebsd-amd64 !hurd-i386], libcam-dev [kfreebsd-i386 kfreebsd-amd64], libmagic-dev Standards-Version: 3.7.2 Package: wodim diff --git a/genisoimage/CMakeLists.txt b/genisoimage/CMakeLists.txt index 8412b60..403c99e 100644 --- a/genisoimage/CMakeLists.txt +++ b/genisoimage/CMakeLists.txt @@ -25,8 +25,7 @@ ENDIF(HAVE_ICONV_H) ADD_DEFINITIONS(-DUSE_LARGEFILES -DABORT_DEEP_ISO_ONLY -DAPPLE_HYB -DUDF -DDVD_VIDEO -DSORTING -DHAVE_CONFIG_H -DUSE_LIBSCHILY -DUSE_SCG -DJIGDO_TEMPLATE) -SET(MKISOFS_MOST_SRCS apple.c boot.c desktop.c dvd_file.c dvd_reader.c eltorito.c exclude.c files.c fnmatch.c hash.c ifo_read.c joliet.c mac_label.c match.c multi.c name.c rock.c scsi.c stream.c tree.c udf.c vms.c volume.c write.c boot-alpha.c boot-hppa.c boot-mips.c md5.c jte.c rsync.c - boot-mipsel.c endian.c ) +SET(MKISOFS_MOST_SRCS apple.c boot.c desktop.c dvd_file.c dvd_reader.c eltorito.c exclude.c files.c fnmatch.c hash.c ifo_read.c joliet.c mac_label.c match.c multi.c name.c rock.c scsi.c stream.c tree.c udf.c vms.c volume.c write.c boot-alpha.c boot-hppa.c boot-mips.c md5.c jte.c rsync.c boot-mipsel.c endian.c sha1.c checksum.c ) INCLUDE(CheckFunctionExists) SET(CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE) @@ -40,7 +39,7 @@ ENDIF(NOT HAVE_GETOPT_LONG) LINK_DIRECTORIES(../libhfs_iso ../librols ../libusal ../libunls ../wodim) ADD_EXECUTABLE (genisoimage genisoimage.c ${MKISOFS_MOST_SRCS}) -TARGET_LINK_LIBRARIES(genisoimage wodimstuff hfs_iso ${MAGICLIBS} c unls z ${EXTRA_LIBICONV} ${EXTRA_LIBS}) +TARGET_LINK_LIBRARIES(genisoimage wodimstuff hfs_iso ${MAGICLIBS} c unls z bz2 ${EXTRA_LIBICONV} ${EXTRA_LIBS}) # common lib set and genisoimage source parts for the rest LINK_LIBRARIES(wodimstuff ${EXTRA_LIBS} unls ${EXTRA_LIBICONV} ) diff --git a/genisoimage/checksum.c b/genisoimage/checksum.c new file mode 100644 index 0000000..39f319e --- /dev/null +++ b/genisoimage/checksum.c @@ -0,0 +1,164 @@ +/* + * checksum.c + * + * Copyright (c) 2008- Steve McIntyre + * + * Implementation of a generic checksum interface, used in JTE. + * + * GNU GPL v2 + */ + +#include +#include "genisoimage.h" +#include +#include +#include +#include +#include "md5.h" +#include "sha1.h" +#include "checksum.h" + +static void md5_init(void *context) +{ + mk_MD5Init(context); +} +static void md5_update(void *context, unsigned char const *buf, unsigned int len) +{ + mk_MD5Update(context, buf, len); +} +static void md5_final(unsigned char *digest, void *context) +{ + mk_MD5Final(digest, context); +} + +static void sha1_init(void *context) +{ + sha1_init_ctx(context); +} +static void sha1_update(void *context, unsigned char const *buf, unsigned int len) +{ + sha1_process_bytes(buf, len, context); +} +static void sha1_final(unsigned char *digest, void *context) +{ + sha1_finish_ctx(context, digest); +} + +struct checksum_details +{ + char *name; + int digest_size; + int context_size; + void (*init)(void *context); + void (*update)(void *context, unsigned char const *buf, unsigned int len); + void (*final)(unsigned char *digest, void *context); +}; + +static const struct checksum_details algorithms[] = +{ + { + "MD5", + 16, + sizeof(struct mk_MD5Context), + md5_init, + md5_update, + md5_final + }, + { + "SHA1", + 20, + sizeof(struct sha1_ctx), + sha1_init, + sha1_update, + sha1_final + } +}; + +struct _checksum_context +{ + void *context; + unsigned char *digest; + int enabled; +}; + +struct checksum_info *checksum_information(enum checksum_types which) +{ + return (struct checksum_info *)&algorithms[which]; +} + +checksum_context_t *checksum_init_context(int checksums) +{ + int i = 0; + struct _checksum_context *context = malloc(NUM_CHECKSUMS * sizeof(struct _checksum_context)); + if (!context) + return NULL; + + for (i = 0; i < NUM_CHECKSUMS; i++) + { + if ( (1 << i) & checksums) + { + context[i].context = malloc(algorithms[i].context_size); + if (!context[i].context) + return NULL; + context[i].digest = malloc(algorithms[i].digest_size); + if (!context[i].digest) + return NULL; + algorithms[i].init(context[i].context); + context[i].enabled = 1; + } + else + context[i].enabled = 0; + } + + return context; +} + +void checksum_free_context(checksum_context_t *context) +{ + int i = 0; + struct _checksum_context *c = context; + + for (i = 0; i < NUM_CHECKSUMS; i++) + { + free(c[i].context); + free(c[i].digest); + } + free(c); +} + +void checksum_update(checksum_context_t *context, + unsigned char const *buf, unsigned int len) +{ + int i = 0; + struct _checksum_context *c = context; + + for (i = 0; i < NUM_CHECKSUMS; i++) + { + if (c[i].enabled) + algorithms[i].update(c[i].context, buf, len); + } +} + +void checksum_final(checksum_context_t *context) +{ + int i = 0; + struct _checksum_context *c = context; + + for (i = 0; i < NUM_CHECKSUMS; i++) + { + if (c[i].enabled) + algorithms[i].final(c[i].digest, c[i].context); + } +} + +void checksum_copy(checksum_context_t *context, + enum checksum_types which, + unsigned char *digest) +{ + struct _checksum_context *c = context; + + if (c[which].enabled) + memcpy(digest, c[which].digest, algorithms[which].digest_size); +} + + diff --git a/genisoimage/checksum.h b/genisoimage/checksum.h new file mode 100644 index 0000000..c1381ff --- /dev/null +++ b/genisoimage/checksum.h @@ -0,0 +1,56 @@ +/* + * checksum.h + * + * Copyright (c) 2008- Steve McIntyre + * + * Definitions and prototypes for a generic checksum interface, used + * in JTE. Inspired heavily by the interface to the MD5 code we're + * using already. + * + * GNU GPL v2 + */ + +enum checksum_types +{ + CHECK_MD5 = 0, + CHECK_SHA1, + NUM_CHECKSUMS +}; + +#define CHECK_MD5_USED (1 << CHECK_MD5) +#define CHECK_SHA1_USED (1 << CHECK_SHA1) + +typedef void checksum_context_t; + +struct checksum_info +{ + char *name; + int digest_size; +}; + +/* Ask the library for information about a particular checksum + * algorithm. Returns a pointer to internal memory - DO NOT + * MODIFY/FREE! */ +struct checksum_info *checksum_information(enum checksum_types which); + +/* Allocate / initialise a context for the chosen checksums. OR + * together the desired checksums as the parameter */ +checksum_context_t *checksum_init_context(int checksums); + +/* Cleanup and free a context when it's finished with */ +void checksum_free_context(checksum_context_t *context); + +/* Pass a new buffer full of data through the checksum code */ +void checksum_update(checksum_context_t *context, + unsigned char const *buf, + unsigned int len); + +/* Finish the current set of checksums */ +void checksum_final(checksum_context_t *context); + +/* Extract a particular algorithm's checksum once checksum_final() has + * been called. Use the details in checksum_information() above first + * to see how big the digest will be. */ +void checksum_copy(checksum_context_t *context, + enum checksum_types which, + unsigned char *digest); diff --git a/genisoimage/jte.c b/genisoimage/jte.c index 2e8c55e..49dd2e8 100644 --- a/genisoimage/jte.c +++ b/genisoimage/jte.c @@ -9,16 +9,12 @@ * GNU GPL v2 */ -#undef BZ2_SUPPORT - #include #include "genisoimage.h" #include #include #include -#ifdef BZ2_SUPPORT -# include -#endif +#include #include #ifdef SORTING #include "match.h" @@ -29,8 +25,8 @@ #include "dvd_reader.h" #include "dvd_file.h" #include "ifo_read.h" -#include "md5.h" #include "endianconv.h" +#include "checksum.h" #endif #ifdef APPLE_HYB #include @@ -45,16 +41,12 @@ #define JTET_NOMATCH 2 #define JTE_VER_MAJOR 0x0001 -#define JTE_VER_MINOR 0x000F +#define JTE_VER_MINOR 0x0012 #define JTE_NAME "JTE" #define JTE_COMMENT "JTE at http://www.einval.com/~steve/software/JTE/ ; jigdo at http://atterer.net/jigdo/" #define JIGDO_TEMPLATE_VERSION "1.1" -#ifdef BZ2_SUPPORT -int use_bz2 = 0; -#endif - /* Simple list to hold the results of -jigdo-exclude and -jigdo-force-match command line options. Seems easiest to do this @@ -81,14 +73,18 @@ char *jjigdo_out = NULL; /* Output name for jigdo .jigdo file; NULL means char *jtemplate_out = NULL; /* Output name for jigdo template file; NULL means don't do it */ char *jmd5_list = NULL; /* Name of file to use for MD5 checking */ int jte_min_size = MIN_JIGDO_FILE_SIZE; +jtc_t jte_template_compression = JTE_TEMP_GZIP; struct path_match *exclude_list = NULL; struct path_match *include_list = NULL; struct path_mapping *map_list = NULL; unsigned long long template_size = 0; unsigned long long image_size = 0; -static struct mk_MD5Context iso_context; -static struct mk_MD5Context template_context; +static checksum_context_t *iso_context = NULL; +static checksum_context_t *template_context = NULL; + +unsigned char image_md5[16]; /* MD5SUM of the entire image */ +unsigned char image_sha1[20]; /* SHA1SUM of the entire image */ /* List of files that we've seen, ready to write into the template and jigdo files */ @@ -305,7 +301,7 @@ extern int list_file_in_jigdo(char *filename, off_t size, char **realname, unsig /* Cheaper to check file size first */ if (size < jte_min_size) { - if (verbose > 0) + if (verbose > 1) fprintf(stderr, "Jigdo-ignoring file %s; it's too small\n", filename); return 0; } @@ -313,7 +309,7 @@ extern int list_file_in_jigdo(char *filename, off_t size, char **realname, unsig /* Now check the excluded list by name */ if (check_exclude_by_name(filename, &matched_rule)) { - if (verbose > 0) + if (verbose > 1) fprintf(stderr, "Jigdo-ignoring file %s; it's covered in the exclude list by \"%s\"\n", filename, matched_rule); return 0; } @@ -435,7 +431,7 @@ static char *remap_filename(char *filename) /* Write data to the template file and update the MD5 sum */ static size_t template_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) { - mk_MD5Update(&template_context, ptr, size * nmemb); + checksum_update(template_context, ptr, size * nmemb); template_size += (unsigned long long)size * nmemb; return fwrite(ptr, size, nmemb, stream); } @@ -449,7 +445,17 @@ static void write_template_header() memset(buf, 0, sizeof(buf)); - mk_MD5Init(&template_context); + template_context = checksum_init_context(CHECK_MD5_USED); + if (!template_context) + { +#ifdef USE_LIBSCHILY + comerr("cannot allocate template checksum contexts\n"); +#else + fprintf(stderr, "cannot allocate template checksum contexts\n"); + exit(1); +#endif + } + i += sprintf(p, "JigsawDownload template %s %s/%d.%d \r\n", JIGDO_TEMPLATE_VERSION, JTE_NAME, JTE_VER_MAJOR, JTE_VER_MINOR); p = &buf[i]; @@ -562,8 +568,17 @@ void write_jt_header(FILE *template_file, FILE *jigdo_file) t_file = template_file; j_file = jigdo_file; - /* Start MD5 work for the image */ - mk_MD5Init(&iso_context); + /* Start checksum work for the image */ + iso_context = checksum_init_context(CHECK_MD5_USED|CHECK_SHA1_USED); + if (!iso_context) + { +#ifdef USE_LIBSCHILY + comerr("cannot allocate iso checksum contexts\n"); +#else + fprintf(stderr, "cannot allocate iso checksum contexts\n"); + exit(1); +#endif + } /* Start the template file */ write_template_header(); @@ -612,7 +627,6 @@ static void flush_gzip_chunk(void *buffer, off_t size) free(comp_buf); } -#ifdef BZ2_SUPPORT /* Compress and flush out a buffer full of template data */ static void flush_bz2_chunk(void *buffer, off_t size) { @@ -650,15 +664,12 @@ static void flush_bz2_chunk(void *buffer, off_t size) template_fwrite(comp_buf, c_stream.total_out_lo32, 1, t_file); free(comp_buf); } -#endif static void flush_compressed_chunk(void *buffer, off_t size) { -#ifdef BZ2_SUPPORT - if (use_bz2) + if (jte_template_compression == JTE_TEMP_BZIP2) flush_bz2_chunk(buffer, size); else -#endif flush_gzip_chunk(buffer, size); } @@ -666,10 +677,29 @@ static void flush_compressed_chunk(void *buffer, off_t size) necessary */ static void write_compressed_chunk(unsigned char *buffer, size_t size) { - static unsigned char uncomp_buf[1024 * 1024]; + static unsigned char *uncomp_buf = NULL; + static size_t uncomp_size = 0; static size_t uncomp_buf_used = 0; - if ((uncomp_buf_used + size) > sizeof(uncomp_buf)) + if (!uncomp_buf) + { + if (jte_template_compression == JTE_TEMP_BZIP2) + uncomp_size = 900 * 1024; + else + uncomp_size = 1024 * 1024; + uncomp_buf = malloc(uncomp_size); + if (!uncomp_buf) + { +#ifdef USE_LIBSCHILY + comerr("failed to allocate %d bytes for template compression buffer\n", uncomp_size); +#else + fprintf(stderr, "failed to allocate %d bytes for template compression buffer\n", uncomp_size); + exit(1); +#endif + } + } + + if ((uncomp_buf_used + size) > uncomp_size) { flush_compressed_chunk(uncomp_buf, uncomp_buf_used); uncomp_buf_used = 0; @@ -682,13 +712,13 @@ static void write_compressed_chunk(unsigned char *buffer, size_t size) } if (!uncomp_buf_used) - memset(uncomp_buf, 0, sizeof(uncomp_buf)); + memset(uncomp_buf, 0, uncomp_size); - while (size > sizeof(uncomp_buf)) + while (size > uncomp_size) { - flush_compressed_chunk(buffer, sizeof(uncomp_buf)); - buffer += sizeof(uncomp_buf); - size -= sizeof(uncomp_buf); + flush_compressed_chunk(buffer, uncomp_size); + buffer += uncomp_size; + size -= uncomp_size; } memcpy(&uncomp_buf[uncomp_buf_used], buffer, size); uncomp_buf_used += size; @@ -730,7 +760,7 @@ static void write_template_desc_entries(off_t image_len, char *image_md5) case JTET_NOMATCH: { jigdo_chunk_entry_t jchunk; - jchunk.type = 2; /* Raw data, gzipped */ + jchunk.type = 2; /* Raw data, compressed */ write_le48(entry->data.chunk.uncompressed_length, &jchunk.skipLen[0]); template_fwrite(&jchunk, sizeof(jchunk), 1, t_file); break; @@ -789,7 +819,9 @@ static void write_jigdo_file(void) entry_t *entry = entry_list; struct path_mapping *map = map_list; - mk_MD5Final(&template_md5sum[0], &template_context); + checksum_final(template_context); + checksum_copy(template_context, CHECK_MD5, &template_md5sum[0]); +// mk_MD5Final(&template_md5sum[0], &template_context); fprintf(j_file, "# JigsawDownload\n"); fprintf(j_file, "# See for details about jigdo\n"); @@ -807,6 +839,10 @@ static void write_jigdo_file(void) fprintf(j_file, "# Template Hex MD5sum %s\n", hex_dump(&template_md5sum[0], sizeof(template_md5sum))); fprintf(j_file, "# Template size %lld bytes\n", template_size); + fprintf(j_file, "# Image Hex MD5Sum %s\n", + hex_dump(&image_md5[0], sizeof(image_md5))); + fprintf(j_file, "# Image Hex SHA1Sum %s\n", + hex_dump(&image_sha1[0], sizeof(image_sha1))); fprintf(j_file, "# Image size %lld bytes\n\n", image_size); fprintf(j_file, "[Parts]\n"); @@ -834,15 +870,16 @@ static void write_jigdo_file(void) */ void write_jt_footer(void) { - unsigned char md5[16]; /* MD5SUM of the entire image */ - /* Finish calculating the image's checksum */ - mk_MD5Final(&md5[0], &iso_context); + checksum_final(iso_context); + checksum_copy(iso_context, CHECK_MD5, &image_md5[0]); + checksum_copy(iso_context, CHECK_SHA1, &image_sha1[0]); +// mk_MD5Final(&md5[0], &iso_context); /* And calculate the image size */ image_size = (unsigned long long)SECTOR_SIZE * last_extent_written; - write_template_desc_entries(image_size, md5); + write_template_desc_entries(image_size, image_md5); write_jigdo_file(); } @@ -919,14 +956,15 @@ void jtwrite(buffer, size, count, submode, islast) { #ifdef JTWRITE_DEBUG if (count != 1 || (size % 2048) != 0) - fprintf(stderr, "Count: %d, size: %d\n", count, size); + error("Count: %d, size: %d\n", count, size); #endif if (!jtemplate_out) return; /* Update the global image checksum */ - mk_MD5Update(&iso_context, buffer, size*count); + checksum_update(iso_context, buffer, size * count); +// mk_MD5Update(&iso_context, buffer, size*count); /* Write a compressed version of the data to the template file, and add a reference on the state list so we can write that @@ -983,7 +1021,8 @@ void write_jt_match_record(char *filename, char *mirror_name, int sector_size, o } if (first_block) rsync64_sum = rsync64(buf, MIN_JIGDO_FILE_SIZE); - mk_MD5Update(&iso_context, buf, use); + checksum_update(iso_context, buf, use); +// mk_MD5Update(&iso_context, buf, use); remain -= use; first_block = 0; } @@ -995,7 +1034,8 @@ void write_jt_match_record(char *filename, char *mirror_name, int sector_size, o { int pad_size = sector_size - (size % sector_size); memset(buf, 0, pad_size); - mk_MD5Update(&iso_context, buf, pad_size); + checksum_update(iso_context, buf, pad_size); +// mk_MD5Update(&iso_context, buf, pad_size); } add_file_entry(mirror_name, size, &md5[0], rsync64_sum); diff --git a/genisoimage/jte.h b/genisoimage/jte.h index 2a73133..18125b0 100644 --- a/genisoimage/jte.h +++ b/genisoimage/jte.h @@ -25,4 +25,13 @@ extern int jte_add_exclude(char *pattern); extern int jte_add_include(char *pattern); extern int jte_add_mapping(char *arg); +typedef enum _jtc_e +{ + JTE_TEMP_GZIP = 0, + JTE_TEMP_BZIP2 +} jtc_t; + +extern jtc_t jte_template_compression; + + #define MIN_JIGDO_FILE_SIZE 1024 diff --git a/genisoimage/sha1.c b/genisoimage/sha1.c new file mode 100644 index 0000000..ae410ac --- /dev/null +++ b/genisoimage/sha1.c @@ -0,0 +1,415 @@ +/* sha1.c - Functions to compute SHA1 message digest of files or + memory blocks according to the NIST specification FIPS-180-1. + + Copyright (C) 2000, 2001, 2003, 2004, 2005 Free Software Foundation, Inc. + + 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, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* Written by Scott G. Miller + Credits: + Robert Klep -- Expansion function fix +*/ + +#include "sha1.h" + +#include +#include + +/* SWAP does an endian swap on architectures that are little-endian, + as SHA1 needs some data in a big-endian form. */ + +#ifdef WORDS_BIGENDIAN +# define SWAP(n) (n) +#else +# define SWAP(n) \ + (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) +#endif + +#define BLOCKSIZE 4096 +#if BLOCKSIZE % 64 != 0 +# error "invalid BLOCKSIZE" +#endif + +/* This array contains the bytes used to pad the buffer to the next + 64-byte boundary. (RFC 1321, 3.1: Step 1) */ +static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ... */ }; + + +/* + Takes a pointer to a 160 bit block of data (five 32 bit ints) and + intializes it to the start constants of the SHA1 algorithm. This + must be called before using hash in the call to sha1_hash. +*/ +void +sha1_init_ctx (struct sha1_ctx *ctx) +{ + ctx->A = 0x67452301; + ctx->B = 0xefcdab89; + ctx->C = 0x98badcfe; + ctx->D = 0x10325476; + ctx->E = 0xc3d2e1f0; + + ctx->total[0] = ctx->total[1] = 0; + ctx->buflen = 0; +} + +/* Put result from CTX in first 20 bytes following RESBUF. The result + must be in little endian byte order. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +void * +sha1_read_ctx (const struct sha1_ctx *ctx, void *resbuf) +{ + ((md5_uint32 *) resbuf)[0] = SWAP (ctx->A); + ((md5_uint32 *) resbuf)[1] = SWAP (ctx->B); + ((md5_uint32 *) resbuf)[2] = SWAP (ctx->C); + ((md5_uint32 *) resbuf)[3] = SWAP (ctx->D); + ((md5_uint32 *) resbuf)[4] = SWAP (ctx->E); + + return resbuf; +} + +/* Process the remaining bytes in the internal buffer and the usual + prolog according to the standard and write the result to RESBUF. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +void * +sha1_finish_ctx (struct sha1_ctx *ctx, void *resbuf) +{ + /* Take yet unprocessed bytes into account. */ + md5_uint32 bytes = ctx->buflen; + size_t pad; + + /* Now count remaining bytes. */ + ctx->total[0] += bytes; + if (ctx->total[0] < bytes) + ++ctx->total[1]; + + pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes; + memcpy (&ctx->buffer[bytes], fillbuf, pad); + + /* Put the 64-bit file length in *bits* at the end of the buffer. */ + *(md5_uint32 *) &ctx->buffer[bytes + pad + 4] = SWAP (ctx->total[0] << 3); + *(md5_uint32 *) &ctx->buffer[bytes + pad] = SWAP ((ctx->total[1] << 3) | + (ctx->total[0] >> 29)); + + /* Process last bytes. */ + sha1_process_block (ctx->buffer, bytes + pad + 8, ctx); + + return sha1_read_ctx (ctx, resbuf); +} + +/* Compute SHA1 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 16 bytes + beginning at RESBLOCK. */ +int +sha1_stream (FILE *stream, void *resblock) +{ + struct sha1_ctx ctx; + char buffer[BLOCKSIZE + 72]; + size_t sum; + + /* Initialize the computation context. */ + sha1_init_ctx (&ctx); + + /* Iterate over full file contents. */ + while (1) + { + /* We read the file in blocks of BLOCKSIZE bytes. One call of the + computation function processes the whole buffer so that with the + next round of the loop another block can be read. */ + size_t n; + sum = 0; + + /* Read block. Take care for partial reads. */ + while (1) + { + n = fread (buffer + sum, 1, BLOCKSIZE - sum, stream); + + sum += n; + + if (sum == BLOCKSIZE) + break; + + if (n == 0) + { + /* Check for the error flag IFF N == 0, so that we don't + exit the loop after a partial read due to e.g., EAGAIN + or EWOULDBLOCK. */ + if (ferror (stream)) + return 1; + goto process_partial_block; + } + + /* We've read at least one byte, so ignore errors. But always + check for EOF, since feof may be true even though N > 0. + Otherwise, we could end up calling fread after EOF. */ + if (feof (stream)) + goto process_partial_block; + } + + /* Process buffer with BLOCKSIZE bytes. Note that + BLOCKSIZE % 64 == 0 + */ + sha1_process_block (buffer, BLOCKSIZE, &ctx); + } + + process_partial_block:; + + /* Process any remaining bytes. */ + if (sum > 0) + sha1_process_bytes (buffer, sum, &ctx); + + /* Construct result in desired memory. */ + sha1_finish_ctx (&ctx, resblock); + return 0; +} + +/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +void * +sha1_buffer (const char *buffer, size_t len, void *resblock) +{ + struct sha1_ctx ctx; + + /* Initialize the computation context. */ + sha1_init_ctx (&ctx); + + /* Process whole buffer but last len % 64 bytes. */ + sha1_process_bytes (buffer, len, &ctx); + + /* Put result in desired memory area. */ + return sha1_finish_ctx (&ctx, resblock); +} + +void +sha1_process_bytes (const void *buffer, size_t len, struct sha1_ctx *ctx) +{ + /* When we already have some bits in our internal buffer concatenate + both inputs first. */ + if (ctx->buflen != 0) + { + size_t left_over = ctx->buflen; + size_t add = 128 - left_over > len ? len : 128 - left_over; + + memcpy (&ctx->buffer[left_over], buffer, add); + ctx->buflen += add; + + if (ctx->buflen > 64) + { + sha1_process_block (ctx->buffer, ctx->buflen & ~63, ctx); + + ctx->buflen &= 63; + /* The regions in the following copy operation cannot overlap. */ + memcpy (ctx->buffer, &ctx->buffer[(left_over + add) & ~63], + ctx->buflen); + } + + buffer = (const char *) buffer + add; + len -= add; + } + + /* Process available complete blocks. */ + if (len >= 64) + { +#if !_STRING_ARCH_unaligned +# define alignof(type) offsetof (struct { char c; type x; }, x) +# define UNALIGNED_P(p) (((size_t) p) % alignof (md5_uint32) != 0) + if (UNALIGNED_P (buffer)) + while (len > 64) + { + sha1_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx); + buffer = (const char *) buffer + 64; + len -= 64; + } + else +#endif + { + sha1_process_block (buffer, len & ~63, ctx); + buffer = (const char *) buffer + (len & ~63); + len &= 63; + } + } + + /* Move remaining bytes in internal buffer. */ + if (len > 0) + { + size_t left_over = ctx->buflen; + + memcpy (&ctx->buffer[left_over], buffer, len); + left_over += len; + if (left_over >= 64) + { + sha1_process_block (ctx->buffer, 64, ctx); + left_over -= 64; + memcpy (ctx->buffer, &ctx->buffer[64], left_over); + } + ctx->buflen = left_over; + } +} + +/* --- Code below is the primary difference between md5.c and sha1.c --- */ + +/* SHA1 round constants */ +#define K1 0x5a827999L +#define K2 0x6ed9eba1L +#define K3 0x8f1bbcdcL +#define K4 0xca62c1d6L + +/* Round functions. Note that F2 is the same as F4. */ +#define F1(B,C,D) ( D ^ ( B & ( C ^ D ) ) ) +#define F2(B,C,D) (B ^ C ^ D) +#define F3(B,C,D) ( ( B & C ) | ( D & ( B | C ) ) ) +#define F4(B,C,D) (B ^ C ^ D) + +/* Process LEN bytes of BUFFER, accumulating context into CTX. + It is assumed that LEN % 64 == 0. + Most of this code comes from GnuPG's cipher/sha1.c. */ + +void +sha1_process_block (const void *buffer, size_t len, struct sha1_ctx *ctx) +{ + const md5_uint32 *words = buffer; + size_t nwords = len / sizeof (md5_uint32); + const md5_uint32 *endp = words + nwords; + md5_uint32 x[16]; + md5_uint32 a = ctx->A; + md5_uint32 b = ctx->B; + md5_uint32 c = ctx->C; + md5_uint32 d = ctx->D; + md5_uint32 e = ctx->E; + + /* First increment the byte count. RFC 1321 specifies the possible + length of the file up to 2^64 bits. Here we only compute the + number of bytes. Do a double word increment. */ + ctx->total[0] += len; + if (ctx->total[0] < len) + ++ctx->total[1]; + +#define rol(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + +#define M(I) ( tm = x[I&0x0f] ^ x[(I-14)&0x0f] \ + ^ x[(I-8)&0x0f] ^ x[(I-3)&0x0f] \ + , (x[I&0x0f] = rol(tm, 1)) ) + +#define R(A,B,C,D,E,F,K,M) do { E += rol( A, 5 ) \ + + F( B, C, D ) \ + + K \ + + M; \ + B = rol( B, 30 ); \ + } while(0) + + while (words < endp) + { + md5_uint32 tm; + int t; + for (t = 0; t < 16; t++) + { + x[t] = SWAP (*words); + words++; + } + + R( a, b, c, d, e, F1, K1, x[ 0] ); + R( e, a, b, c, d, F1, K1, x[ 1] ); + R( d, e, a, b, c, F1, K1, x[ 2] ); + R( c, d, e, a, b, F1, K1, x[ 3] ); + R( b, c, d, e, a, F1, K1, x[ 4] ); + R( a, b, c, d, e, F1, K1, x[ 5] ); + R( e, a, b, c, d, F1, K1, x[ 6] ); + R( d, e, a, b, c, F1, K1, x[ 7] ); + R( c, d, e, a, b, F1, K1, x[ 8] ); + R( b, c, d, e, a, F1, K1, x[ 9] ); + R( a, b, c, d, e, F1, K1, x[10] ); + R( e, a, b, c, d, F1, K1, x[11] ); + R( d, e, a, b, c, F1, K1, x[12] ); + R( c, d, e, a, b, F1, K1, x[13] ); + R( b, c, d, e, a, F1, K1, x[14] ); + R( a, b, c, d, e, F1, K1, x[15] ); + R( e, a, b, c, d, F1, K1, M(16) ); + R( d, e, a, b, c, F1, K1, M(17) ); + R( c, d, e, a, b, F1, K1, M(18) ); + R( b, c, d, e, a, F1, K1, M(19) ); + R( a, b, c, d, e, F2, K2, M(20) ); + R( e, a, b, c, d, F2, K2, M(21) ); + R( d, e, a, b, c, F2, K2, M(22) ); + R( c, d, e, a, b, F2, K2, M(23) ); + R( b, c, d, e, a, F2, K2, M(24) ); + R( a, b, c, d, e, F2, K2, M(25) ); + R( e, a, b, c, d, F2, K2, M(26) ); + R( d, e, a, b, c, F2, K2, M(27) ); + R( c, d, e, a, b, F2, K2, M(28) ); + R( b, c, d, e, a, F2, K2, M(29) ); + R( a, b, c, d, e, F2, K2, M(30) ); + R( e, a, b, c, d, F2, K2, M(31) ); + R( d, e, a, b, c, F2, K2, M(32) ); + R( c, d, e, a, b, F2, K2, M(33) ); + R( b, c, d, e, a, F2, K2, M(34) ); + R( a, b, c, d, e, F2, K2, M(35) ); + R( e, a, b, c, d, F2, K2, M(36) ); + R( d, e, a, b, c, F2, K2, M(37) ); + R( c, d, e, a, b, F2, K2, M(38) ); + R( b, c, d, e, a, F2, K2, M(39) ); + R( a, b, c, d, e, F3, K3, M(40) ); + R( e, a, b, c, d, F3, K3, M(41) ); + R( d, e, a, b, c, F3, K3, M(42) ); + R( c, d, e, a, b, F3, K3, M(43) ); + R( b, c, d, e, a, F3, K3, M(44) ); + R( a, b, c, d, e, F3, K3, M(45) ); + R( e, a, b, c, d, F3, K3, M(46) ); + R( d, e, a, b, c, F3, K3, M(47) ); + R( c, d, e, a, b, F3, K3, M(48) ); + R( b, c, d, e, a, F3, K3, M(49) ); + R( a, b, c, d, e, F3, K3, M(50) ); + R( e, a, b, c, d, F3, K3, M(51) ); + R( d, e, a, b, c, F3, K3, M(52) ); + R( c, d, e, a, b, F3, K3, M(53) ); + R( b, c, d, e, a, F3, K3, M(54) ); + R( a, b, c, d, e, F3, K3, M(55) ); + R( e, a, b, c, d, F3, K3, M(56) ); + R( d, e, a, b, c, F3, K3, M(57) ); + R( c, d, e, a, b, F3, K3, M(58) ); + R( b, c, d, e, a, F3, K3, M(59) ); + R( a, b, c, d, e, F4, K4, M(60) ); + R( e, a, b, c, d, F4, K4, M(61) ); + R( d, e, a, b, c, F4, K4, M(62) ); + R( c, d, e, a, b, F4, K4, M(63) ); + R( b, c, d, e, a, F4, K4, M(64) ); + R( a, b, c, d, e, F4, K4, M(65) ); + R( e, a, b, c, d, F4, K4, M(66) ); + R( d, e, a, b, c, F4, K4, M(67) ); + R( c, d, e, a, b, F4, K4, M(68) ); + R( b, c, d, e, a, F4, K4, M(69) ); + R( a, b, c, d, e, F4, K4, M(70) ); + R( e, a, b, c, d, F4, K4, M(71) ); + R( d, e, a, b, c, F4, K4, M(72) ); + R( c, d, e, a, b, F4, K4, M(73) ); + R( b, c, d, e, a, F4, K4, M(74) ); + R( a, b, c, d, e, F4, K4, M(75) ); + R( e, a, b, c, d, F4, K4, M(76) ); + R( d, e, a, b, c, F4, K4, M(77) ); + R( c, d, e, a, b, F4, K4, M(78) ); + R( b, c, d, e, a, F4, K4, M(79) ); + + a = ctx->A += a; + b = ctx->B += b; + c = ctx->C += c; + d = ctx->D += d; + e = ctx->E += e; + } +} diff --git a/genisoimage/sha1.h b/genisoimage/sha1.h new file mode 100644 index 0000000..c263810 --- /dev/null +++ b/genisoimage/sha1.h @@ -0,0 +1,88 @@ +/* Declarations of functions and data types used for SHA1 sum + library functions. + Copyright (C) 2000, 2001, 2003, 2005 Free Software Foundation, Inc. + + 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, 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef SHA1_H +# define SHA1_H 1 + +# include + +typedef unsigned long md5_uint32; + +/* Structure to save state of computation between the single steps. */ +struct sha1_ctx +{ + md5_uint32 A; + md5_uint32 B; + md5_uint32 C; + md5_uint32 D; + md5_uint32 E; + + md5_uint32 total[2]; + md5_uint32 buflen; + char buffer[128] __attribute__ ((__aligned__ (__alignof__ (md5_uint32)))); +}; + + +/* Initialize structure containing state of computation. */ +extern void sha1_init_ctx (struct sha1_ctx *ctx); + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is necessary that LEN is a multiple of 64!!! */ +extern void sha1_process_block (const void *buffer, size_t len, + struct sha1_ctx *ctx); + +/* Starting with the result of former calls of this function (or the + initialization function update the context for the next LEN bytes + starting at BUFFER. + It is NOT required that LEN is a multiple of 64. */ +extern void sha1_process_bytes (const void *buffer, size_t len, + struct sha1_ctx *ctx); + +/* Process the remaining bytes in the buffer and put result from CTX + in first 20 bytes following RESBUF. The result is always in little + endian byte order, so that a byte-wise output yields to the wanted + ASCII representation of the message digest. + + IMPORTANT: On some systems it is required that RESBUF be correctly + aligned for a 32 bits value. */ +extern void *sha1_finish_ctx (struct sha1_ctx *ctx, void *resbuf); + + +/* Put result from CTX in first 20 bytes following RESBUF. The result is + always in little endian byte order, so that a byte-wise output yields + to the wanted ASCII representation of the message digest. + + IMPORTANT: On some systems it is required that RESBUF is correctly + aligned for a 32 bits value. */ +extern void *sha1_read_ctx (const struct sha1_ctx *ctx, void *resbuf); + + +/* Compute SHA1 message digest for bytes read from STREAM. The + resulting message digest number will be written into the 20 bytes + beginning at RESBLOCK. */ +extern int sha1_stream (FILE *stream, void *resblock); + +/* Compute SHA1 message digest for LEN bytes beginning at BUFFER. The + result is always in little endian byte order, so that a byte-wise + output yields to the wanted ASCII representation of the message + digest. */ +extern void *sha1_buffer (const char *buffer, size_t len, void *resblock); + +#endif