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