XMMS2

src/xmms/bindata.c

Go to the documentation of this file.
00001 /*  XMMS2 - X Music Multiplexer System
00002  *  Copyright (C) 2003-2009 XMMS2 Team
00003  *
00004  *  PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!!
00005  *
00006  *  This library is free software; you can redistribute it and/or
00007  *  modify it under the terms of the GNU Lesser General Public
00008  *  License as published by the Free Software Foundation; either
00009  *  version 2.1 of the License, or (at your option) any later version.
00010  *
00011  *  This library is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  *  Lesser General Public License for more details.
00015  */
00016 
00017 #include <glib.h>
00018 #include <string.h>
00019 #include <stdio.h>
00020 #include <stdlib.h>
00021 #include <unistd.h>
00022 #include <sys/time.h>
00023 #include <errno.h>
00024 
00025 #include "xmmsc/xmmsc_idnumbers.h"
00026 #include "xmmsc/xmmsc_ipc_transport.h"
00027 #include "xmmsc/xmmsc_ipc_msg.h"
00028 
00029 #include "xmms/xmms_log.h"
00030 
00031 #include "xmms/xmms_bindata.h"
00032 
00033 #include "xmmspriv/xmms_ringbuf.h"
00034 #include "xmmspriv/xmms_ipc.h"
00035 #include "xmmspriv/xmms_playlist.h"
00036 #include "xmmspriv/xmms_config.h"
00037 #include "xmmspriv/xmms_bindata.h"
00038 #include "xmmspriv/xmms_utils.h"
00039 
00040 struct xmms_bindata_St {
00041     xmms_object_t obj;
00042     const gchar *bindir;
00043 };
00044 
00045 static xmms_bindata_t *global_bindata;
00046 
00047 static void xmms_bindata_destroy (xmms_object_t *obj);
00048 
00049 typedef unsigned char md5_byte_t; /* 8-bit byte */
00050 typedef unsigned int md5_word_t; /* 32-bit word */
00051 
00052 /* Define the state of the MD5 Algorithm. */
00053 typedef struct md5_state_s {
00054     md5_word_t count[2]; /* message length in bits, lsw first */
00055     md5_word_t abcd[4];  /* digest buffer */
00056     md5_byte_t buf[64];  /* accumulate block */
00057 } md5_state_t;
00058 
00059 /* Initialize the algorithm. */
00060 static void md5_init (md5_state_t *pms);
00061 static void md5_append (md5_state_t *pms, const md5_byte_t *data, int nbytes);
00062 static void md5_finish (md5_state_t *pms, md5_byte_t digest[16]);
00063 
00064 static gchar *xmms_bindata_build_path (xmms_bindata_t *bindata, const gchar *hash);
00065 
00066 static gchar *xmms_bindata_client_add (xmms_bindata_t *bindata, GString *data, xmms_error_t *err);
00067 static xmmsv_t *xmms_bindata_client_retrieve (xmms_bindata_t *bindata, const gchar *hash, xmms_error_t *err);
00068 static void xmms_bindata_client_remove (xmms_bindata_t *bindata, const gchar *hash, xmms_error_t *);
00069 static GList *xmms_bindata_client_list (xmms_bindata_t *bindata, xmms_error_t *err);
00070 static gboolean _xmms_bindata_add (xmms_bindata_t *bindata, const guchar *data, gsize len, gchar hash[33], xmms_error_t *err);
00071 
00072 XMMS_CMD_DEFINE (get_data, xmms_bindata_client_retrieve, xmms_bindata_t *, BIN, STRING, NONE);
00073 XMMS_CMD_DEFINE (add_data, xmms_bindata_client_add, xmms_bindata_t *, STRING, BIN, NONE);
00074 XMMS_CMD_DEFINE (remove_data, xmms_bindata_client_remove, xmms_bindata_t *, NONE, STRING, NONE);
00075 XMMS_CMD_DEFINE (list_data, xmms_bindata_client_list, xmms_bindata_t *, LIST, NONE, NONE);
00076 
00077 xmms_bindata_t *
00078 xmms_bindata_init ()
00079 {
00080     gchar *tmp;
00081     xmms_bindata_t *obj;
00082     xmms_config_property_t *cv;
00083 
00084     obj = xmms_object_new (xmms_bindata_t, xmms_bindata_destroy);
00085 
00086     xmms_object_cmd_add (XMMS_OBJECT (obj),
00087                          XMMS_IPC_CMD_ADD_DATA,
00088                          XMMS_CMD_FUNC (add_data));
00089 
00090     xmms_object_cmd_add (XMMS_OBJECT (obj),
00091                          XMMS_IPC_CMD_REMOVE_DATA,
00092                          XMMS_CMD_FUNC (remove_data));
00093 
00094     xmms_object_cmd_add (XMMS_OBJECT (obj),
00095                          XMMS_IPC_CMD_GET_DATA,
00096                          XMMS_CMD_FUNC (get_data));
00097 
00098     xmms_object_cmd_add (XMMS_OBJECT (obj),
00099                          XMMS_IPC_CMD_LIST_DATA,
00100                          XMMS_CMD_FUNC (list_data));
00101 
00102     xmms_ipc_object_register (XMMS_IPC_OBJECT_BINDATA, XMMS_OBJECT (obj));
00103 
00104     tmp = XMMS_BUILD_PATH ("bindata");
00105     cv = xmms_config_property_register ("bindata.path", tmp, NULL, NULL);
00106     g_free (tmp);
00107 
00108     obj->bindir = xmms_config_property_get_string (cv);
00109 
00110     if (!g_file_test (obj->bindir, G_FILE_TEST_IS_DIR)) {
00111         if (g_mkdir_with_parents (obj->bindir, 0755) == -1) {
00112             xmms_log_error ("Couldn't create bindir %s", obj->bindir);
00113         }
00114     }
00115 
00116     global_bindata = obj;
00117 
00118     return obj;
00119 }
00120 
00121 static void
00122 xmms_bindata_destroy (xmms_object_t *obj)
00123 {
00124     xmms_ipc_object_unregister (XMMS_IPC_OBJECT_BINDATA);
00125 }
00126 
00127 gchar *
00128 xmms_bindata_calculate_md5 (const guchar *data, gsize size, gchar ret[33])
00129 {
00130     md5_state_t state;
00131     md5_byte_t digest[16];
00132     int di;
00133     static gchar hex[] = {
00134         '0', '1', '2', '3', '4', '5', '6', '7',
00135         '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
00136     };
00137 
00138     md5_init (&state);
00139     md5_append (&state, (const md5_byte_t *)data, size);
00140     md5_finish (&state, digest);
00141 
00142     for (di = 0; di < 16; ++di) {
00143         ret[di * 2] = hex[digest[di] >> 4];
00144         ret[di * 2 + 1] = hex[digest[di] & 0x0f];
00145     }
00146     ret[32] = 0;
00147     return ret;
00148 }
00149 
00150 static gchar *
00151 xmms_bindata_build_path (xmms_bindata_t *bindata, const gchar *hash)
00152 {
00153     return g_build_path (G_DIR_SEPARATOR_S, bindata->bindir, hash, NULL);
00154 }
00155 
00156 /** Add binary data from a plugin */
00157 gboolean
00158 xmms_bindata_plugin_add (const guchar *data, gsize size, gchar hash[33])
00159 {
00160     xmms_error_t err;
00161     return _xmms_bindata_add (global_bindata, data, size, hash, &err);
00162 }
00163 
00164 static gboolean
00165 _xmms_bindata_add (xmms_bindata_t *bindata, const guchar *data, gsize len, gchar hash[33], xmms_error_t *err)
00166 {
00167     const guchar *ptr;
00168     gsize left;
00169     gchar *path;
00170     FILE *fp;
00171 
00172     xmms_bindata_calculate_md5 (data, len, hash);
00173 
00174     path = xmms_bindata_build_path (bindata, hash);
00175 
00176     if (g_file_test (path, G_FILE_TEST_IS_REGULAR)) {
00177         XMMS_DBG ("file %s is already in bindata dir", hash);
00178         g_free (path);
00179         return TRUE;
00180     }
00181 
00182     XMMS_DBG ("Creating %s", path);
00183     fp = fopen (path, "wb");
00184     if (!fp) {
00185         xmms_log_error ("Couldn't create %s", path);
00186         xmms_error_set (err, XMMS_ERROR_GENERIC, "Couldn't create file on server!");
00187         g_free (path);
00188         return FALSE;
00189     }
00190 
00191     /* write the data to the file */
00192     ptr = data;
00193     left = len;
00194 
00195     while (left > 0) {
00196         size_t w;
00197 
00198         w = fwrite (ptr, 1, left, fp);
00199         if (!w && ferror (fp)) {
00200             fclose (fp);
00201             unlink (path);
00202 
00203             xmms_log_error ("Couldn't write data");
00204             xmms_error_set (err, XMMS_ERROR_GENERIC,
00205                             "Couldn't write data!");
00206             g_free (path);
00207             return FALSE;
00208         }
00209 
00210         left -= w;
00211         ptr += w;
00212     }
00213 
00214     fclose (fp);
00215     g_free (path);
00216 
00217     return TRUE;
00218 }
00219 
00220 char *
00221 xmms_bindata_client_add (xmms_bindata_t *bindata, GString *data, xmms_error_t *err)
00222 {
00223     gchar hash[33];
00224     if (_xmms_bindata_add (bindata, (guchar *)data->str, data->len, hash, err))
00225         return g_strdup (hash);
00226     return NULL;
00227 }
00228 
00229 static xmmsv_t *
00230 xmms_bindata_client_retrieve (xmms_bindata_t *bindata, const gchar *hash,
00231                               xmms_error_t *err)
00232 {
00233     xmmsv_t *res;
00234     gchar *path;
00235     GString *str;
00236     FILE *fp;
00237 
00238     path = xmms_bindata_build_path (bindata, hash);
00239 
00240     fp = fopen (path, "rb");
00241     if (!fp) {
00242         xmms_log_error ("Requesting '%s' which is not on the server", hash);
00243         xmms_error_set (err, XMMS_ERROR_NOENT, "File not found!");
00244         g_free (path);
00245         return NULL;
00246     }
00247 
00248     g_free (path);
00249 
00250     str = g_string_new (NULL);
00251     while (!feof (fp)) {
00252         gchar buf[1024];
00253         gint l;
00254 
00255         l = fread (buf, 1, 1024, fp);
00256         if (ferror (fp)) {
00257             g_string_free (str, TRUE);
00258             xmms_log_error ("Error reading bindata '%s'", hash);
00259             xmms_error_set (err, XMMS_ERROR_GENERIC, "Error reading file");
00260             fclose (fp);
00261             return NULL;
00262         }
00263         g_string_append_len (str, buf, l);
00264     }
00265 
00266     fclose (fp);
00267 
00268     res = xmmsv_new_bin ((unsigned char *)str->str, str->len);
00269 
00270     g_string_free (str, TRUE);
00271 
00272     return res;
00273 }
00274 
00275 static void
00276 xmms_bindata_client_remove (xmms_bindata_t *bindata, const gchar *hash,
00277                             xmms_error_t *err)
00278 {
00279     gchar *path;
00280     path = xmms_bindata_build_path (bindata, hash);
00281     if (unlink (path) == -1) {
00282         xmms_error_set (err, XMMS_ERROR_GENERIC, "Couldn't remove file");
00283     }
00284     g_free (path);
00285     return;
00286 }
00287 
00288 static GList *
00289 xmms_bindata_client_list (xmms_bindata_t *bindata, xmms_error_t *err)
00290 {
00291     GList *entries = NULL;
00292     gchar *path;
00293     const gchar *file;
00294     GDir *dir;
00295 
00296     path = xmms_bindata_build_path (bindata, NULL);
00297     dir = g_dir_open (path, 0, NULL);
00298     g_free (path);
00299 
00300     if (!dir) {
00301         xmms_error_set (err, XMMS_ERROR_GENERIC,
00302                         "Couldn't open bindata directory");
00303         return NULL;
00304     }
00305 
00306     while ((file = g_dir_read_name (dir))) {
00307         entries = g_list_prepend (entries, xmmsv_new_string (file));
00308     }
00309 
00310     g_dir_close (dir);
00311 
00312     return entries;
00313 }
00314 
00315 /*
00316   Copyright (C) 1999, 2000, 2002 Aladdin Enterprises.  All rights reserved.
00317 
00318   This software is provided 'as-is', without any express or implied
00319   warranty.  In no event will the authors be held liable for any damages
00320   arising from the use of this software.
00321 
00322   Permission is granted to anyone to use this software for any purpose,
00323   including commercial applications, and to alter it and redistribute it
00324   freely, subject to the following restrictions:
00325 
00326   1. The origin of this software must not be misrepresented; you must not
00327      claim that you wrote the original software. If you use this software
00328      in a product, an acknowledgment in the product documentation would be
00329      appreciated but is not required.
00330   2. Altered source versions must be plainly marked as such, and must not be
00331      misrepresented as being the original software.
00332   3. This notice may not be removed or altered from any source distribution.
00333 
00334   L. Peter Deutsch
00335   ghost@aladdin.com
00336 
00337  */
00338 /* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */
00339 /*
00340   Independent implementation of MD5 (RFC 1321).
00341 
00342   This code implements the MD5 Algorithm defined in RFC 1321, whose
00343   text is available at
00344     http://www.ietf.org/rfc/rfc1321.txt
00345   The code is derived from the text of the RFC, including the test suite
00346   (section A.5) but excluding the rest of Appendix A.  It does not include
00347   any code or documentation that is identified in the RFC as being
00348   copyrighted.
00349 
00350   The original and principal author of md5.c is L. Peter Deutsch
00351   <ghost@aladdin.com>.  Other authors are noted in the change history
00352   that follows (in reverse chronological order):
00353 
00354   2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
00355     either statically or dynamically; added missing #include <string.h>
00356     in library.
00357   2002-03-11 lpd Corrected argument list for main(), and added int return
00358     type, in test program and T value program.
00359   2002-02-21 lpd Added missing #include <stdio.h> in test program.
00360   2000-07-03 lpd Patched to eliminate warnings about "constant is
00361     unsigned in ANSI C, signed in traditional"; made test program
00362     self-checking.
00363   1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
00364   1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
00365   1999-05-03 lpd Original version.
00366  */
00367 
00368 /*
00369  * This package supports both compile-time and run-time determination of CPU
00370  * byte order.  If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be
00371  * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is
00372  * defined as non-zero, the code will be compiled to run only on big-endian
00373  * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to
00374  * run on either big- or little-endian CPUs, but will run slightly less
00375  * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined.
00376  */
00377 
00378 #undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
00379 #ifdef ARCH_IS_BIG_ENDIAN
00380 #  define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
00381 #else
00382 #  define BYTE_ORDER 0
00383 #endif
00384 
00385 #define T_MASK ((md5_word_t)~0)
00386 #define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87)
00387 #define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9)
00388 #define T3    0x242070db
00389 #define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111)
00390 #define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050)
00391 #define T6    0x4787c62a
00392 #define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec)
00393 #define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe)
00394 #define T9    0x698098d8
00395 #define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850)
00396 #define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e)
00397 #define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841)
00398 #define T13    0x6b901122
00399 #define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c)
00400 #define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71)
00401 #define T16    0x49b40821
00402 #define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d)
00403 #define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf)
00404 #define T19    0x265e5a51
00405 #define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855)
00406 #define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2)
00407 #define T22    0x02441453
00408 #define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e)
00409 #define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437)
00410 #define T25    0x21e1cde6
00411 #define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829)
00412 #define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278)
00413 #define T28    0x455a14ed
00414 #define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa)
00415 #define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07)
00416 #define T31    0x676f02d9
00417 #define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375)
00418 #define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd)
00419 #define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e)
00420 #define T35    0x6d9d6122
00421 #define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3)
00422 #define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb)
00423 #define T38    0x4bdecfa9
00424 #define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f)
00425 #define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f)
00426 #define T41    0x289b7ec6
00427 #define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805)
00428 #define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a)
00429 #define T44    0x04881d05
00430 #define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6)
00431 #define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a)
00432 #define T47    0x1fa27cf8
00433 #define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a)
00434 #define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb)
00435 #define T50    0x432aff97
00436 #define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58)
00437 #define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6)
00438 #define T53    0x655b59c3
00439 #define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d)
00440 #define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82)
00441 #define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e)
00442 #define T57    0x6fa87e4f
00443 #define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f)
00444 #define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb)
00445 #define T60    0x4e0811a1
00446 #define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d)
00447 #define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca)
00448 #define T63    0x2ad7d2bb
00449 #define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e)
00450 
00451 
00452 static void
00453 md5_process (md5_state_t *pms, const md5_byte_t *data /*[64]*/)
00454 {
00455     md5_word_t
00456     a = pms->abcd[0], b = pms->abcd[1],
00457     c = pms->abcd[2], d = pms->abcd[3];
00458     md5_word_t t;
00459 #if BYTE_ORDER > 0
00460     /* Define storage only for big-endian CPUs. */
00461     md5_word_t X[16];
00462 #else
00463     /* Define storage for little-endian or both types of CPUs. */
00464     md5_word_t xbuf[16];
00465     const md5_word_t *X;
00466 #endif
00467 
00468     {
00469 #if BYTE_ORDER == 0
00470     /*
00471      * Determine dynamically whether this is a big-endian or
00472      * little-endian machine, since we can use a more efficient
00473      * algorithm on the latter.
00474      */
00475     static const int w = 1;
00476 
00477     if (*((const md5_byte_t *)&w)) /* dynamic little-endian */
00478 #endif
00479 #if BYTE_ORDER <= 0 /* little-endian */
00480     {
00481         /*
00482          * On little-endian machines, we can process properly aligned
00483          * data without copying it.
00484          */
00485         if (!((data - (const md5_byte_t *)0) & 3)) {
00486             /* data are properly aligned */
00487             X = (const md5_word_t *)data;
00488         } else {
00489             /* not aligned */
00490             memcpy (xbuf, data, 64);
00491             X = xbuf;
00492         }
00493     }
00494 #endif
00495 #if BYTE_ORDER == 0
00496     else /* dynamic big-endian */
00497 #endif
00498 #if BYTE_ORDER >= 0 /* big-endian */
00499     {
00500         /*
00501          * On big-endian machines, we must arrange the bytes in the
00502          * right order.
00503          */
00504         const md5_byte_t *xp = data;
00505         int i;
00506 
00507 #  if BYTE_ORDER == 0
00508         X = xbuf;/* (dynamic only) */
00509 #  else
00510 #    define xbuf X /* (static only) */
00511 #  endif
00512         for (i = 0; i < 16; ++i, xp += 4)
00513         xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);
00514     }
00515 #endif
00516     }
00517 
00518 #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
00519 
00520     /* Round 1. */
00521     /* Let [abcd k s i] denote the operation
00522        a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */
00523 #define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
00524 #define SET(a, b, c, d, k, s, Ti)\
00525   t = a + F (b,c,d) + X[k] + Ti;\
00526   a = ROTATE_LEFT (t, s) + b
00527     /* Do the following 16 operations. */
00528     SET (a, b, c, d,  0,  7,  T1);
00529     SET (d, a, b, c,  1, 12,  T2);
00530     SET (c, d, a, b,  2, 17,  T3);
00531     SET (b, c, d, a,  3, 22,  T4);
00532     SET (a, b, c, d,  4,  7,  T5);
00533     SET (d, a, b, c,  5, 12,  T6);
00534     SET (c, d, a, b,  6, 17,  T7);
00535     SET (b, c, d, a,  7, 22,  T8);
00536     SET (a, b, c, d,  8,  7,  T9);
00537     SET (d, a, b, c,  9, 12, T10);
00538     SET (c, d, a, b, 10, 17, T11);
00539     SET (b, c, d, a, 11, 22, T12);
00540     SET (a, b, c, d, 12,  7, T13);
00541     SET (d, a, b, c, 13, 12, T14);
00542     SET (c, d, a, b, 14, 17, T15);
00543     SET (b, c, d, a, 15, 22, T16);
00544 #undef SET
00545 
00546     /* Round 2. */
00547     /* Let [abcd k s i] denote the operation
00548        a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
00549 #define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))
00550 #define SET(a, b, c, d, k, s, Ti)\
00551   t = a + G (b,c,d) + X[k] + Ti;\
00552   a = ROTATE_LEFT (t, s) + b
00553      /* Do the following 16 operations. */
00554     SET (a, b, c, d,  1,  5, T17);
00555     SET (d, a, b, c,  6,  9, T18);
00556     SET (c, d, a, b, 11, 14, T19);
00557     SET (b, c, d, a,  0, 20, T20);
00558     SET (a, b, c, d,  5,  5, T21);
00559     SET (d, a, b, c, 10,  9, T22);
00560     SET (c, d, a, b, 15, 14, T23);
00561     SET (b, c, d, a,  4, 20, T24);
00562     SET (a, b, c, d,  9,  5, T25);
00563     SET (d, a, b, c, 14,  9, T26);
00564     SET (c, d, a, b,  3, 14, T27);
00565     SET (b, c, d, a,  8, 20, T28);
00566     SET (a, b, c, d, 13,  5, T29);
00567     SET (d, a, b, c,  2,  9, T30);
00568     SET (c, d, a, b,  7, 14, T31);
00569     SET (b, c, d, a, 12, 20, T32);
00570 #undef SET
00571 
00572     /* Round 3. */
00573     /* Let [abcd k s t] denote the operation
00574        a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
00575 #define H(x, y, z) ((x) ^ (y) ^ (z))
00576 #define SET(a, b, c, d, k, s, Ti)\
00577   t = a + H (b,c,d) + X[k] + Ti;\
00578   a = ROTATE_LEFT (t, s) + b
00579      /* Do the following 16 operations. */
00580     SET (a, b, c, d,  5,  4, T33);
00581     SET (d, a, b, c,  8, 11, T34);
00582     SET (c, d, a, b, 11, 16, T35);
00583     SET (b, c, d, a, 14, 23, T36);
00584     SET (a, b, c, d,  1,  4, T37);
00585     SET (d, a, b, c,  4, 11, T38);
00586     SET (c, d, a, b,  7, 16, T39);
00587     SET (b, c, d, a, 10, 23, T40);
00588     SET (a, b, c, d, 13,  4, T41);
00589     SET (d, a, b, c,  0, 11, T42);
00590     SET (c, d, a, b,  3, 16, T43);
00591     SET (b, c, d, a,  6, 23, T44);
00592     SET (a, b, c, d,  9,  4, T45);
00593     SET (d, a, b, c, 12, 11, T46);
00594     SET (c, d, a, b, 15, 16, T47);
00595     SET (b, c, d, a,  2, 23, T48);
00596 #undef SET
00597 
00598     /* Round 4. */
00599     /* Let [abcd k s t] denote the operation
00600        a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
00601 #define I(x, y, z) ((y) ^ ((x) | ~(z)))
00602 #define SET(a, b, c, d, k, s, Ti)\
00603   t = a + I (b,c,d) + X[k] + Ti;\
00604   a = ROTATE_LEFT (t, s) + b
00605      /* Do the following 16 operations. */
00606     SET (a, b, c, d,  0,  6, T49);
00607     SET (d, a, b, c,  7, 10, T50);
00608     SET (c, d, a, b, 14, 15, T51);
00609     SET (b, c, d, a,  5, 21, T52);
00610     SET (a, b, c, d, 12,  6, T53);
00611     SET (d, a, b, c,  3, 10, T54);
00612     SET (c, d, a, b, 10, 15, T55);
00613     SET (b, c, d, a,  1, 21, T56);
00614     SET (a, b, c, d,  8,  6, T57);
00615     SET (d, a, b, c, 15, 10, T58);
00616     SET (c, d, a, b,  6, 15, T59);
00617     SET (b, c, d, a, 13, 21, T60);
00618     SET (a, b, c, d,  4,  6, T61);
00619     SET (d, a, b, c, 11, 10, T62);
00620     SET (c, d, a, b,  2, 15, T63);
00621     SET (b, c, d, a,  9, 21, T64);
00622 #undef SET
00623 
00624     /* Then perform the following additions. (That is increment each
00625         of the four registers by the value it had before this block
00626         was started.) */
00627     pms->abcd[0] += a;
00628     pms->abcd[1] += b;
00629     pms->abcd[2] += c;
00630     pms->abcd[3] += d;
00631 }
00632 
00633 static void
00634 md5_init (md5_state_t *pms)
00635 {
00636     pms->count[0] = pms->count[1] = 0;
00637     pms->abcd[0] = 0x67452301;
00638     pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476;
00639     pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301;
00640     pms->abcd[3] = 0x10325476;
00641 }
00642 
00643 static void
00644 md5_append (md5_state_t *pms, const md5_byte_t *data, int nbytes)
00645 {
00646     const md5_byte_t *p = data;
00647     int left = nbytes;
00648     int offset = (pms->count[0] >> 3) & 63;
00649     md5_word_t nbits = (md5_word_t)(nbytes << 3);
00650 
00651     if (nbytes <= 0)
00652         return;
00653 
00654     /* Update the message length. */
00655     pms->count[1] += nbytes >> 29;
00656     pms->count[0] += nbits;
00657     if (pms->count[0] < nbits)
00658         pms->count[1]++;
00659 
00660     /* Process an initial partial block. */
00661     if (offset) {
00662         int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);
00663 
00664         memcpy (pms->buf + offset, p, copy);
00665         if (offset + copy < 64)
00666             return;
00667         p += copy;
00668         left -= copy;
00669         md5_process (pms, pms->buf);
00670     }
00671 
00672     /* Process full blocks. */
00673     for (; left >= 64; p += 64, left -= 64)
00674         md5_process (pms, p);
00675 
00676     /* Process a final partial block. */
00677     if (left)
00678         memcpy (pms->buf, p, left);
00679 }
00680 
00681 static void
00682 md5_finish (md5_state_t *pms, md5_byte_t digest[16])
00683 {
00684     static const md5_byte_t pad[64] = {
00685         0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00686         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00687         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00688         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
00689     };
00690     md5_byte_t data[8];
00691     int i;
00692 
00693     /* Save the length before padding. */
00694     for (i = 0; i < 8; ++i)
00695         data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));
00696     /* Pad to 56 bytes mod 64. */
00697     md5_append (pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);
00698     /* Append the length. */
00699     md5_append (pms, data, 8);
00700     for (i = 0; i < 16; ++i)
00701         digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));
00702 }