* ttyio.c (tty_enable_completion, tty_disable_completion): Add checks
[gnupg.git] / cipher / rmd160.c
index f0072f7..7a7230f 100644 (file)
@@ -1,21 +1,22 @@
 /* rmd160.c  - RIPE-MD160
- *     Copyright (C) 1998 Free Software Foundation, Inc.
+ *     Copyright (C) 1998, 1999, 2000, 2001 Free Software Foundation, Inc.
  *
- * This file is part of GNUPG.
+ * This file is part of GnuPG.
  *
- * GNUPG is free software; you can redistribute it and/or modify
+ * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  *
- * GNUPG is distributed in the hope that it will be useful,
+ * GnuPG is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
  */
 
 #include <config.h>
 #include "util.h"
 #include "memory.h"
 #include "rmd.h"
+#include "cipher.h" /* for rmd160_hash_buffer */
+#include "algorithms.h"
+
+#include "bithelp.h"
 
 /*********************************
  * RIPEMD-160 is not patented, see (as of 25.10.97)
  * 1 million times "a"   52783243c1697bdbe16d37f97f68f08325dc1528
  */
 
+static void
+burn_stack (int bytes)
+{
+    char buf[150];
+    
+    wipememory(buf,sizeof buf);
+    bytes -= sizeof buf;
+    if (bytes > 0)
+        burn_stack (bytes);
+}
+
+
 
 void
 rmd160_init( RMD160_CONTEXT *hd )
@@ -151,19 +168,6 @@ rmd160_init( RMD160_CONTEXT *hd )
 }
 
 
-#if defined(__GNUC__) && defined(__i386__)
-static inline u32
-rol(int n, u32 x)
-{
-       __asm__("roll %%cl,%0"
-               :"=r" (x)
-               :"0" (x),"c" (n));
-       return x;
-}
-#else
-  #define rol(n,x) ( ((x) << (n)) | ((x) >> (32-(n))) )
-#endif
-
 
 /****************
  * Transform the message X which consists of 16 32-bit-words
@@ -171,10 +175,8 @@ rol(int n, u32 x)
 static void
 transform( RMD160_CONTEXT *hd, byte *data )
 {
-
-
     u32 a,b,c,d,e,aa,bb,cc,dd,ee,t;
-  #ifdef BIG_ENDIAN_HOST
+#ifdef BIG_ENDIAN_HOST
     u32 x[16];
     { int i;
       byte *p2, *p1;
@@ -185,9 +187,21 @@ transform( RMD160_CONTEXT *hd, byte *data )
        p2[0] = *p1++;
       }
     }
-  #else
-    u32 *x = (u32*)data;
-  #endif
+#else
+#if 0
+    u32 *x =(u32*)data;
+#else
+    /* this version is better because it is always aligned;
+     * The performance penalty on a 586-100 is about 6% which
+     * is acceptable - because the data is more local it might
+     * also be possible that this is faster on some machines.
+     * This function (when compiled with -02 on gcc 2.7.2)
+     * executes on a 586-100 (39.73 bogomips) at about 1900kb/sec;
+     * [measured with a 4MB data and "gpgm --print-md rmd160"] */
+    u32 x[16];
+    memcpy( x, data, 64 );
+#endif
+#endif
 
 
 #define K0  0x00000000
@@ -206,8 +220,8 @@ transform( RMD160_CONTEXT *hd, byte *data )
 #define F3(x,y,z)   ( ((x) & (z)) | ((y) & ~(z)) )
 #define F4(x,y,z)   ( (x) ^ ((y) | ~(z)) )
 #define R(a,b,c,d,e,f,k,r,s) do { t = a + f(b,c,d) + k + x[r]; \
-                                 a = rol(s,t) + e;            \
-                                 c = rol(10,c);               \
+                                 a = rol(t,s) + e;            \
+                                 c = rol(c,10);               \
                                } while(0)
 
     /* left lane */
@@ -396,15 +410,15 @@ transform( RMD160_CONTEXT *hd, byte *data )
 }
 
 
-
 /* Update the message digest with the contents
  * of INBUF with length INLEN.
  */
-void
+static void
 rmd160_write( RMD160_CONTEXT *hd, byte *inbuf, size_t inlen)
 {
     if( hd->count == 64 ) { /* flush the buffer */
        transform( hd, hd->buf );
+        burn_stack (108+5*sizeof(void*));
        hd->count = 0;
        hd->nblocks++;
     }
@@ -425,15 +439,15 @@ rmd160_write( RMD160_CONTEXT *hd, byte *inbuf, size_t inlen)
        inlen -= 64;
        inbuf += 64;
     }
+    burn_stack (108+5*sizeof(void*));
     for( ; inlen && hd->count < 64; inlen-- )
        hd->buf[hd->count++] = *inbuf++;
 }
 
-
 /****************
  * Apply the rmd160 transform function on the buffer which must have
  * a length 64 bytes. Do not use this function together with the
- * other functions, use rmd160_init to initialize intzernal variables.
+ * other functions, use rmd160_init to initialize internal variables.
  * Returns: 16 bytes in buffer with the mixed contentes of buffer.
  */
 void
@@ -441,20 +455,20 @@ rmd160_mixblock( RMD160_CONTEXT *hd, char *buffer )
 {
     char *p = buffer;
     transform( hd, buffer );
-  #define X(a) do { *(u32*)p = hd->h##a ; p += 4; } while(0)
+#define X(a) do { *(u32*)p = hd->h##a ; p += 4; } while(0)
     X(0);
     X(1);
     X(2);
     X(3);
     X(4);
-  #undef X
+#undef X
 }
 
 
 /* The routine terminates the computation
  */
 
-void
+static void
 rmd160_final( RMD160_CONTEXT *hd )
 {
     u32 t, msb, lsb;
@@ -462,18 +476,19 @@ rmd160_final( RMD160_CONTEXT *hd )
 
     rmd160_write(hd, NULL, 0); /* flush */;
 
-    msb = 0;
     t = hd->nblocks;
-    if( (lsb = t << 6) < t ) /* multiply by 64 to make a byte count */
-       msb++;
-    msb += t >> 26;
+    /* multiply by 64 to make a byte count */
+    lsb = t << 6;
+    msb = t >> 26;
+    /* add the count */
     t = lsb;
-    if( (lsb = t + hd->count) < t ) /* add the count */
+    if( (lsb += hd->count) < t )
        msb++;
+    /* multiply by 8 to make a bit count */
     t = lsb;
-    if( (lsb = t << 3) < t ) /* multiply by 8 to make a bit count */
-       msb++;
-    msb += t >> 29;
+    lsb <<= 3;
+    msb <<= 3;
+    msb |= t >> 29;
 
     if( hd->count < 56 ) { /* enough room */
        hd->buf[hd->count++] = 0x80; /* pad */
@@ -497,20 +512,77 @@ rmd160_final( RMD160_CONTEXT *hd )
     hd->buf[62] = msb >> 16;
     hd->buf[63] = msb >> 24;
     transform( hd, hd->buf );
+    burn_stack (108+5*sizeof(void*));
 
     p = hd->buf;
-  #ifdef BIG_ENDIAN_HOST
-    #define X(a) do { *p++ = hd->h##a     ; *p++ = hd->h##a >> 8;      \
+#ifdef BIG_ENDIAN_HOST
+#define X(a) do { *p++ = hd->h##a         ; *p++ = hd->h##a >> 8;      \
                      *p++ = hd->h##a >> 16; *p++ = hd->h##a >> 24; } while(0)
-  #else /* little endian */
-    #define X(a) do { *(u32*)p = hd->h##a ; p += 4; } while(0)
-  #endif
+#else /* little endian */
+#define X(a) do { *(u32*)p = hd->h##a ; p += 4; } while(0)
+#endif
     X(0);
     X(1);
     X(2);
     X(3);
     X(4);
-  #undef X
+#undef X
 }
 
+static byte *
+rmd160_read( RMD160_CONTEXT *hd )
+{
+    return hd->buf;
+}
+
+
 
+/****************
+ * Shortcut functions which puts the hash value of the supplied buffer
+ * into outbuf which must have a size of 20 bytes.
+ */
+void
+rmd160_hash_buffer( char *outbuf, const char *buffer, size_t length )
+{
+    RMD160_CONTEXT hd;
+
+    rmd160_init( &hd );
+    rmd160_write( &hd, (byte*)buffer, length );
+    rmd160_final( &hd );
+    memcpy( outbuf, hd.buf, 20 );
+}
+
+
+/****************
+ * Return some information about the algorithm.  We need algo here to
+ * distinguish different flavors of the algorithm.
+ * Returns: A pointer to string describing the algorithm or NULL if
+ *         the ALGO is invalid.
+ */
+const char *
+rmd160_get_info( int algo, size_t *contextsize,
+              byte **r_asnoid, int *r_asnlen, int *r_mdlen,
+              void (**r_init)( void *c ),
+              void (**r_write)( void *c, byte *buf, size_t nbytes ),
+              void (**r_final)( void *c ),
+              byte *(**r_read)( void *c )
+            )
+{
+    static byte asn[15] = /* Object ID is 1.3.36.3.2.1 */
+         { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x24, 0x03,
+           0x02, 0x01, 0x05, 0x00, 0x04, 0x14 };
+
+    if( algo != 3 )
+       return NULL;
+
+    *contextsize = sizeof(RMD160_CONTEXT);
+    *r_asnoid = asn;
+    *r_asnlen = DIM(asn);
+    *r_mdlen = 20;
+    *(void  (**)(RMD160_CONTEXT *))r_init                = rmd160_init;
+    *(void  (**)(RMD160_CONTEXT *, byte*, size_t))r_write = rmd160_write;
+    *(void  (**)(RMD160_CONTEXT *))r_final               = rmd160_final;
+    *(byte *(**)(RMD160_CONTEXT *))r_read                = rmd160_read;
+
+    return "RIPEMD160";
+}