"Fossies" - the Fresh Open Source Software Archive

Member "xorriso-1.5.4/libisofs/md5.c" (30 Jan 2021, 28197 Bytes) of package /linux/misc/xorriso-1.5.4.pl02.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "md5.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.5.2_vs_1.5.4.

    1 /*
    2  * Copyright (c) 2009 - 2013 Thomas Schmitt
    3  *
    4  * This file is part of the libisofs project; you can redistribute it and/or
    5  * modify it under the terms of the GNU General Public License version 2 
    6  * or later as published by the Free Software Foundation. 
    7  * See COPYING file for details.
    8  */
    9 
   10 
   11 #ifdef HAVE_CONFIG_H
   12 #include "../config.h"
   13 #endif
   14 
   15 #ifdef HAVE_STDINT_H
   16 #include <stdint.h>
   17 #else
   18 #ifdef HAVE_INTTYPES_H
   19 #include <inttypes.h>
   20 #endif
   21 #endif
   22 
   23 #include <stdlib.h>
   24 #include <string.h>
   25 #include <stdio.h>
   26 
   27 #include "writer.h"
   28 #include "messages.h"
   29 #include "ecma119.h"
   30 #include "image.h"
   31 #include "util.h"
   32 
   33 #include "md5.h"
   34 
   35 
   36 /* This code is derived from RFC 1321 and implements computation of the
   37     "RSA Data Security, Inc. MD5 Message-Digest Algorithm" */
   38 
   39 #define Libisofs_md5_S11 7
   40 #define Libisofs_md5_S12 12
   41 #define Libisofs_md5_S13 17
   42 #define Libisofs_md5_S14 22
   43 #define Libisofs_md5_S21 5
   44 #define Libisofs_md5_S22 9
   45 #define Libisofs_md5_S23 14
   46 #define Libisofs_md5_S24 20
   47 #define Libisofs_md5_S31 4
   48 #define Libisofs_md5_S32 11
   49 #define Libisofs_md5_S33 16
   50 #define Libisofs_md5_S34 23
   51 #define Libisofs_md5_S41 6
   52 #define Libisofs_md5_S42 10
   53 #define Libisofs_md5_S43 15
   54 #define Libisofs_md5_S44 21
   55 
   56 
   57 /* F, G, H and I are basic MD5 functions.
   58  */
   59 #define Libisofs_md5_F(x, y, z) (((x) & (y)) | ((~x) & (z)))
   60 #define Libisofs_md5_G(x, y, z) (((x) & (z)) | ((y) & (~z)))
   61 #define Libisofs_md5_H(x, y, z) ((x) ^ (y) ^ (z))
   62 #define Libisofs_md5_I(x, y, z) ((y) ^ ((x) | (~z)))
   63 
   64 /* ROTATE_LEFT rotates x left n bits.
   65  */
   66 #define Libisofs_md5_ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
   67 
   68 /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
   69 Rotation is separate from addition to prevent recomputation.
   70  */
   71 #define Libisofs_md5_FF(a, b, c, d, x, s, ac) { \
   72  (a) += Libisofs_md5_F ((b), (c), (d)) + (x) + (uint32_t)(ac); \
   73  (a) = Libisofs_md5_ROTATE_LEFT ((a), (s)); \
   74  (a) += (b); \
   75   }
   76 #define Libisofs_md5_GG(a, b, c, d, x, s, ac) { \
   77  (a) += Libisofs_md5_G ((b), (c), (d)) + (x) + (uint32_t)(ac); \
   78  (a) = Libisofs_md5_ROTATE_LEFT ((a), (s)); \
   79  (a) += (b); \
   80   }
   81 #define Libisofs_md5_HH(a, b, c, d, x, s, ac) { \
   82  (a) += Libisofs_md5_H ((b), (c), (d)) + (x) + (uint32_t)(ac); \
   83  (a) = Libisofs_md5_ROTATE_LEFT ((a), (s)); \
   84  (a) += (b); \
   85   }
   86 #define Libisofs_md5_II(a, b, c, d, x, s, ac) { \
   87  (a) += Libisofs_md5_I ((b), (c), (d)) + (x) + (uint32_t)(ac); \
   88  (a) = Libisofs_md5_ROTATE_LEFT ((a), (s)); \
   89  (a) += (b); \
   90   }
   91 
   92 
   93 /* MD5 context. */
   94 struct _libisofs_md5_ctx {
   95   uint32_t state[4];                                   /* state (ABCD) */
   96   uint32_t count[2];        /* number of bits, modulo 2^64 (lsb first) */
   97   unsigned char buffer[64];                         /* input buffer */
   98 };
   99 
  100 typedef struct _libisofs_md5_ctx libisofs_md5_ctx;
  101 
  102 
  103 /* MD5 basic transformation. Transforms state based on block.
  104  */
  105 static int md5__transform (uint32_t state[4], unsigned char block[64])
  106 {
  107  uint32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16];
  108  unsigned int i, j;
  109 
  110  for (i = 0, j = 0; j < 64; i++, j += 4)
  111    x[i] = ((uint32_t)block[j]) | (((uint32_t)block[j+1]) << 8) |
  112     (((uint32_t)block[j+2]) << 16) | (((uint32_t)block[j+3]) << 24);
  113 
  114   /* Round 1 */
  115   Libisofs_md5_FF (a, b, c, d, x[ 0], Libisofs_md5_S11, 0xd76aa478); /* 1 */
  116   Libisofs_md5_FF (d, a, b, c, x[ 1], Libisofs_md5_S12, 0xe8c7b756); /* 2 */
  117   Libisofs_md5_FF (c, d, a, b, x[ 2], Libisofs_md5_S13, 0x242070db); /* 3 */
  118   Libisofs_md5_FF (b, c, d, a, x[ 3], Libisofs_md5_S14, 0xc1bdceee); /* 4 */
  119   Libisofs_md5_FF (a, b, c, d, x[ 4], Libisofs_md5_S11, 0xf57c0faf); /* 5 */
  120   Libisofs_md5_FF (d, a, b, c, x[ 5], Libisofs_md5_S12, 0x4787c62a); /* 6 */
  121   Libisofs_md5_FF (c, d, a, b, x[ 6], Libisofs_md5_S13, 0xa8304613); /* 7 */
  122   Libisofs_md5_FF (b, c, d, a, x[ 7], Libisofs_md5_S14, 0xfd469501); /* 8 */
  123   Libisofs_md5_FF (a, b, c, d, x[ 8], Libisofs_md5_S11, 0x698098d8); /* 9 */
  124   Libisofs_md5_FF (d, a, b, c, x[ 9], Libisofs_md5_S12, 0x8b44f7af); /* 10 */
  125   Libisofs_md5_FF (c, d, a, b, x[10], Libisofs_md5_S13, 0xffff5bb1); /* 11 */
  126   Libisofs_md5_FF (b, c, d, a, x[11], Libisofs_md5_S14, 0x895cd7be); /* 12 */
  127   Libisofs_md5_FF (a, b, c, d, x[12], Libisofs_md5_S11, 0x6b901122); /* 13 */
  128   Libisofs_md5_FF (d, a, b, c, x[13], Libisofs_md5_S12, 0xfd987193); /* 14 */
  129   Libisofs_md5_FF (c, d, a, b, x[14], Libisofs_md5_S13, 0xa679438e); /* 15 */
  130   Libisofs_md5_FF (b, c, d, a, x[15], Libisofs_md5_S14, 0x49b40821); /* 16 */
  131 
  132   /* Round 2 */
  133   Libisofs_md5_GG (a, b, c, d, x[ 1], Libisofs_md5_S21, 0xf61e2562); /* 17 */
  134   Libisofs_md5_GG (d, a, b, c, x[ 6], Libisofs_md5_S22, 0xc040b340); /* 18 */
  135   Libisofs_md5_GG (c, d, a, b, x[11], Libisofs_md5_S23, 0x265e5a51); /* 19 */
  136   Libisofs_md5_GG (b, c, d, a, x[ 0], Libisofs_md5_S24, 0xe9b6c7aa); /* 20 */
  137   Libisofs_md5_GG (a, b, c, d, x[ 5], Libisofs_md5_S21, 0xd62f105d); /* 21 */
  138   Libisofs_md5_GG (d, a, b, c, x[10], Libisofs_md5_S22,  0x2441453); /* 22 */
  139   Libisofs_md5_GG (c, d, a, b, x[15], Libisofs_md5_S23, 0xd8a1e681); /* 23 */
  140   Libisofs_md5_GG (b, c, d, a, x[ 4], Libisofs_md5_S24, 0xe7d3fbc8); /* 24 */
  141   Libisofs_md5_GG (a, b, c, d, x[ 9], Libisofs_md5_S21, 0x21e1cde6); /* 25 */
  142   Libisofs_md5_GG (d, a, b, c, x[14], Libisofs_md5_S22, 0xc33707d6); /* 26 */
  143   Libisofs_md5_GG (c, d, a, b, x[ 3], Libisofs_md5_S23, 0xf4d50d87); /* 27 */
  144   Libisofs_md5_GG (b, c, d, a, x[ 8], Libisofs_md5_S24, 0x455a14ed); /* 28 */
  145   Libisofs_md5_GG (a, b, c, d, x[13], Libisofs_md5_S21, 0xa9e3e905); /* 29 */
  146   Libisofs_md5_GG (d, a, b, c, x[ 2], Libisofs_md5_S22, 0xfcefa3f8); /* 30 */
  147   Libisofs_md5_GG (c, d, a, b, x[ 7], Libisofs_md5_S23, 0x676f02d9); /* 31 */
  148   Libisofs_md5_GG (b, c, d, a, x[12], Libisofs_md5_S24, 0x8d2a4c8a); /* 32 */
  149 
  150   /* Round 3 */
  151   Libisofs_md5_HH (a, b, c, d, x[ 5], Libisofs_md5_S31, 0xfffa3942); /* 33 */
  152   Libisofs_md5_HH (d, a, b, c, x[ 8], Libisofs_md5_S32, 0x8771f681); /* 34 */
  153   Libisofs_md5_HH (c, d, a, b, x[11], Libisofs_md5_S33, 0x6d9d6122); /* 35 */
  154   Libisofs_md5_HH (b, c, d, a, x[14], Libisofs_md5_S34, 0xfde5380c); /* 36 */
  155   Libisofs_md5_HH (a, b, c, d, x[ 1], Libisofs_md5_S31, 0xa4beea44); /* 37 */
  156   Libisofs_md5_HH (d, a, b, c, x[ 4], Libisofs_md5_S32, 0x4bdecfa9); /* 38 */
  157   Libisofs_md5_HH (c, d, a, b, x[ 7], Libisofs_md5_S33, 0xf6bb4b60); /* 39 */
  158   Libisofs_md5_HH (b, c, d, a, x[10], Libisofs_md5_S34, 0xbebfbc70); /* 40 */
  159   Libisofs_md5_HH (a, b, c, d, x[13], Libisofs_md5_S31, 0x289b7ec6); /* 41 */
  160   Libisofs_md5_HH (d, a, b, c, x[ 0], Libisofs_md5_S32, 0xeaa127fa); /* 42 */
  161   Libisofs_md5_HH (c, d, a, b, x[ 3], Libisofs_md5_S33, 0xd4ef3085); /* 43 */
  162   Libisofs_md5_HH (b, c, d, a, x[ 6], Libisofs_md5_S34,  0x4881d05); /* 44 */
  163   Libisofs_md5_HH (a, b, c, d, x[ 9], Libisofs_md5_S31, 0xd9d4d039); /* 45 */
  164   Libisofs_md5_HH (d, a, b, c, x[12], Libisofs_md5_S32, 0xe6db99e5); /* 46 */
  165   Libisofs_md5_HH (c, d, a, b, x[15], Libisofs_md5_S33, 0x1fa27cf8); /* 47 */
  166   Libisofs_md5_HH (b, c, d, a, x[ 2], Libisofs_md5_S34, 0xc4ac5665); /* 48 */
  167 
  168   /* Round 4 */
  169   Libisofs_md5_II (a, b, c, d, x[ 0], Libisofs_md5_S41, 0xf4292244); /* 49 */
  170   Libisofs_md5_II (d, a, b, c, x[ 7], Libisofs_md5_S42, 0x432aff97); /* 50 */
  171   Libisofs_md5_II (c, d, a, b, x[14], Libisofs_md5_S43, 0xab9423a7); /* 51 */
  172   Libisofs_md5_II (b, c, d, a, x[ 5], Libisofs_md5_S44, 0xfc93a039); /* 52 */
  173   Libisofs_md5_II (a, b, c, d, x[12], Libisofs_md5_S41, 0x655b59c3); /* 53 */
  174   Libisofs_md5_II (d, a, b, c, x[ 3], Libisofs_md5_S42, 0x8f0ccc92); /* 54 */
  175   Libisofs_md5_II (c, d, a, b, x[10], Libisofs_md5_S43, 0xffeff47d); /* 55 */
  176   Libisofs_md5_II (b, c, d, a, x[ 1], Libisofs_md5_S44, 0x85845dd1); /* 56 */
  177   Libisofs_md5_II (a, b, c, d, x[ 8], Libisofs_md5_S41, 0x6fa87e4f); /* 57 */
  178   Libisofs_md5_II (d, a, b, c, x[15], Libisofs_md5_S42, 0xfe2ce6e0); /* 58 */
  179   Libisofs_md5_II (c, d, a, b, x[ 6], Libisofs_md5_S43, 0xa3014314); /* 59 */
  180   Libisofs_md5_II (b, c, d, a, x[13], Libisofs_md5_S44, 0x4e0811a1); /* 60 */
  181   Libisofs_md5_II (a, b, c, d, x[ 4], Libisofs_md5_S41, 0xf7537e82); /* 61 */
  182   Libisofs_md5_II (d, a, b, c, x[11], Libisofs_md5_S42, 0xbd3af235); /* 62 */
  183   Libisofs_md5_II (c, d, a, b, x[ 2], Libisofs_md5_S43, 0x2ad7d2bb); /* 63 */
  184   Libisofs_md5_II (b, c, d, a, x[ 9], Libisofs_md5_S44, 0xeb86d391); /* 64 */
  185 
  186   state[0] += a;
  187   state[1] += b;
  188   state[2] += c;
  189   state[3] += d;
  190 
  191   /* Zeroize sensitive information. */
  192   memset ((char *) x, 0, sizeof (x));
  193   return(1);
  194 }
  195 
  196 
  197 static int md5__encode(unsigned char *output, uint32_t *input,
  198                        unsigned int len)
  199 {
  200   unsigned int i, j;
  201 
  202   for (i = 0, j = 0; j < len; i++, j += 4) {
  203     output[j] = (unsigned char)(input[i] & 0xff);
  204     output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
  205     output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
  206     output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
  207   }
  208   return(1);
  209 }
  210 
  211 
  212 
  213 static int md5_init(libisofs_md5_ctx *ctx, int flag)
  214 {
  215  ctx->count[0] = ctx->count[1] = 0;
  216  /* Load magic initialization constants. */
  217  ctx->state[0] = 0x67452301;
  218  ctx->state[1] = 0xefcdab89;
  219  ctx->state[2] = 0x98badcfe;
  220  ctx->state[3] = 0x10325476;
  221  return(1);
  222 }
  223 
  224 
  225 /* MD5 block update operation. Continues an MD5 message-digest
  226   operation, processing another message block, and updating the
  227   context.
  228  */
  229 static int md5_update(libisofs_md5_ctx *ctx, unsigned char *data,
  230                       int datalen, int flag)
  231 {
  232  int i, index, partlen;
  233 
  234  /* Compute number of bytes mod 64 */
  235  index = ((ctx->count[0] >> 3) & 0x3F);
  236  /* Update number of bits */
  237  if ((ctx->count[0] += ((uint32_t) datalen << 3)) < 
  238      ((uint32_t) datalen << 3))
  239    ctx->count[1]++;
  240  ctx->count[1] += ((uint32_t) datalen >> 29);
  241  partlen = 64 - index;
  242 
  243  /* Transform as many times as possible. */
  244  if (datalen >= partlen) {
  245    memcpy((char *) &ctx->buffer[index], (char *) data, partlen);
  246    md5__transform(ctx->state, ctx->buffer);
  247    for (i = partlen; i + 63 < datalen; i += 64)
  248      md5__transform(ctx->state, &data[i]);
  249    index = 0;
  250  } else
  251    i = 0;
  252 
  253  /* Buffer remaining data */
  254  memcpy((char *) &ctx->buffer[index], (char *) &data[i],datalen-i);
  255 
  256  return(1);
  257 }
  258 
  259 
  260 static int md5_final(libisofs_md5_ctx *ctx, char result[16], int flag)
  261 {
  262  unsigned char bits[8], *respt;
  263  unsigned int index, padlen;
  264  static unsigned char PADDING[64] = {
  265    0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  266    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  267    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
  268  };
  269 
  270  /* Save number of bits */
  271  md5__encode(bits, ctx->count, 8);
  272  /* Pad out to 56 mod 64.  */
  273  index = (unsigned int)((ctx->count[0] >> 3) & 0x3f);
  274  padlen = (index < 56) ? (56 - index) : (120 - index);
  275  md5_update(ctx, PADDING, padlen,0);
  276  /* Append length (before padding) */
  277  md5_update(ctx, bits, 8,0);
  278  /* Store state in result */
  279  respt= (unsigned char *) result;
  280  md5__encode(respt, ctx->state, 16);
  281  /* Zeroize sensitive information.  */
  282  memset ((char *) ctx, 0, sizeof (*ctx));
  283  return(1);
  284 }
  285 
  286 /** Compute a MD5 checksum from one or more calls of this function.
  287     The first call has to be made with flag bit0 == 1. It may already submit
  288     processing payload in data and datalen.
  289     The last call has to be made with bit15 set. Normally bit1 will be set
  290     too in order to receive the checksum before it gets disposed. 
  291     bit1 may only be set in the last call or together with bit2.
  292     The combination of bit1 and bit2 may be used to get an intermediate
  293     result without hampering an ongoing checksum computation.
  294 
  295     @param ctx      the checksum context which stores the state between calls.
  296                     It gets created with flag bit0 and disposed with bit15.
  297                     With flag bit0, *ctx has to be NULL or point to freeable
  298                     memory.
  299     @param data     the bytes to be checksummed
  300     @param datalen  the number of bytes in data
  301     @param result   returns the 16 bytes of checksum if called with bit1 set
  302     @param flag     bit0= allocate and init *ctx
  303                     bit1= transfer ctx to result
  304                     bit2= with bit 0 : clone new *ctx from data
  305                     bit15= free *ctx
  306 */
  307 static
  308 int libisofs_md5(void **ctx_in, char *data, int datalen,
  309                  char result[16], int flag)
  310 /* *ctx has to be NULL or point to freeable memory */
  311 /*
  312  bit0= allocate and init *ctx
  313  bit1= transfer ctx to result
  314  bit2= with bit 0 : clone new *ctx from data
  315  bit15= free *ctx
  316 */
  317 {
  318  unsigned char *datapt;
  319  libisofs_md5_ctx **ctx;
  320 
  321  ctx= (libisofs_md5_ctx **) ctx_in;
  322  if(flag&1) {
  323    if(*ctx!=NULL)
  324      free((char *) *ctx);
  325    *ctx= calloc(1, sizeof(libisofs_md5_ctx));
  326    if(*ctx==NULL)
  327      return(-1);
  328    md5_init(*ctx,0);
  329    if(flag&4)
  330      memcpy((char *) *ctx,data,sizeof(libisofs_md5_ctx));
  331  }
  332  if(*ctx==NULL)
  333    return(0);
  334  if(datalen>0) {
  335    datapt= (unsigned char *) data;
  336    md5_update(*ctx, datapt, datalen, 0);
  337  }
  338  if(flag&2)
  339    md5_final(*ctx, result, 0);
  340  if(flag&(1<<15)) {
  341    free((char *) *ctx);
  342    *ctx= NULL;
  343  }
  344  return(1);
  345 }
  346 
  347 
  348 /* ----------------------------------------------------------------------- */
  349 
  350 /* Public MD5 computing facility */
  351 
  352 /* API */
  353 int iso_md5_start(void **md5_context)
  354 {
  355     int ret;
  356 
  357     ret = libisofs_md5(md5_context, NULL, 0, NULL, 1);
  358     if (ret <= 0)
  359         return ISO_OUT_OF_MEM;
  360     return 1;
  361 }
  362 
  363 
  364 /* API */
  365 int iso_md5_compute(void *md5_context, char *data, int datalen)
  366 {
  367     int ret;
  368 
  369     ret = libisofs_md5(&md5_context, data, datalen, NULL, 0);
  370     if (ret <= 0)
  371         return ISO_NULL_POINTER;
  372     return 1;
  373 }
  374 
  375 
  376 /* API */
  377 int iso_md5_clone(void *old_md5_context, void **new_md5_context)
  378 {
  379     int ret;
  380 
  381     ret = libisofs_md5(new_md5_context, old_md5_context, 0, NULL, 1 | 4);
  382     if (ret < 0)
  383         return ISO_OUT_OF_MEM;
  384     if (ret == 0)
  385         return ISO_NULL_POINTER;
  386     return 1;
  387 }
  388 
  389 
  390 /* API */
  391 int iso_md5_end(void **md5_context, char result[16])
  392 {
  393     int ret;
  394 
  395     ret = libisofs_md5(md5_context, NULL, 0, result, 2 | (1 << 15));
  396     if (ret <= 0)
  397         return ISO_NULL_POINTER;
  398     return 1;
  399 }
  400 
  401 
  402 /* API */
  403 int iso_md5_match(char first_md5[16], char second_md5[16])
  404 {
  405     int i;
  406 
  407     for (i= 0; i < 16; i++)
  408         if (first_md5[i] != second_md5[i])
  409             return 0;
  410     return 1;
  411 }
  412 
  413 
  414 /* ----------------------------------------------------------------------- */
  415 
  416 
  417 /* Function to identify and manage md5sum indice of the old image.
  418  * data is supposed to be a 4 byte integer, bit 31 shall be 0,
  419  * value 0 of this integer means that it is not a valid index.
  420  */
  421 int checksum_cx_xinfo_func(void *data, int flag)
  422 {
  423     /* data is an int disguised as pointer. It does not point to memory. */
  424     return 1;
  425 }
  426 
  427 /* The iso_node_xinfo_cloner function which gets associated to
  428  * checksum_cx_xinfo_func by iso_init() resp. iso_init_with_flag() via
  429  * iso_node_xinfo_make_clonable()
  430  */
  431 int checksum_cx_xinfo_cloner(void *old_data, void **new_data, int flag)
  432 {
  433     *new_data = NULL;
  434     if (flag)
  435         return ISO_XINFO_NO_CLONE;
  436     if (old_data == NULL)
  437         return 0;
  438     /* data is an int disguised as pointer. It does not point to memory. */
  439     *new_data = old_data;
  440     return 0;
  441 }
  442 
  443 
  444 /* Function to identify and manage md5 sums of unspecified providence stored
  445  * directly in this xinfo.
  446  */
  447 int checksum_md5_xinfo_func(void *data, int flag)
  448 {
  449     if (data == NULL)
  450         return 1;
  451     free(data);
  452     return 1;
  453 }
  454 
  455 /* The iso_node_xinfo_cloner function which gets associated to
  456  * checksum_md5_xinfo_func by iso_init() resp. iso_init_with_flag() via
  457  * iso_node_xinfo_make_clonable()
  458  */
  459 int checksum_md5_xinfo_cloner(void *old_data, void **new_data, int flag)
  460 {
  461     *new_data = NULL;
  462     if (flag)
  463         return ISO_XINFO_NO_CLONE;
  464     if (old_data == NULL)
  465         return 0;
  466     *new_data = calloc(1, 16);
  467     if (*new_data == NULL)
  468         return ISO_OUT_OF_MEM;
  469     memcpy(*new_data, old_data, 16);
  470     return 16;
  471 }
  472 
  473 
  474 /* ----------------------------------------------------------------------- */
  475 
  476 /* MD5 checksum image writer */
  477 
  478 /*
  479   @flag bit0= recursion
  480         bit1= session will be appended to an existing image
  481 */
  482 static
  483 int checksum_copy_old_nodes(Ecma119Image *target, IsoNode *node, int flag)
  484 {
  485     IsoNode *pos;
  486     IsoFile *file;
  487     IsoImage *img;
  488     int ret, i;
  489     size_t value_length;
  490     unsigned int idx = 0, old_idx = 0;
  491     char *value = NULL, *md5_pt = NULL;
  492     void *xipt;
  493 
  494     img = target->image;
  495     if (target->checksum_buffer == NULL)
  496         return 0;
  497 
  498     if (node->type == LIBISO_FILE) {
  499         file = (IsoFile *) node;
  500         if (file->from_old_session && target->opts->appendable) {
  501             /* Look for checksums at various places */
  502 
  503             /* Try checksum directly stored with node */
  504             if (md5_pt == NULL) {
  505                 ret = iso_node_get_xinfo(node, checksum_md5_xinfo_func, &xipt);
  506                 if (ret < 0)
  507                     return ret;
  508                 if (ret == 1)
  509                     md5_pt = (char *) xipt;
  510             }
  511 
  512             /* Try checksum index to image checksum buffer */
  513             if (md5_pt == NULL && img->checksum_array != NULL) {
  514                 ret = iso_node_get_xinfo(node, checksum_cx_xinfo_func, &xipt);
  515                 if (ret <= 0)
  516                     return ret;
  517                 /* xipt is an int disguised as void pointer */
  518                 old_idx = 0;
  519                 for (i = 0; i < 4; i++)
  520                     old_idx = (old_idx << 8) | ((unsigned char *) &xipt)[i];
  521     
  522                 if (old_idx == 0 || old_idx > img->checksum_idx_count - 1)
  523                     return 0;
  524                 md5_pt = img->checksum_array + 16 * old_idx;
  525             }
  526 
  527             if (md5_pt == NULL)
  528                 return 0;
  529 
  530             if (!target->opts->will_cancel) {
  531                 ret = iso_node_lookup_attr(node, "isofs.cx", &value_length,
  532                                            &value, 0);
  533                 if (ret == 1 && value_length == 4) {
  534                     for (i = 0; i < 4; i++)
  535                         idx = (idx << 8) | ((unsigned char *) value)[i];
  536                     if (idx > 0 && idx <= target->checksum_idx_counter) {
  537                         memcpy(target->checksum_buffer + 16 * idx, md5_pt, 16);
  538                     }
  539                 }
  540                 if (value != NULL)
  541                     free(value);
  542 
  543                 /* >>> ts B30114 : It is unclear why these are removed here.
  544                                    At least with the opts->will_cancel runs,
  545                                    this is not appropriate.
  546                 */
  547                 iso_node_remove_xinfo(node, checksum_md5_xinfo_func);
  548             }
  549         }
  550     } else if (node->type == LIBISO_DIR) {
  551         for (pos = ((IsoDir *) node)->children; pos != NULL; pos = pos->next) {
  552             ret = checksum_copy_old_nodes(target, pos, 1);
  553             if (ret < 0)
  554                 return ret;
  555         }
  556     }
  557     return ISO_SUCCESS;
  558 }
  559 
  560 
  561 static
  562 int checksum_writer_compute_data_blocks(IsoImageWriter *writer)
  563 {
  564     size_t size;
  565     Ecma119Image *t;
  566     int ret;
  567 
  568     if (writer == NULL) {
  569         return ISO_ASSERT_FAILURE;
  570     }
  571     t = writer->target;
  572 
  573     t->checksum_array_pos = t->curblock;
  574                          /* (t->curblock already contains t->opts->ms_block) */ 
  575     t->checksum_range_start = t->opts->ms_block;
  576     size = (t->checksum_idx_counter + 2) / 128;
  577     if (size * 128 < t->checksum_idx_counter + 2)
  578         size++;
  579     t->curblock += size;
  580     t->checksum_range_size = t->checksum_array_pos + size
  581                              - t->checksum_range_start;
  582 
  583     /* Extra block for stream detectable checksum tag */
  584     t->checksum_tag_pos =  t->curblock;
  585     t->curblock++;
  586 
  587     /* Allocate array of MD5 sums */
  588     t->checksum_buffer = calloc(size, 2048);
  589     if (t->checksum_buffer == NULL)
  590         return ISO_OUT_OF_MEM;
  591 
  592     /* Copy MD5 from nodes of old image into writer->data */
  593     ret = checksum_copy_old_nodes(t, (IsoNode *) t->image->root, 0);
  594     if (ret < 0)
  595         return ret;
  596 
  597     /* Record lba,count,size,cecksum_type in "isofs.ca" of root node */
  598     ret = iso_root_set_isofsca((IsoNode *) t->image->root,
  599                                t->checksum_range_start, 
  600                                t->checksum_array_pos,
  601                                t->checksum_idx_counter + 2, 16, "MD5", 0);
  602     if (ret < 0)
  603         return ret;
  604     return ISO_SUCCESS;
  605 }
  606 
  607 
  608 static
  609 int checksum_writer_write_vol_desc(IsoImageWriter *writer)
  610 {
  611 
  612     /* The superblock checksum tag has to be written after
  613        the Volume Descriptor Set Terminator and thus may not be
  614        written by this function. (It would have been neat, though).
  615     */
  616 
  617     return ISO_SUCCESS;
  618 }
  619 
  620 
  621 static
  622 int checksum_writer_write_data(IsoImageWriter *writer)
  623 {
  624     int wres, res;
  625     size_t i, size;
  626     Ecma119Image *t;
  627     void *ctx = NULL;
  628     char md5[16];
  629 
  630     if (writer == NULL) {
  631         return ISO_ASSERT_FAILURE;
  632     }
  633 
  634     t = writer->target;
  635     iso_msg_debug(t->image->id, "Writing Checksums...");
  636 
  637     /* Write image checksum to index 0 */
  638     if (t->checksum_ctx != NULL) {
  639         res = iso_md5_clone(t->checksum_ctx, &ctx);
  640         if (res > 0) {
  641             res = iso_md5_end(&ctx, t->image_md5);
  642             if (res > 0)
  643                 memcpy(t->checksum_buffer + 0 * 16, t->image_md5, 16);
  644         }
  645     }
  646 
  647     size = (t->checksum_idx_counter + 2) / 128;
  648     if (size * 128 < t->checksum_idx_counter + 2)
  649         size++;
  650  
  651     /* Write checksum of checksum array as index t->checksum_idx_counter + 1 */
  652     res = iso_md5_start(&ctx);
  653     if (res > 0) {
  654         for (i = 0; i < t->checksum_idx_counter + 1; i++)
  655             iso_md5_compute(ctx,
  656                           t->checksum_buffer + ((size_t) i) * (size_t) 16, 16);
  657         res = iso_md5_end(&ctx, md5);
  658         if (res > 0)
  659            memcpy(t->checksum_buffer + (t->checksum_idx_counter + 1) * 16,
  660                   md5, 16);
  661     }
  662 
  663     for (i = 0; i < size; i++) {
  664         wres = iso_write(t, t->checksum_buffer + ((size_t) 2048) * i, 2048);
  665         if (wres < 0) {
  666             res = wres;
  667             goto ex;
  668         }
  669     }
  670     if (t->checksum_ctx == NULL) {
  671         res = ISO_SUCCESS;
  672         goto ex;
  673     }
  674 
  675     /* Write stream detectable checksum tag to extra block */;
  676     res = iso_md5_write_tag(t, 1);
  677     if (res < 0)
  678         goto ex;
  679 
  680     res = ISO_SUCCESS;
  681 ex:;
  682     if (ctx != NULL)
  683         iso_md5_end(&ctx, md5);
  684     return(res);
  685 }
  686 
  687 
  688 static
  689 int checksum_writer_free_data(IsoImageWriter *writer)
  690 {
  691     /* nothing was allocated at writer->data */
  692     return ISO_SUCCESS;
  693 }
  694 
  695 
  696 int checksum_writer_create(Ecma119Image *target)
  697 {
  698     IsoImageWriter *writer;
  699     
  700     writer = malloc(sizeof(IsoImageWriter));
  701     if (writer == NULL) {
  702         return ISO_OUT_OF_MEM;
  703     }
  704     
  705     writer->compute_data_blocks = checksum_writer_compute_data_blocks;
  706     writer->write_vol_desc = checksum_writer_write_vol_desc;
  707     writer->write_data = checksum_writer_write_data;
  708     writer->free_data = checksum_writer_free_data;
  709     writer->data = NULL;
  710     writer->target = target;
  711 
  712     /* add this writer to image */
  713     target->writers[target->nwriters++] = writer;
  714     /* Account for superblock checksum tag */
  715     if (target->opts->md5_session_checksum) {
  716         target->checksum_sb_tag_pos = target->curblock;
  717         target->curblock++;
  718     }
  719     return ISO_SUCCESS;
  720 }
  721 
  722 
  723 static
  724 int iso_md5_write_scdbackup_tag(Ecma119Image *t, char *tag_block, int flag)
  725 {
  726     void *ctx = NULL;
  727     off_t pos = 0, line_start;
  728     int record_len, block_len, ret, i;
  729     char postext[40], md5[16], *record = NULL;
  730 
  731     LIBISO_ALLOC_MEM(record, char, 160);
  732     line_start = strlen(tag_block);
  733     iso_md5_compute(t->checksum_ctx, tag_block, line_start);
  734     ret = iso_md5_clone(t->checksum_ctx, &ctx);
  735     if (ret < 0)
  736         goto ex;
  737     ret = iso_md5_end(&ctx, md5);
  738 
  739     pos = (off_t) t->checksum_tag_pos * (off_t) 2048 + line_start;
  740     if(pos >= 1000000000)
  741         sprintf(postext, "%u%9.9u", (unsigned int) (pos / 1000000000),
  742                                     (unsigned int) (pos % 1000000000));
  743     else
  744         sprintf(postext, "%u", (unsigned int) pos);
  745     sprintf(record, "%s %s ", t->opts->scdbackup_tag_parm, postext);
  746     record_len = strlen(record);
  747     for (i = 0; i < 16; i++)
  748          sprintf(record + record_len + 2 * i,
  749                  "%2.2x", ((unsigned char *) md5)[i]);
  750     record_len += 32;
  751 
  752     ret = iso_md5_start(&ctx);
  753     if (ret < 0)
  754         goto ex;
  755     iso_md5_compute(ctx, record, record_len);
  756     iso_md5_end(&ctx, md5);
  757 
  758     sprintf(tag_block + line_start, "scdbackup_checksum_tag_v0.1 %s %d %s ",
  759             postext, record_len, record);
  760     block_len = strlen(tag_block);
  761     for (i = 0; i < 16; i++)
  762         sprintf(tag_block + block_len + 2 * i,
  763                 "%2.2x", ((unsigned char *) md5)[i]);
  764     block_len+= 32;
  765     tag_block[block_len++]= '\n';
  766 
  767     if (t->opts->scdbackup_tag_written != NULL)
  768         strncpy(t->opts->scdbackup_tag_written, tag_block + line_start,
  769                 block_len - line_start);
  770     ret = ISO_SUCCESS;
  771 ex:;
  772     if (ctx != NULL)
  773         iso_md5_end(&ctx, md5);
  774     LIBISO_FREE_MEM(record);
  775     return ret;
  776 }
  777 
  778 
  779 /* Write stream detectable checksum tag to extra block.
  780  * @flag bit0-7= tag type
  781  *               1= session tag (End checksumming.)
  782  *               2= superblock tag (System Area and Volume Descriptors)
  783  *               3= tree tag (ECMA-119 and Rock Ridge tree)
  784  *               4= relocated superblock tag (at LBA 0 of overwritable media)
  785  *                  Write to target->opts_overwrite rather than to iso_write().
  786  */
  787 int iso_md5_write_tag(Ecma119Image *t, int flag)
  788 {
  789     int ret, mode, l, i, wres, tag_id_len;
  790     void *ctx = NULL;
  791     char md5[16], *tag_block = NULL, *tag_id;
  792     uint32_t size = 0, pos = 0, start;
  793 
  794     LIBISO_ALLOC_MEM(tag_block, char, 2048);
  795     start = t->checksum_range_start;
  796     mode = flag & 255;
  797     if (mode < 1 || mode > 4)
  798         {ret = ISO_WRONG_ARG_VALUE; goto ex;}
  799     ret = iso_md5_clone(t->checksum_ctx, &ctx);
  800     if (ret < 0)
  801         goto ex;
  802     ret = iso_md5_end(&ctx, md5);
  803     if (mode == 1) {
  804         size = t->checksum_range_size;
  805         pos = t->checksum_tag_pos;
  806     } else {
  807         if (mode == 2) {
  808             pos = t->checksum_sb_tag_pos;
  809         } else if (mode == 3) {
  810             pos = t->checksum_tree_tag_pos;
  811         } else if (mode == 4) {
  812             pos = t->checksum_rlsb_tag_pos;
  813             start = pos - (pos % 32);
  814         }
  815         size = pos - start;
  816     }
  817     if (ret < 0)
  818         goto ex;
  819 
  820     iso_util_tag_magic(mode, &tag_id, &tag_id_len, 0);
  821     sprintf(tag_block, "%s pos=%u range_start=%u range_size=%u",
  822             tag_id, pos, start, size);
  823 
  824     l = strlen(tag_block);
  825     if (mode == 2) {
  826         sprintf(tag_block + l, " next=%u", t->checksum_tree_tag_pos);
  827     } else if (mode == 3) {
  828         sprintf(tag_block + l, " next=%u", t->checksum_tag_pos);
  829     } else if (mode == 4) {
  830         sprintf(tag_block + l, " session_start=%u", t->opts->ms_block);
  831     }
  832     strcat(tag_block + l, " md5=");
  833     l = strlen(tag_block);
  834     for (i = 0; i < 16; i++)
  835         sprintf(tag_block + l + 2 * i, "%2.2x",
  836                 ((unsigned char *) md5)[i]);
  837     l+= 32;
  838         
  839     ret = iso_md5_start(&ctx);
  840     if (ret > 0) {
  841         iso_md5_compute(ctx, tag_block, l);
  842         iso_md5_end(&ctx, md5);
  843         strcpy(tag_block + l, " self=");
  844         l += 6;
  845         for (i = 0; i < 16; i++)
  846             sprintf(tag_block + l + 2 * i, "%2.2x",
  847                     ((unsigned char *) md5)[i]);
  848     }
  849     tag_block[l + 32] = '\n';
  850 
  851     if (mode == 1 && t->opts->scdbackup_tag_parm[0]) {
  852         if (t->opts->ms_block > 0) {
  853             iso_msg_submit(t->image->id, ISO_SCDBACKUP_TAG_NOT_0, 0, NULL);
  854         } else {
  855             ret = iso_md5_write_scdbackup_tag(t, tag_block, 0);
  856             if (ret < 0)
  857                 goto ex;
  858         }
  859     }
  860 
  861     if (mode == 4) {
  862         if (t->opts_overwrite != NULL)
  863             memcpy(t->opts_overwrite + pos * 2048, tag_block, 2048);
  864     } else {
  865         wres = iso_write(t, tag_block, 2048);
  866         if (wres < 0) {
  867             ret = wres;
  868             goto ex;
  869         }
  870     }
  871 
  872     ret = ISO_SUCCESS;
  873 ex:;
  874     if (ctx != NULL)
  875         iso_md5_end(&ctx, md5);
  876     LIBISO_FREE_MEM(tag_block);
  877     return ret;
  878 }
  879 
  880