dbus-sha.c

00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
00002 /* dbus-sha.c SHA-1 implementation
00003  *
00004  * Copyright (C) 2003 Red Hat Inc.
00005  * Copyright (C) 1995 A. M. Kuchling
00006  *
00007  * Licensed under the Academic Free License version 2.1
00008  *
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022  *
00023  */
00024 
00025 #include "dbus-internals.h"
00026 #include "dbus-sha.h"
00027 #include "dbus-marshal-basic.h" /* for byteswap routines */
00028 #include <string.h>
00029 
00030 /* The following comments have the history of where this code
00031  * comes from. I actually copied it from GNet in GNOME CVS.
00032  * - hp@redhat.com
00033  */
00034 
00035 /*
00036  *  sha.h : Implementation of the Secure Hash Algorithm
00037  *
00038  * Part of the Python Cryptography Toolkit, version 1.0.0
00039  *
00040  * Copyright (C) 1995, A.M. Kuchling
00041  *
00042  * Distribute and use freely; there are no restrictions on further
00043  * dissemination and usage except those imposed by the laws of your
00044  * country of residence.
00045  *
00046  */
00047 
00048 /* SHA: NIST's Secure Hash Algorithm */
00049 
00050 /* Based on SHA code originally posted to sci.crypt by Peter Gutmann
00051    in message <30ajo5$oe8@ccu2.auckland.ac.nz>.
00052    Modified to test for endianness on creation of SHA objects by AMK.
00053    Also, the original specification of SHA was found to have a weakness
00054    by NSA/NIST.  This code implements the fixed version of SHA.
00055 */
00056 
00057 /* Here's the first paragraph of Peter Gutmann's posting:
00058 
00059 The following is my SHA (FIPS 180) code updated to allow use of the "fixed"
00060 SHA, thanks to Jim Gillogly and an anonymous contributor for the information on
00061 what's changed in the new version.  The fix is a simple change which involves
00062 adding a single rotate in the initial expansion function.  It is unknown
00063 whether this is an optimal solution to the problem which was discovered in the
00064 SHA or whether it's simply a bandaid which fixes the problem with a minimum of
00065 effort (for example the reengineering of a great many Capstone chips).
00066 */
00067 
00087 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00088 
00089 /* The SHA block size and message digest sizes, in bytes */
00090 
00091 #define SHA_DATASIZE    64
00092 #define SHA_DIGESTSIZE  20
00093 
00094 /* The SHA f()-functions.  The f1 and f3 functions can be optimized to
00095    save one boolean operation each - thanks to Rich Schroeppel,
00096    rcs@cs.arizona.edu for discovering this */
00097 
00098 /*#define f1(x,y,z) ( ( x & y ) | ( ~x & z ) )          // Rounds  0-19 */
00099 #define f1(x,y,z)  ( z ^ ( x & ( y ^ z ) ) )           /* Rounds  0-19 */
00100 #define f2(x,y,z)  ( x ^ y ^ z )                       /* Rounds 20-39 */
00101 /*#define f3(x,y,z) ( ( x & y ) | ( x & z ) | ( y & z ) )   // Rounds 40-59 */
00102 #define f3(x,y,z)  ( ( x & y ) | ( z & ( x | y ) ) )   /* Rounds 40-59 */
00103 #define f4(x,y,z)  ( x ^ y ^ z )                       /* Rounds 60-79 */
00104 
00105 /* The SHA Mysterious Constants */
00106 
00107 #define K1  0x5A827999L                                 /* Rounds  0-19 */
00108 #define K2  0x6ED9EBA1L                                 /* Rounds 20-39 */
00109 #define K3  0x8F1BBCDCL                                 /* Rounds 40-59 */
00110 #define K4  0xCA62C1D6L                                 /* Rounds 60-79 */
00111 
00112 /* SHA initial values */
00113 
00114 #define h0init  0x67452301L
00115 #define h1init  0xEFCDAB89L
00116 #define h2init  0x98BADCFEL
00117 #define h3init  0x10325476L
00118 #define h4init  0xC3D2E1F0L
00119 
00120 /* Note that it may be necessary to add parentheses to these macros if they
00121    are to be called with expressions as arguments */
00122 /* 32-bit rotate left - kludged with shifts */
00123 
00124 #define ROTL(n,X) ( ( ( X ) << n ) | ( ( X ) >> ( 32 - n ) ) )
00125 
00126 /* The initial expanding function.  The hash function is defined over an
00127    80-word expanded input array W, where the first 16 are copies of the input
00128    data, and the remaining 64 are defined by
00129 
00130         W[ i ] = W[ i - 16 ] ^ W[ i - 14 ] ^ W[ i - 8 ] ^ W[ i - 3 ]
00131 
00132    This implementation generates these values on the fly in a circular
00133    buffer - thanks to Colin Plumb, colin@nyx10.cs.du.edu for this
00134    optimization.
00135 
00136    The updated SHA changes the expanding function by adding a rotate of 1
00137    bit.  Thanks to Jim Gillogly, jim@rand.org, and an anonymous contributor
00138    for this information */
00139 
00140 #define expand(W,i) ( W[ i & 15 ] = ROTL( 1, ( W[ i & 15 ] ^ W[ (i - 14) & 15 ] ^ \
00141                                                  W[ (i - 8) & 15 ] ^ W[ (i - 3) & 15 ] ) ) )
00142 
00143 
00144 /* The prototype SHA sub-round.  The fundamental sub-round is:
00145 
00146         a' = e + ROTL( 5, a ) + f( b, c, d ) + k + data;
00147         b' = a;
00148         c' = ROTL( 30, b );
00149         d' = c;
00150         e' = d;
00151 
00152    but this is implemented by unrolling the loop 5 times and renaming the
00153    variables ( e, a, b, c, d ) = ( a', b', c', d', e' ) each iteration.
00154    This code is then replicated 20 times for each of the 4 functions, using
00155    the next 20 values from the W[] array each time */
00156 
00157 #define subRound(a, b, c, d, e, f, k, data) \
00158    ( e += ROTL( 5, a ) + f( b, c, d ) + k + data, b = ROTL( 30, b ) )
00159 
00160 #endif /* !DOXYGEN_SHOULD_SKIP_THIS */
00161 
00162 /* Perform the SHA transformation.  Note that this code, like MD5, seems to
00163    break some optimizing compilers due to the complexity of the expressions
00164    and the size of the basic block.  It may be necessary to split it into
00165    sections, e.g. based on the four subrounds
00166 
00167    Note that this corrupts the context->data area */
00168 
00169 static void
00170 SHATransform(dbus_uint32_t *digest, dbus_uint32_t *data)
00171 {
00172   dbus_uint32_t A, B, C, D, E;     /* Local vars */
00173   dbus_uint32_t eData[16];       /* Expanded data */
00174 
00175   /* Set up first buffer and local data buffer */
00176   A = digest[0];
00177   B = digest[1];
00178   C = digest[2];
00179   D = digest[3];
00180   E = digest[4];
00181   memmove (eData, data, SHA_DATASIZE);
00182 
00183   /* Heavy mangling, in 4 sub-rounds of 20 interations each. */
00184   subRound (A, B, C, D, E, f1, K1, eData[0]);
00185   subRound (E, A, B, C, D, f1, K1, eData[1]);
00186   subRound (D, E, A, B, C, f1, K1, eData[2]);
00187   subRound (C, D, E, A, B, f1, K1, eData[3]);
00188   subRound (B, C, D, E, A, f1, K1, eData[4]);
00189   subRound (A, B, C, D, E, f1, K1, eData[5]);
00190   subRound (E, A, B, C, D, f1, K1, eData[6]);
00191   subRound (D, E, A, B, C, f1, K1, eData[7]);
00192   subRound (C, D, E, A, B, f1, K1, eData[8]);
00193   subRound (B, C, D, E, A, f1, K1, eData[9]);
00194   subRound (A, B, C, D, E, f1, K1, eData[10]);
00195   subRound (E, A, B, C, D, f1, K1, eData[11]);
00196   subRound (D, E, A, B, C, f1, K1, eData[12]);
00197   subRound (C, D, E, A, B, f1, K1, eData[13]);
00198   subRound (B, C, D, E, A, f1, K1, eData[14]);
00199   subRound (A, B, C, D, E, f1, K1, eData[15]);
00200   subRound (E, A, B, C, D, f1, K1, expand ( eData, 16) );
00201   subRound (D, E, A, B, C, f1, K1, expand ( eData, 17) );
00202   subRound (C, D, E, A, B, f1, K1, expand ( eData, 18) );
00203   subRound (B, C, D, E, A, f1, K1, expand ( eData, 19) );
00204 
00205   subRound (A, B, C, D, E, f2, K2, expand ( eData, 20) );
00206   subRound (E, A, B, C, D, f2, K2, expand ( eData, 21) );
00207   subRound (D, E, A, B, C, f2, K2, expand ( eData, 22) );
00208   subRound (C, D, E, A, B, f2, K2, expand ( eData, 23) );
00209   subRound (B, C, D, E, A, f2, K2, expand ( eData, 24) );
00210   subRound (A, B, C, D, E, f2, K2, expand ( eData, 25) );
00211   subRound (E, A, B, C, D, f2, K2, expand ( eData, 26) );
00212   subRound (D, E, A, B, C, f2, K2, expand ( eData, 27) );
00213   subRound (C, D, E, A, B, f2, K2, expand ( eData, 28) );
00214   subRound (B, C, D, E, A, f2, K2, expand ( eData, 29) );
00215   subRound (A, B, C, D, E, f2, K2, expand ( eData, 30) );
00216   subRound (E, A, B, C, D, f2, K2, expand ( eData, 31) );
00217   subRound (D, E, A, B, C, f2, K2, expand ( eData, 32) );
00218   subRound (C, D, E, A, B, f2, K2, expand ( eData, 33) );
00219   subRound (B, C, D, E, A, f2, K2, expand ( eData, 34) );
00220   subRound (A, B, C, D, E, f2, K2, expand ( eData, 35) );
00221   subRound (E, A, B, C, D, f2, K2, expand ( eData, 36) );
00222   subRound (D, E, A, B, C, f2, K2, expand ( eData, 37) );
00223   subRound (C, D, E, A, B, f2, K2, expand ( eData, 38) );
00224   subRound (B, C, D, E, A, f2, K2, expand ( eData, 39) );
00225 
00226   subRound (A, B, C, D, E, f3, K3, expand ( eData, 40) );
00227   subRound (E, A, B, C, D, f3, K3, expand ( eData, 41) );
00228   subRound (D, E, A, B, C, f3, K3, expand ( eData, 42) );
00229   subRound (C, D, E, A, B, f3, K3, expand ( eData, 43) );
00230   subRound (B, C, D, E, A, f3, K3, expand ( eData, 44) );
00231   subRound (A, B, C, D, E, f3, K3, expand ( eData, 45) );
00232   subRound (E, A, B, C, D, f3, K3, expand ( eData, 46) );
00233   subRound (D, E, A, B, C, f3, K3, expand ( eData, 47) );
00234   subRound (C, D, E, A, B, f3, K3, expand ( eData, 48) );
00235   subRound (B, C, D, E, A, f3, K3, expand ( eData, 49) );
00236   subRound (A, B, C, D, E, f3, K3, expand ( eData, 50) );
00237   subRound (E, A, B, C, D, f3, K3, expand ( eData, 51) );
00238   subRound (D, E, A, B, C, f3, K3, expand ( eData, 52) );
00239   subRound (C, D, E, A, B, f3, K3, expand ( eData, 53) );
00240   subRound (B, C, D, E, A, f3, K3, expand ( eData, 54) );
00241   subRound (A, B, C, D, E, f3, K3, expand ( eData, 55) );
00242   subRound (E, A, B, C, D, f3, K3, expand ( eData, 56) );
00243   subRound (D, E, A, B, C, f3, K3, expand ( eData, 57) );
00244   subRound (C, D, E, A, B, f3, K3, expand ( eData, 58) );
00245   subRound (B, C, D, E, A, f3, K3, expand ( eData, 59) );
00246 
00247   subRound (A, B, C, D, E, f4, K4, expand ( eData, 60) );
00248   subRound (E, A, B, C, D, f4, K4, expand ( eData, 61) );
00249   subRound (D, E, A, B, C, f4, K4, expand ( eData, 62) );
00250   subRound (C, D, E, A, B, f4, K4, expand ( eData, 63) );
00251   subRound (B, C, D, E, A, f4, K4, expand ( eData, 64) );
00252   subRound (A, B, C, D, E, f4, K4, expand ( eData, 65) );
00253   subRound (E, A, B, C, D, f4, K4, expand ( eData, 66) );
00254   subRound (D, E, A, B, C, f4, K4, expand ( eData, 67) );
00255   subRound (C, D, E, A, B, f4, K4, expand ( eData, 68) );
00256   subRound (B, C, D, E, A, f4, K4, expand ( eData, 69) );
00257   subRound (A, B, C, D, E, f4, K4, expand ( eData, 70) );
00258   subRound (E, A, B, C, D, f4, K4, expand ( eData, 71) );
00259   subRound (D, E, A, B, C, f4, K4, expand ( eData, 72) );
00260   subRound (C, D, E, A, B, f4, K4, expand ( eData, 73) );
00261   subRound (B, C, D, E, A, f4, K4, expand ( eData, 74) );
00262   subRound (A, B, C, D, E, f4, K4, expand ( eData, 75) );
00263   subRound (E, A, B, C, D, f4, K4, expand ( eData, 76) );
00264   subRound (D, E, A, B, C, f4, K4, expand ( eData, 77) );
00265   subRound (C, D, E, A, B, f4, K4, expand ( eData, 78) );
00266   subRound (B, C, D, E, A, f4, K4, expand ( eData, 79) );
00267 
00268   /* Build message digest */
00269   digest[0] += A;
00270   digest[1] += B;
00271   digest[2] += C;
00272   digest[3] += D;
00273   digest[4] += E;
00274 }
00275 
00276 /* When run on a little-endian CPU we need to perform byte reversal on an
00277    array of longwords. */
00278 
00279 #ifdef WORDS_BIGENDIAN
00280 #define swap_words(buffer, byte_count)
00281 #else
00282 static void
00283 swap_words (dbus_uint32_t *buffer,
00284             int            byte_count)
00285 {
00286   byte_count /= sizeof (dbus_uint32_t);
00287   while (byte_count--)
00288     {
00289       *buffer = DBUS_UINT32_SWAP_LE_BE (*buffer);
00290       ++buffer;
00291     }
00292 }
00293 #endif
00294 
00295 static void
00296 sha_init (DBusSHAContext *context)
00297 {
00298   /* Set the h-vars to their initial values */
00299   context->digest[0] = h0init;
00300   context->digest[1] = h1init;
00301   context->digest[2] = h2init;
00302   context->digest[3] = h3init;
00303   context->digest[4] = h4init;
00304 
00305   /* Initialise bit count */
00306   context->count_lo = context->count_hi = 0;
00307 }
00308 
00309 static void
00310 sha_append (DBusSHAContext      *context,
00311             const unsigned char *buffer,
00312             unsigned int         count)
00313 {
00314   dbus_uint32_t tmp;
00315   unsigned int dataCount;
00316 
00317   /* Update bitcount */
00318   tmp = context->count_lo;
00319   if (( context->count_lo = tmp + ( ( dbus_uint32_t) count << 3) ) < tmp)
00320     context->count_hi++;             /* Carry from low to high */
00321   context->count_hi += count >> 29;
00322 
00323   /* Get count of bytes already in data */
00324   dataCount = (int) (tmp >> 3) & 0x3F;
00325 
00326   /* Handle any leading odd-sized chunks */
00327   if (dataCount)
00328     {
00329       unsigned char *p = (unsigned char *) context->data + dataCount;
00330 
00331       dataCount = SHA_DATASIZE - dataCount;
00332       if (count < dataCount)
00333         {
00334           memmove (p, buffer, count);
00335           return;
00336         }
00337       memmove (p, buffer, dataCount);
00338       swap_words (context->data, SHA_DATASIZE);
00339       SHATransform (context->digest, context->data);
00340       buffer += dataCount;
00341       count -= dataCount;
00342     }
00343 
00344   /* Process data in SHA_DATASIZE chunks */
00345   while (count >= SHA_DATASIZE)
00346     {
00347       memmove (context->data, buffer, SHA_DATASIZE);
00348       swap_words (context->data, SHA_DATASIZE);
00349       SHATransform (context->digest, context->data);
00350       buffer += SHA_DATASIZE;
00351       count -= SHA_DATASIZE;
00352     }
00353 
00354   /* Handle any remaining bytes of data. */
00355   memmove (context->data, buffer, count);
00356 }
00357 
00358 
00359 /* Final wrapup - pad to SHA_DATASIZE-byte boundary with the bit pattern
00360    1 0* (64-bit count of bits processed, MSB-first) */
00361 
00362 static void
00363 sha_finish (DBusSHAContext *context, unsigned char digest[20])
00364 {
00365   int count;
00366   unsigned char *data_p;
00367 
00368   /* Compute number of bytes mod 64 */
00369   count = (int) context->count_lo;
00370   count = (count >> 3) & 0x3F;
00371 
00372   /* Set the first char of padding to 0x80.  This is safe since there is
00373      always at least one byte free */
00374   data_p = (unsigned char *) context->data + count;
00375   *data_p++ = 0x80;
00376 
00377   /* Bytes of padding needed to make 64 bytes */
00378   count = SHA_DATASIZE - 1 - count;
00379 
00380   /* Pad out to 56 mod 64 */
00381   if (count < 8)
00382     {
00383       /* Two lots of padding:  Pad the first block to 64 bytes */
00384       memset (data_p, 0, count);
00385       swap_words (context->data, SHA_DATASIZE);
00386       SHATransform (context->digest, context->data);
00387 
00388       /* Now fill the next block with 56 bytes */
00389       memset (context->data, 0, SHA_DATASIZE - 8);
00390     }
00391   else
00392     /* Pad block to 56 bytes */
00393     memset (data_p, 0, count - 8);
00394 
00395   /* Append length in bits and transform */
00396   context->data[14] = context->count_hi;
00397   context->data[15] = context->count_lo;
00398 
00399   swap_words (context->data, SHA_DATASIZE - 8);
00400   SHATransform (context->digest, context->data);
00401   swap_words (context->digest, SHA_DIGESTSIZE);
00402   memmove (digest, context->digest, SHA_DIGESTSIZE);
00403 }
00404  /* End of internals */
00406 
00418 void
00419 _dbus_sha_init (DBusSHAContext *context)
00420 {
00421   sha_init (context);
00422 }
00423 
00430 void
00431 _dbus_sha_update (DBusSHAContext   *context,
00432                   const DBusString *data)
00433 {
00434   unsigned int inputLen;
00435   const unsigned char *input;
00436 
00437   input = (const unsigned char*) _dbus_string_get_const_data (data);
00438   inputLen = _dbus_string_get_length (data);
00439 
00440   sha_append (context, input, inputLen);
00441 }
00442 
00454 dbus_bool_t
00455 _dbus_sha_final (DBusSHAContext   *context,
00456                  DBusString       *results)
00457 {
00458   unsigned char digest[20];
00459 
00460   sha_finish (context, digest);
00461 
00462   if (!_dbus_string_append_len (results, digest, 20))
00463     return FALSE;
00464 
00465   /* some kind of security paranoia, though it seems pointless
00466    * to me given the nonzeroed stuff flying around
00467    */
00468   memset ((void*)context, '\0', sizeof (DBusSHAContext));
00469 
00470   return TRUE;
00471 }
00472 
00481 dbus_bool_t
00482 _dbus_sha_compute (const DBusString *data,
00483                    DBusString       *ascii_output)
00484 {
00485   DBusSHAContext context;
00486   DBusString digest;
00487 
00488   _dbus_sha_init (&context);
00489 
00490   _dbus_sha_update (&context, data);
00491 
00492   if (!_dbus_string_init (&digest))
00493     return FALSE;
00494 
00495   if (!_dbus_sha_final (&context, &digest))
00496     goto error;
00497 
00498   if (!_dbus_string_hex_encode (&digest, 0, ascii_output,
00499                                 _dbus_string_get_length (ascii_output)))
00500     goto error;
00501 
00502   _dbus_string_free (&digest);
00503   
00504   return TRUE;
00505 
00506  error:
00507   _dbus_string_free (&digest);
00508   return FALSE;
00509 }
00510  /* end of exported functions */
00512 
00513 #ifdef DBUS_BUILD_TESTS
00514 #include "dbus-test.h"
00515 #include <stdio.h>
00516 
00517 static dbus_bool_t
00518 check_sha_binary (const unsigned char *input,
00519                   int                  input_len,
00520                   const char          *expected)
00521 {
00522   DBusString input_str;
00523   DBusString expected_str;
00524   DBusString results;
00525 
00526   _dbus_string_init_const_len (&input_str, input, input_len);
00527   _dbus_string_init_const (&expected_str, expected);
00528 
00529   if (!_dbus_string_init (&results))
00530     _dbus_assert_not_reached ("no memory for SHA-1 results");
00531 
00532   if (!_dbus_sha_compute (&input_str, &results))
00533     _dbus_assert_not_reached ("no memory for SHA-1 results");
00534 
00535   if (!_dbus_string_equal (&expected_str, &results))
00536     {
00537       _dbus_warn ("Expected hash %s got %s for SHA-1 sum\n",
00538                   expected,
00539                   _dbus_string_get_const_data (&results));
00540       _dbus_string_free (&results);
00541       return FALSE;
00542     }
00543 
00544   _dbus_string_free (&results);
00545   return TRUE;
00546 }
00547 
00548 static dbus_bool_t
00549 check_sha_str (const char *input,
00550                const char *expected)
00551 {
00552   return check_sha_binary (input, strlen (input), expected);
00553 }
00554 
00555 static dbus_bool_t
00556 decode_compact_string (const DBusString *line,
00557                        DBusString       *decoded)
00558 {
00559   int n_bits;
00560   dbus_bool_t current_b;
00561   int offset;
00562   int next;
00563   long val;
00564   int length_bytes;
00565   
00566   offset = 0;
00567   next = 0;
00568 
00569   if (!_dbus_string_parse_int (line, offset, &val, &next))
00570     {
00571       fprintf (stderr, "could not parse length at start of compact string: %s\n",
00572                _dbus_string_get_const_data (line));
00573       return FALSE;
00574     }
00575 
00576   _dbus_string_skip_blank (line, next, &next);
00577   
00578   offset = next;
00579   if (!_dbus_string_parse_int (line, offset, &val, &next))
00580     {
00581       fprintf (stderr, "could not parse start bit 'b' in compact string: %s\n",
00582                _dbus_string_get_const_data (line));
00583       return FALSE;
00584     }
00585   
00586   if (!(val == 0 || val == 1))
00587     {
00588       fprintf (stderr, "the value 'b' must be 0 or 1, see sha-1/Readme.txt\n");
00589       return FALSE;
00590     }
00591 
00592   _dbus_string_skip_blank (line, next, &next);
00593   
00594   current_b = val;
00595   n_bits = 0;
00596   
00597   while (next < _dbus_string_get_length (line))
00598     {
00599       int total_bits;
00600       
00601       offset = next;
00602 
00603       if (_dbus_string_get_byte (line, offset) == '^')
00604         break;
00605       
00606       if (!_dbus_string_parse_int (line, offset, &val, &next))
00607         {
00608           fprintf (stderr, "could not parse bit count in compact string\n");
00609           return FALSE;
00610         }
00611 
00612       /* We now append "val" copies of "current_b" bits to the string */
00613       total_bits = n_bits + val;
00614       while (n_bits < total_bits)
00615         {
00616           int byte_containing_next_bit = n_bits / 8;
00617           int bit_containing_next_bit = 7 - (n_bits % 8);
00618           unsigned char old_byte;
00619           
00620           if (byte_containing_next_bit >= _dbus_string_get_length (decoded))
00621             {
00622               if (!_dbus_string_set_length (decoded, byte_containing_next_bit + 1))
00623                 _dbus_assert_not_reached ("no memory to extend to next byte");
00624             }
00625 
00626           old_byte = _dbus_string_get_byte (decoded, byte_containing_next_bit);
00627           old_byte |= current_b << bit_containing_next_bit;
00628 
00629 #if 0
00630           printf ("Appending bit %d to byte %d at bit %d resulting in byte 0x%x\n",
00631                   current_b, byte_containing_next_bit,
00632                   bit_containing_next_bit, old_byte);
00633 #endif
00634           
00635           _dbus_string_set_byte (decoded, byte_containing_next_bit, old_byte);
00636           
00637           ++n_bits;
00638         }
00639 
00640       _dbus_string_skip_blank (line, next, &next);
00641           
00642       current_b = !current_b;
00643     }
00644 
00645   length_bytes = (n_bits / 8 + ((n_bits % 8) ? 1 : 0));
00646   
00647   if (_dbus_string_get_length (decoded) != length_bytes)
00648     {
00649       fprintf (stderr, "Expected length %d bytes %d bits for compact string, got %d bytes\n",
00650                length_bytes, n_bits, _dbus_string_get_length (decoded));
00651       return FALSE;
00652     }
00653   else
00654     return TRUE;
00655 }
00656 
00657 static dbus_bool_t
00658 get_next_expected_result (DBusString *results,
00659                           DBusString *result)
00660 {
00661   DBusString line;
00662   dbus_bool_t retval;
00663 
00664   retval = FALSE;
00665   
00666   if (!_dbus_string_init (&line))
00667     _dbus_assert_not_reached ("no memory");
00668   
00669  next_iteration:
00670   while (_dbus_string_pop_line (results, &line))
00671     {
00672       _dbus_string_delete_leading_blanks (&line);
00673 
00674       if (_dbus_string_get_length (&line) == 0)
00675         goto next_iteration;
00676       else if (_dbus_string_starts_with_c_str (&line, "#"))
00677         goto next_iteration;
00678       else if (_dbus_string_starts_with_c_str (&line, "H>"))
00679         {
00680           /* don't print */
00681         }
00682       else if (_dbus_string_starts_with_c_str (&line, "D>") ||
00683                _dbus_string_starts_with_c_str (&line, "<D"))
00684         goto next_iteration;
00685       else
00686         {
00687           int i;
00688           
00689           if (!_dbus_string_move (&line, 0, result, 0))
00690             _dbus_assert_not_reached ("no memory");
00691 
00692           i = 0;
00693           while (i < _dbus_string_get_length (result))
00694             {
00695               switch (_dbus_string_get_byte (result, i))
00696                 {
00697                 case 'A':
00698                   _dbus_string_set_byte (result, i, 'a');
00699                   break;
00700                 case 'B':
00701                   _dbus_string_set_byte (result, i, 'b');
00702                   break;
00703                 case 'C':
00704                   _dbus_string_set_byte (result, i, 'c');
00705                   break;
00706                 case 'D':
00707                   _dbus_string_set_byte (result, i, 'd');
00708                   break;
00709                 case 'E':
00710                   _dbus_string_set_byte (result, i, 'e');
00711                   break;
00712                 case 'F':
00713                   _dbus_string_set_byte (result, i, 'f');
00714                   break;
00715                 case '^':
00716                 case ' ':
00717                   _dbus_string_delete (result, i, 1);
00718                   --i; /* to offset ++i below */
00719                   break;
00720                 }
00721 
00722               ++i;
00723             }
00724           
00725           break;
00726         }
00727     }
00728   
00729   retval = TRUE;
00730   
00731   /* out: */
00732   _dbus_string_free (&line);
00733   return retval;
00734 }
00735 
00736 static dbus_bool_t
00737 process_test_data (const char *test_data_dir)
00738 {
00739   DBusString tests_file;
00740   DBusString results_file;
00741   DBusString tests;
00742   DBusString results;
00743   DBusString line;
00744   DBusString tmp;
00745   int line_no;
00746   dbus_bool_t retval;
00747   int success_count;
00748   DBusError error = DBUS_ERROR_INIT;
00749 
00750   retval = FALSE;
00751   
00752   if (!_dbus_string_init (&tests_file))
00753     _dbus_assert_not_reached ("no memory");
00754 
00755   if (!_dbus_string_init (&results_file))
00756     _dbus_assert_not_reached ("no memory");
00757 
00758   if (!_dbus_string_init (&tests))
00759     _dbus_assert_not_reached ("no memory");
00760 
00761   if (!_dbus_string_init (&results))
00762     _dbus_assert_not_reached ("no memory");
00763 
00764   if (!_dbus_string_init (&line))
00765     _dbus_assert_not_reached ("no memory");
00766   
00767   if (!_dbus_string_append (&tests_file, test_data_dir))
00768     _dbus_assert_not_reached ("no memory");
00769 
00770   if (!_dbus_string_append (&results_file, test_data_dir))
00771     _dbus_assert_not_reached ("no memory");
00772 
00773   _dbus_string_init_const (&tmp, "sha-1/byte-messages.sha1");
00774   if (!_dbus_concat_dir_and_file (&tests_file, &tmp))
00775     _dbus_assert_not_reached ("no memory");
00776 
00777   _dbus_string_init_const (&tmp, "sha-1/byte-hashes.sha1");
00778   if (!_dbus_concat_dir_and_file (&results_file, &tmp))
00779     _dbus_assert_not_reached ("no memory");
00780 
00781   if (!_dbus_file_get_contents (&tests, &tests_file, &error))
00782     {
00783       fprintf (stderr, "could not load test data file %s: %s\n",
00784                _dbus_string_get_const_data (&tests_file),
00785                error.message);
00786       dbus_error_free (&error);
00787       goto out;
00788     }
00789 
00790   if (!_dbus_file_get_contents (&results, &results_file, &error))
00791     {
00792       fprintf (stderr, "could not load results data file %s: %s\n",
00793                _dbus_string_get_const_data (&results_file), error.message);
00794       dbus_error_free (&error);
00795       goto out;
00796     }
00797 
00798   success_count = 0;
00799   line_no = 0;
00800  next_iteration:
00801   while (_dbus_string_pop_line (&tests, &line))
00802     {
00803       line_no += 1;
00804 
00805       _dbus_string_delete_leading_blanks (&line);
00806 
00807       if (_dbus_string_get_length (&line) == 0)
00808         goto next_iteration;
00809       else if (_dbus_string_starts_with_c_str (&line, "#"))
00810         goto next_iteration;
00811       else if (_dbus_string_starts_with_c_str (&line, "H>"))
00812         {
00813           printf ("SHA-1: %s\n", _dbus_string_get_const_data (&line));
00814 
00815           if (_dbus_string_find (&line, 0, "Type 3", NULL))
00816             {
00817               /* See sha-1/Readme.txt - the "Type 3" tests are
00818                * random seeds, rather than data to be hashed.
00819                * we'd have to do a little bit more implementation
00820                * to use those tests.
00821                */
00822               
00823               printf (" (ending tests due to Type 3 tests seen - this is normal)\n");
00824               break;
00825             }
00826         }
00827       else if (_dbus_string_starts_with_c_str (&line, "D>") ||
00828                _dbus_string_starts_with_c_str (&line, "<D"))
00829         goto next_iteration;
00830       else
00831         {
00832           DBusString test;
00833           DBusString result;
00834           DBusString next_line;
00835           DBusString expected;
00836           dbus_bool_t success;
00837 
00838           success = FALSE;
00839           
00840           if (!_dbus_string_init (&next_line))
00841             _dbus_assert_not_reached ("no memory");
00842 
00843           if (!_dbus_string_init (&expected))
00844             _dbus_assert_not_reached ("no memory");
00845           
00846           if (!_dbus_string_init (&test))
00847             _dbus_assert_not_reached ("no memory");
00848 
00849           if (!_dbus_string_init (&result))
00850             _dbus_assert_not_reached ("no memory");
00851 
00852           /* the "compact strings" are "^"-terminated not
00853            * newline-terminated so readahead to find the
00854            * "^"
00855            */
00856           while (!_dbus_string_find (&line, 0, "^", NULL) &&
00857                  _dbus_string_pop_line (&tests, &next_line))
00858             {
00859               if (!_dbus_string_append_byte (&line, ' ') ||
00860                   !_dbus_string_move (&next_line, 0, &line,
00861                                       _dbus_string_get_length (&line)))
00862                 _dbus_assert_not_reached ("no memory");
00863             }
00864           
00865           if (!decode_compact_string (&line, &test))
00866             {
00867               fprintf (stderr, "Failed to decode line %d as a compact string\n",
00868                        line_no);
00869               goto failure;
00870             }
00871           
00872           if (!_dbus_sha_compute (&test, &result))
00873             _dbus_assert_not_reached ("no memory for SHA-1 result");
00874 
00875           if (!get_next_expected_result (&results, &expected))
00876             {
00877               fprintf (stderr, "Failed to read an expected result\n");
00878               goto failure;
00879             }
00880           
00881           if (!_dbus_string_equal (&result, &expected))
00882             {              
00883               fprintf (stderr, " for line %d got hash %s expected %s\n",
00884                        line_no,
00885                        _dbus_string_get_const_data (&result),
00886                        _dbus_string_get_const_data (&expected));
00887               goto failure;
00888             }
00889           else
00890             {
00891               success_count += 1;
00892             }
00893 
00894           success = TRUE;
00895 
00896         failure:
00897           _dbus_string_free (&test);
00898           _dbus_string_free (&result);
00899           _dbus_string_free (&next_line);
00900           _dbus_string_free (&expected);
00901 
00902           if (!success)
00903             goto out;
00904         }
00905     }
00906 
00907   retval = TRUE;
00908 
00909   printf ("Passed the %d SHA-1 tests in the test file\n",
00910           success_count);
00911   
00912  out:
00913   _dbus_string_free (&tests_file);
00914   _dbus_string_free (&results_file);
00915   _dbus_string_free (&tests);
00916   _dbus_string_free (&results);
00917   _dbus_string_free (&line);
00918 
00919   return retval;
00920 }
00921 
00928 dbus_bool_t
00929 _dbus_sha_test (const char *test_data_dir)
00930 {
00931   unsigned char all_bytes[256];
00932   int i;
00933 
00934   if (test_data_dir != NULL)
00935     {
00936       if (!process_test_data (test_data_dir))
00937         return FALSE;
00938     }
00939   else
00940     printf ("No test data dir\n");
00941   
00942   i = 0;
00943   while (i < 256)
00944     {
00945       all_bytes[i] = i;
00946       ++i;
00947     }
00948 
00949   if (!check_sha_binary (all_bytes, 256,
00950                          "4916d6bdb7f78e6803698cab32d1586ea457dfc8"))
00951     return FALSE;
00952 
00953 #define CHECK(input,expected) if (!check_sha_str (input, expected)) return FALSE
00954 
00955   CHECK ("", "da39a3ee5e6b4b0d3255bfef95601890afd80709");
00956   CHECK ("a", "86f7e437faa5a7fce15d1ddcb9eaeaea377667b8");
00957   CHECK ("abc", "a9993e364706816aba3e25717850c26c9cd0d89d");
00958   CHECK ("message digest", "c12252ceda8be8994d5fa0290a47231c1d16aae3");
00959   CHECK ("abcdefghijklmnopqrstuvwxyz", "32d10c7b8cf96570ca04ce37f2a19d84240d3a89");
00960   CHECK ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
00961          "761c457bf73b14d27e9e9265c46f4b4dda11f940");
00962   CHECK ("12345678901234567890123456789012345678901234567890123456789012345678901234567890",
00963          "50abf5706a150990a08b2c5ea40fa0e585554732");
00964 
00965   return TRUE;
00966 }
00967 
00968 #endif /* DBUS_BUILD_TESTS */

Generated on Tue Feb 24 16:40:40 2009 for D-Bus by  doxygen 1.5.1