Code

fix parameter ranges, copyedit
[inkscape.git] / src / pedro / pedroutil.cpp
index 6de3bbfd414a2fc4421de9bb3cdba87d34dae4bc..09407ff08a52fcb09c47dfcff04fb43a4c87ffa8 100644 (file)
@@ -4,7 +4,7 @@
  * Authors:
  *   Bob Jamison
  *
- * Copyright (C) 2005-2006 Bob Jamison
+ * Copyright (C) 2005-2007 Bob Jamison
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public
@@ -24,7 +24,7 @@
 
 #include <stdio.h>
 #include <stdarg.h>
-
+#include <string.h>
 #include <sys/stat.h>
 
 #include "pedroutil.h"
@@ -48,6 +48,9 @@
 
 #endif /* UNIX */
 
+#ifdef HAVE_SSL
+RELAYTOOL_SSL
+#endif
 
 
 namespace Pedro
@@ -69,7 +72,7 @@ namespace Pedro
 //#################
 
 
-static char *base64encode =
+static const char *base64encode =
     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 
 
@@ -301,9 +304,6 @@ DOMString Base64Decoder::decodeToString(const DOMString &str)
 //########################################################################
 //########################################################################
 
-
-
-
 void Sha1::hash(unsigned char *dataIn, int len, unsigned char *digest)
 {
     Sha1 sha1;
@@ -311,7 +311,7 @@ void Sha1::hash(unsigned char *dataIn, int len, unsigned char *digest)
     sha1.finish(digest);
 }
 
-static char *sha1hex = "0123456789abcdef";
+static const char *sha1hex = "0123456789abcdef";
 
 DOMString Sha1::hashHex(unsigned char *dataIn, int len)
 {
@@ -328,70 +328,106 @@ DOMString Sha1::hashHex(unsigned char *dataIn, int len)
 }
 
 
+DOMString Sha1::hashHex(const DOMString &str)
+{
+    return hashHex((unsigned char *)str.c_str(), str.size());
+}
+
+
 void Sha1::init()
 {
 
-    lenW   = 0;
-    sizeHi = 0;
-    sizeLo = 0;
+    longNr    = 0;
+    byteNr    = 0;
+    nrBytesHi = 0;
+    nrBytesLo = 0;
 
     // Initialize H with the magic constants (see FIPS180 for constants)
-    H[0] = 0x67452301L;
-    H[1] = 0xefcdab89L;
-    H[2] = 0x98badcfeL;
-    H[3] = 0x10325476L;
-    H[4] = 0xc3d2e1f0L;
+    hashBuf[0] = 0x67452301L;
+    hashBuf[1] = 0xefcdab89L;
+    hashBuf[2] = 0x98badcfeL;
+    hashBuf[3] = 0x10325476L;
+    hashBuf[4] = 0xc3d2e1f0L;
+
+    for (int i = 0; i < 4; i++)
+        inb[i] = 0;
 
     for (int i = 0; i < 80; i++)
-        W[i] = 0;
+        inBuf[i] = 0;
 }
 
 
-void Sha1::append(unsigned char *dataIn, int len)
+void Sha1::append(unsigned char ch)
 {
-    // Read the data into W and process blocks as they get full
-    for (int i = 0; i < len; i++)
+    if (nrBytesLo == 0xffffffffL)
         {
-        W[lenW / 4] <<= 8;
-        W[lenW / 4] |= (unsigned long)dataIn[i];
-        if ((++lenW) % 64 == 0)
-            {
-            hashblock();
-            lenW = 0;
-            }
-        sizeLo += 8;
-        sizeHi += (sizeLo < 8);
+        nrBytesHi++;
+        nrBytesLo = 0;
+        }
+    else
+        nrBytesLo++;
+
+    inb[byteNr++] = (unsigned long)ch;
+    if (byteNr >= 4)
+        {
+        inBuf[longNr++] = inb[0] << 24 | inb[1] << 16 |
+                          inb[2] << 8  | inb[3];
+        byteNr = 0;
+        }
+    if (longNr >= 16)
+        {
+        transform();
+        longNr = 0;
         }
 }
 
 
-void Sha1::finish(unsigned char hashout[20])
+void Sha1::append(unsigned char *dataIn, int len)
+{
+    for (int i = 0; i < len; i++)
+        append(dataIn[i]);
+}
+
+
+void Sha1::append(const DOMString &str)
+{
+    append((unsigned char *)str.c_str(), str.size());
+}
+
+
+void Sha1::finish(unsigned char digest[20])
 {
-    unsigned char pad0x80 = 0x80;
-    unsigned char pad0x00 = 0x00;
-    unsigned char padlen[8];
+    //snapshot the bit count now before padding
+    unsigned long nrBitsLo = (nrBytesLo << 3) & 0xffffffff;
+    unsigned long nrBitsHi = (nrBytesHi << 3) | ((nrBytesLo >> 29) & 7);
 
-    // Pad with a binary 1 (e.g. 0x80), then zeroes, then length
-    padlen[0] = (unsigned char)((sizeHi >> 24) & 255);
-    padlen[1] = (unsigned char)((sizeHi >> 16) & 255);
-    padlen[2] = (unsigned char)((sizeHi >>  8) & 255);
-    padlen[3] = (unsigned char)((sizeHi >>  0) & 255);
-    padlen[4] = (unsigned char)((sizeLo >> 24) & 255);
-    padlen[5] = (unsigned char)((sizeLo >> 16) & 255);
-    padlen[6] = (unsigned char)((sizeLo >>  8) & 255);
-    padlen[7] = (unsigned char)((sizeLo >>  0) & 255);
+    //Append terminal char
+    append(0x80);
 
-    append(&pad0x80, 1);
+    //pad until we have a 56 of 64 bytes, allowing for 8 bytes at the end
+    while (longNr != 14)
+        append(0);
 
-    while (lenW != 56)
-        append(&pad0x00, 1);
-    append(padlen, 8);
 
-    // Output hash
-    for (int i = 0; i < 20; i++)
+    //##### Append length in bits
+    append((unsigned char)((nrBitsHi>>24) & 0xff));
+    append((unsigned char)((nrBitsHi>>16) & 0xff));
+    append((unsigned char)((nrBitsHi>> 8) & 0xff));
+    append((unsigned char)((nrBitsHi    ) & 0xff));
+    append((unsigned char)((nrBitsLo>>24) & 0xff));
+    append((unsigned char)((nrBitsLo>>16) & 0xff));
+    append((unsigned char)((nrBitsLo>> 8) & 0xff));
+    append((unsigned char)((nrBitsLo    ) & 0xff));
+
+
+    //copy out answer
+    int indx = 0;
+    for (int i=0 ; i<5 ; i++)
         {
-        hashout[i] = (unsigned char)(H[i / 4] >> 24);
-        H[i / 4] <<= 8;
+        digest[indx++] = (unsigned char)((hashBuf[i] >> 24) & 0xff);
+        digest[indx++] = (unsigned char)((hashBuf[i] >> 16) & 0xff);
+        digest[indx++] = (unsigned char)((hashBuf[i] >>  8) & 0xff);
+        digest[indx++] = (unsigned char)((hashBuf[i]      ) & 0xff);
         }
 
     // Re-initialize the context (also zeroizes contents)
@@ -399,10 +435,13 @@ void Sha1::finish(unsigned char hashout[20])
 }
 
 
-#define SHA_ROTL(X,n) ((((X) << (n)) | ((X) >> (32-(n)))) & 0xffffffffL)
 
-void Sha1::hashblock()
+#define SHA_ROTL(X,n) ((((X) << (n)) & 0xffffffff) | (((X) >> (32-(n))) & 0xffffffff))
+
+void Sha1::transform()
 {
+    unsigned long *W = inBuf;
+    unsigned long *H = hashBuf;
 
     for (int t = 16; t <= 79; t++)
         W[t] = SHA_ROTL(W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16], 1);
@@ -417,7 +456,7 @@ void Sha1::hashblock()
 
     for (int t = 0; t <= 19; t++)
         {
-        TEMP = (SHA_ROTL(A,5) + (((C^D)&B)^D) +
+        TEMP = (SHA_ROTL(A,5) + ((B&C)|((~B)&D)) +
                 E + W[t] + 0x5a827999L) & 0xffffffffL;
         E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
         }
@@ -429,7 +468,7 @@ void Sha1::hashblock()
         }
     for (int t = 40; t <= 59; t++)
         {
-        TEMP = (SHA_ROTL(A,5) + ((B&C)|(D&(B|C))) +
+        TEMP = (SHA_ROTL(A,5) + ((B&C)|(B&D)|(C&D)) +
                 E + W[t] + 0x8f1bbcdcL) & 0xffffffffL;
         E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
         }
@@ -440,18 +479,15 @@ void Sha1::hashblock()
         E = D; D = C; C = SHA_ROTL(B, 30); B = A; A = TEMP;
         }
 
-    H[0] += A;
-    H[1] += B;
-    H[2] += C;
-    H[3] += D;
-    H[4] += E;
+    H[0] = (H[0] + A) & 0xffffffffL;
+    H[1] = (H[1] + B) & 0xffffffffL;
+    H[2] = (H[2] + C) & 0xffffffffL;
+    H[3] = (H[3] + D) & 0xffffffffL;
+    H[4] = (H[4] + E) & 0xffffffffL;
 }
 
 
 
-
-
-
 //########################################################################
 //########################################################################
 //### M D 5      H A S H I N G
@@ -461,7 +497,6 @@ void Sha1::hashblock()
 
 
 
-
 void Md5::hash(unsigned char *dataIn, unsigned long len, unsigned char *digest)
 {
     Md5 md5;
@@ -477,102 +512,75 @@ DOMString Md5::hashHex(unsigned char *dataIn, unsigned long len)
     return ret;
 }
 
-
-
-/*
- * Note: this code is harmless on little-endian machines.
- */
-/*
-static void byteReverse(unsigned char *buf, unsigned long longs)
-{
-    do
-        {
-        unsigned long t = (unsigned long)
-            ((unsigned) buf[3] << 8 | buf[2]) << 16 |
-            ((unsigned) buf[1] << 8 | buf[0]);
-        *(unsigned long *) buf = t;
-        buf += 4;
-        } while (--longs);
-}
-*/
-
-static void md5_memcpy(void *dest, void *src, int n)
+DOMString Md5::hashHex(const DOMString &str)
 {
-    unsigned char *s1 = (unsigned char *)dest;
-    unsigned char *s2 = (unsigned char *)src;
-    while (n--)
-        *s1++ = *s2++;
+    Md5 md5;
+    md5.append(str);
+    DOMString ret = md5.finishHex();
+    return ret;
 }
 
-static void md5_memset(void *dest, char v, int n)
-{
-    unsigned char *s = (unsigned char *)dest;
-    while (n--)
-        *s++ = v;
-}
 
 /**
  * Initialize MD5 polynomials and storage
  */
 void Md5::init()
 {
-    buf[0]  = 0x67452301;
-    buf[1]  = 0xefcdab89;
-    buf[2]  = 0x98badcfe;
-    buf[3]  = 0x10325476;
-
-    bits[0] = 0;
-    bits[1] = 0;
+    hashBuf[0]  = 0x67452301;
+    hashBuf[1]  = 0xefcdab89;
+    hashBuf[2]  = 0x98badcfe;
+    hashBuf[3]  = 0x10325476;
+
+    nrBytesHi = 0;
+    nrBytesLo = 0;
+    byteNr    = 0;
+    longNr    = 0;
 }
 
-/*
- * Update context to reflect the concatenation of another buffer full
- * of bytes.
- */
-void Md5::append(unsigned char *source, unsigned long len)
-{
-
-    // Update bitcount
-    unsigned long t = bits[0];
-    if ((bits[0] = t + ((unsigned long) len << 3)) < t)
-           bits[1]++;// Carry from low to high
-    bits[1] += len >> 29;
 
-       //Bytes already in shsInfo->data
-    t = (t >> 3) & 0x3f;
 
 
-    // Handle any leading odd-sized chunks
-    if (t)
+/**
+ * Update with one character
+ */
+void Md5::append(unsigned char ch)
+{
+    if (nrBytesLo == 0xffffffff)
         {
-        unsigned char *p = (unsigned char *) in + t;
-        t = 64 - t;
-        if (len < t)
-            {
-            md5_memcpy(p, source, len);
-            return;
-            }
-        md5_memcpy(p, source, t);
-        //byteReverse(in, 16);
-        transform(buf, (unsigned long *) in);
-        source += t;
-        len    -= t;
+        nrBytesLo = 0;
+        nrBytesHi++;
         }
+    else
+        nrBytesLo++;
 
-    // Process data in 64-byte chunks
-    while (len >= 64)
+    //pack 64 bytes into 16 longs
+    inb[byteNr++] = (unsigned long)ch;
+    if (byteNr >= 4)
+        {
+        unsigned long val =
+             inb[3] << 24 | inb[2] << 16 | inb[1] << 8 | inb[0];
+        inBuf[longNr++] = val;
+        byteNr = 0;
+        }
+    if (longNr >= 16)
         {
-        md5_memcpy(in, source, 64);
-        //byteReverse(in, 16);
-        transform(buf, (unsigned long *) in);
-        source += 64;
-        len    -= 64;
+        transform();
+        longNr = 0;
         }
+}
+
 
-    // Handle any remaining bytes of data.
-    md5_memcpy(in, source, len);
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void Md5::append(unsigned char *source, unsigned long len)
+{
+    while (len--)
+        append(*source++);
 }
 
+
 /*
  * Update context to reflect the concatenation of another string
  */
@@ -581,52 +589,50 @@ void Md5::append(const DOMString &str)
     append((unsigned char *)str.c_str(), str.size());
 }
 
+
 /*
  * Final wrapup - pad to 64-byte boundary with the bit pattern
  * 1 0* (64-bit count of bits processed, MSB-first)
  */
 void Md5::finish(unsigned char *digest)
 {
-    // Compute number of bytes mod 64
-    unsigned int count = (bits[0] >> 3) & 0x3F;
-
-    // Set the first char of padding to 0x80.
-    // This is safe since there is always at least one byte free
-    unsigned char *p = in + count;
-    *p++ = 0x80;
-
-    // Bytes of padding needed to make 64 bytes
-    count = 64 - 1 - count;
-
-    // Pad out to 56 mod 64
-    if (count < 8)
-        {
-           // Two lots of padding:  Pad the first block to 64 bytes
-           md5_memset(p, 0, count);
-           //byteReverse(in, 16);
-           transform(buf, (unsigned long *) in);
-
-           // Now fill the next block with 56 bytes
-           md5_memset(in, 0, 56);
-        }
-    else
+    //snapshot the bit count now before padding
+    unsigned long nrBitsLo = (nrBytesLo << 3) & 0xffffffff;
+    unsigned long nrBitsHi = (nrBytesHi << 3) | ((nrBytesLo >> 29) & 7);
+
+    //Append terminal char
+    append(0x80);
+
+    //pad until we have a 56 of 64 bytes, allowing for 8 bytes at the end
+    while (longNr != 14)
+        append(0);
+
+    //##### Append length in bits
+    append((unsigned char)((nrBitsLo    ) & 0xff));
+    append((unsigned char)((nrBitsLo>> 8) & 0xff));
+    append((unsigned char)((nrBitsLo>>16) & 0xff));
+    append((unsigned char)((nrBitsLo>>24) & 0xff));
+    append((unsigned char)((nrBitsHi    ) & 0xff));
+    append((unsigned char)((nrBitsHi>> 8) & 0xff));
+    append((unsigned char)((nrBitsHi>>16) & 0xff));
+    append((unsigned char)((nrBitsHi>>24) & 0xff));
+
+    //copy out answer
+    int indx = 0;
+    for (int i=0 ; i<4 ; i++)
         {
-        // Pad block to 56 bytes
-        md5_memset(p, 0, count - 8);
+        digest[indx++] = (unsigned char)((hashBuf[i]      ) & 0xff);
+        digest[indx++] = (unsigned char)((hashBuf[i] >>  8) & 0xff);
+        digest[indx++] = (unsigned char)((hashBuf[i] >> 16) & 0xff);
+        digest[indx++] = (unsigned char)((hashBuf[i] >> 24) & 0xff);
         }
-    //byteReverse(in, 14);
-
-    // Append length in bits and transform
-    ((unsigned long *) in)[14] = bits[0];
-    ((unsigned long *) in)[15] = bits[1];
 
-    transform(buf, (unsigned long *) in);
-    //byteReverse((unsigned char *) buf, 4);
-    md5_memcpy(digest, buf, 16);
     init();  // Security!  ;-)
 }
 
-static char *md5hex = "0123456789abcdef";
+
+
+static const char *md5hex = "0123456789abcdef";
 
 DOMString Md5::finishHex()
 {
@@ -646,7 +652,8 @@ DOMString Md5::finishHex()
 
 //#  The four core functions - F1 is optimized somewhat
 
-//  #define F1(x, y, z) (x & y | ~x & z)
+// #define F1(x, y, z) (x & y | ~x & z)
+#define M(x) ((x) &= 0xffffffff)
 #define F1(x, y, z) (z ^ (x & (y ^ z)))
 #define F2(x, y, z) F1(z, x, y)
 #define F3(x, y, z) (x ^ y ^ z)
@@ -654,105 +661,101 @@ DOMString Md5::finishHex()
 
 // ## This is the central step in the MD5 algorithm.
 #define MD5STEP(f, w, x, y, z, data, s) \
-       ( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
+       ( w += (f(x, y, z) + data), M(w), w = w<<s | w>>(32-s), w += x, M(w) )
 
 /*
  * The core of the MD5 algorithm, this alters an existing MD5 hash to
  * reflect the addition of 16 longwords of new data.  MD5Update blocks
  * the data and converts bytes into longwords for this routine.
- * @parm buf points to an array of 4 unsigned longs
- * @parm in points to an array of 16 unsigned longs
+ * @parm buf points to an array of 4 unsigned 32bit (at least) integers
+ * @parm in points to an array of 16 unsigned 32bit (at least) integers
  */
-void Md5::transform(unsigned long *buf, unsigned long *in)
-{
-    unsigned long a = buf[0];
-    unsigned long b = buf[1];
-    unsigned long c = buf[2];
-    unsigned long d = buf[3];
-
-    MD5STEP(F1, a, b, c, d, in[ 0] + 0xd76aa478,  7);
-    MD5STEP(F1, d, a, b, c, in[ 1] + 0xe8c7b756, 12);
-    MD5STEP(F1, c, d, a, b, in[ 2] + 0x242070db, 17);
-    MD5STEP(F1, b, c, d, a, in[ 3] + 0xc1bdceee, 22);
-    MD5STEP(F1, a, b, c, d, in[ 4] + 0xf57c0faf,  7);
-    MD5STEP(F1, d, a, b, c, in[ 5] + 0x4787c62a, 12);
-    MD5STEP(F1, c, d, a, b, in[ 6] + 0xa8304613, 17);
-    MD5STEP(F1, b, c, d, a, in[ 7] + 0xfd469501, 22);
-    MD5STEP(F1, a, b, c, d, in[ 8] + 0x698098d8,  7);
-    MD5STEP(F1, d, a, b, c, in[ 9] + 0x8b44f7af, 12);
-    MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
-    MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
-    MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122,  7);
-    MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
-    MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
-    MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
-
-    MD5STEP(F2, a, b, c, d, in[ 1] + 0xf61e2562,  5);
-    MD5STEP(F2, d, a, b, c, in[ 6] + 0xc040b340,  9);
-    MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
-    MD5STEP(F2, b, c, d, a, in[ 0] + 0xe9b6c7aa, 20);
-    MD5STEP(F2, a, b, c, d, in[ 5] + 0xd62f105d,  5);
-    MD5STEP(F2, d, a, b, c, in[10] + 0x02441453,  9);
-    MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
-    MD5STEP(F2, b, c, d, a, in[ 4] + 0xe7d3fbc8, 20);
-    MD5STEP(F2, a, b, c, d, in[ 9] + 0x21e1cde6,  5);
-    MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6,  9);
-    MD5STEP(F2, c, d, a, b, in[ 3] + 0xf4d50d87, 14);
-    MD5STEP(F2, b, c, d, a, in[ 8] + 0x455a14ed, 20);
-    MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905,  5);
-    MD5STEP(F2, d, a, b, c, in[ 2] + 0xfcefa3f8,  9);
-    MD5STEP(F2, c, d, a, b, in[ 7] + 0x676f02d9, 14);
-    MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
-
-    MD5STEP(F3, a, b, c, d, in[ 5] + 0xfffa3942,  4);
-    MD5STEP(F3, d, a, b, c, in[ 8] + 0x8771f681, 11);
-    MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
-    MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
-    MD5STEP(F3, a, b, c, d, in[ 1] + 0xa4beea44,  4);
-    MD5STEP(F3, d, a, b, c, in[ 4] + 0x4bdecfa9, 11);
-    MD5STEP(F3, c, d, a, b, in[ 7] + 0xf6bb4b60, 16);
-    MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
-    MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6,  4);
-    MD5STEP(F3, d, a, b, c, in[ 0] + 0xeaa127fa, 11);
-    MD5STEP(F3, c, d, a, b, in[ 3] + 0xd4ef3085, 16);
-    MD5STEP(F3, b, c, d, a, in[ 6] + 0x04881d05, 23);
-    MD5STEP(F3, a, b, c, d, in[ 9] + 0xd9d4d039,  4);
-    MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
-    MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
-    MD5STEP(F3, b, c, d, a, in[ 2] + 0xc4ac5665, 23);
-
-    MD5STEP(F4, a, b, c, d, in[ 0] + 0xf4292244,  6);
-    MD5STEP(F4, d, a, b, c, in[ 7] + 0x432aff97, 10);
-    MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
-    MD5STEP(F4, b, c, d, a, in[ 5] + 0xfc93a039, 21);
-    MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3,  6);
-    MD5STEP(F4, d, a, b, c, in[ 3] + 0x8f0ccc92, 10);
-    MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
-    MD5STEP(F4, b, c, d, a, in[ 1] + 0x85845dd1, 21);
-    MD5STEP(F4, a, b, c, d, in[ 8] + 0x6fa87e4f,  6);
-    MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
-    MD5STEP(F4, c, d, a, b, in[ 6] + 0xa3014314, 15);
-    MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
-    MD5STEP(F4, a, b, c, d, in[ 4] + 0xf7537e82,  6);
-    MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
-    MD5STEP(F4, c, d, a, b, in[ 2] + 0x2ad7d2bb, 15);
-    MD5STEP(F4, b, c, d, a, in[ 9] + 0xeb86d391, 21);
-
-    buf[0] += a;
-    buf[1] += b;
-    buf[2] += c;
-    buf[3] += d;
+void Md5::transform()
+{
+    unsigned long *i = inBuf;
+    unsigned long a  = hashBuf[0];
+    unsigned long b  = hashBuf[1];
+    unsigned long c  = hashBuf[2];
+    unsigned long d  = hashBuf[3];
+
+    MD5STEP(F1, a, b, c, d, i[ 0] + 0xd76aa478,  7);
+    MD5STEP(F1, d, a, b, c, i[ 1] + 0xe8c7b756, 12);
+    MD5STEP(F1, c, d, a, b, i[ 2] + 0x242070db, 17);
+    MD5STEP(F1, b, c, d, a, i[ 3] + 0xc1bdceee, 22);
+    MD5STEP(F1, a, b, c, d, i[ 4] + 0xf57c0faf,  7);
+    MD5STEP(F1, d, a, b, c, i[ 5] + 0x4787c62a, 12);
+    MD5STEP(F1, c, d, a, b, i[ 6] + 0xa8304613, 17);
+    MD5STEP(F1, b, c, d, a, i[ 7] + 0xfd469501, 22);
+    MD5STEP(F1, a, b, c, d, i[ 8] + 0x698098d8,  7);
+    MD5STEP(F1, d, a, b, c, i[ 9] + 0x8b44f7af, 12);
+    MD5STEP(F1, c, d, a, b, i[10] + 0xffff5bb1, 17);
+    MD5STEP(F1, b, c, d, a, i[11] + 0x895cd7be, 22);
+    MD5STEP(F1, a, b, c, d, i[12] + 0x6b901122,  7);
+    MD5STEP(F1, d, a, b, c, i[13] + 0xfd987193, 12);
+    MD5STEP(F1, c, d, a, b, i[14] + 0xa679438e, 17);
+    MD5STEP(F1, b, c, d, a, i[15] + 0x49b40821, 22);
+
+    MD5STEP(F2, a, b, c, d, i[ 1] + 0xf61e2562,  5);
+    MD5STEP(F2, d, a, b, c, i[ 6] + 0xc040b340,  9);
+    MD5STEP(F2, c, d, a, b, i[11] + 0x265e5a51, 14);
+    MD5STEP(F2, b, c, d, a, i[ 0] + 0xe9b6c7aa, 20);
+    MD5STEP(F2, a, b, c, d, i[ 5] + 0xd62f105d,  5);
+    MD5STEP(F2, d, a, b, c, i[10] + 0x02441453,  9);
+    MD5STEP(F2, c, d, a, b, i[15] + 0xd8a1e681, 14);
+    MD5STEP(F2, b, c, d, a, i[ 4] + 0xe7d3fbc8, 20);
+    MD5STEP(F2, a, b, c, d, i[ 9] + 0x21e1cde6,  5);
+    MD5STEP(F2, d, a, b, c, i[14] + 0xc33707d6,  9);
+    MD5STEP(F2, c, d, a, b, i[ 3] + 0xf4d50d87, 14);
+    MD5STEP(F2, b, c, d, a, i[ 8] + 0x455a14ed, 20);
+    MD5STEP(F2, a, b, c, d, i[13] + 0xa9e3e905,  5);
+    MD5STEP(F2, d, a, b, c, i[ 2] + 0xfcefa3f8,  9);
+    MD5STEP(F2, c, d, a, b, i[ 7] + 0x676f02d9, 14);
+    MD5STEP(F2, b, c, d, a, i[12] + 0x8d2a4c8a, 20);
+
+    MD5STEP(F3, a, b, c, d, i[ 5] + 0xfffa3942,  4);
+    MD5STEP(F3, d, a, b, c, i[ 8] + 0x8771f681, 11);
+    MD5STEP(F3, c, d, a, b, i[11] + 0x6d9d6122, 16);
+    MD5STEP(F3, b, c, d, a, i[14] + 0xfde5380c, 23);
+    MD5STEP(F3, a, b, c, d, i[ 1] + 0xa4beea44,  4);
+    MD5STEP(F3, d, a, b, c, i[ 4] + 0x4bdecfa9, 11);
+    MD5STEP(F3, c, d, a, b, i[ 7] + 0xf6bb4b60, 16);
+    MD5STEP(F3, b, c, d, a, i[10] + 0xbebfbc70, 23);
+    MD5STEP(F3, a, b, c, d, i[13] + 0x289b7ec6,  4);
+    MD5STEP(F3, d, a, b, c, i[ 0] + 0xeaa127fa, 11);
+    MD5STEP(F3, c, d, a, b, i[ 3] + 0xd4ef3085, 16);
+    MD5STEP(F3, b, c, d, a, i[ 6] + 0x04881d05, 23);
+    MD5STEP(F3, a, b, c, d, i[ 9] + 0xd9d4d039,  4);
+    MD5STEP(F3, d, a, b, c, i[12] + 0xe6db99e5, 11);
+    MD5STEP(F3, c, d, a, b, i[15] + 0x1fa27cf8, 16);
+    MD5STEP(F3, b, c, d, a, i[ 2] + 0xc4ac5665, 23);
+
+    MD5STEP(F4, a, b, c, d, i[ 0] + 0xf4292244,  6);
+    MD5STEP(F4, d, a, b, c, i[ 7] + 0x432aff97, 10);
+    MD5STEP(F4, c, d, a, b, i[14] + 0xab9423a7, 15);
+    MD5STEP(F4, b, c, d, a, i[ 5] + 0xfc93a039, 21);
+    MD5STEP(F4, a, b, c, d, i[12] + 0x655b59c3,  6);
+    MD5STEP(F4, d, a, b, c, i[ 3] + 0x8f0ccc92, 10);
+    MD5STEP(F4, c, d, a, b, i[10] + 0xffeff47d, 15);
+    MD5STEP(F4, b, c, d, a, i[ 1] + 0x85845dd1, 21);
+    MD5STEP(F4, a, b, c, d, i[ 8] + 0x6fa87e4f,  6);
+    MD5STEP(F4, d, a, b, c, i[15] + 0xfe2ce6e0, 10);
+    MD5STEP(F4, c, d, a, b, i[ 6] + 0xa3014314, 15);
+    MD5STEP(F4, b, c, d, a, i[13] + 0x4e0811a1, 21);
+    MD5STEP(F4, a, b, c, d, i[ 4] + 0xf7537e82,  6);
+    MD5STEP(F4, d, a, b, c, i[11] + 0xbd3af235, 10);
+    MD5STEP(F4, c, d, a, b, i[ 2] + 0x2ad7d2bb, 15);
+    MD5STEP(F4, b, c, d, a, i[ 9] + 0xeb86d391, 21);
+
+    hashBuf[0] += a;
+    hashBuf[1] += b;
+    hashBuf[2] += c;
+    hashBuf[3] += d;
 }
 
 
 
 
 
-
-
-
-
-
 //########################################################################
 //########################################################################
 //### T H R E A D
@@ -888,9 +891,11 @@ TcpSocket::TcpSocket(const std::string &hostnameArg, int port)
 }
 
 
+
+
 #ifdef HAVE_SSL
 
-static void cryptoLockCallback(int mode, int type, const char *file, int line)
+static void cryptoLockCallback(int mode, int type, const char */*file*/, int /*line*/)
 {
     //printf("########### LOCK\n");
     static int modes[CRYPTO_NUM_LOCKS]; /* = {0, 0, ... } */
@@ -948,9 +953,9 @@ static void cryptoLockCallback(int mode, int type, const char *file, int line)
     err:
     if (errstr)
         {
-        /* we cannot use bio_err here */
-        fprintf(stderr, "openssl (lock_dbg_cb): %s (mode=%d, type=%d) at %s:%d\n",
-                errstr, mode, type, file, line);
+        //how do we pass a context pointer here?
+        //error("openssl (lock_dbg_cb): %s (mode=%d, type=%d) at %s:%d",
+        //        errstr, mode, type, file, line);
         }
 }
 
@@ -975,6 +980,27 @@ TcpSocket::TcpSocket(const TcpSocket &other)
     portno    = other.portno;
 }
 
+
+void TcpSocket::error(const char *fmt, ...)
+{
+    static char buf[256];
+    lastError = "TcpSocket err: ";
+    va_list args;
+    va_start(args, fmt);
+    vsnprintf(buf, 255, fmt, args);
+    va_end(args);
+    lastError.append(buf);
+    fprintf(stderr, "%s\n", lastError.c_str());
+}
+
+
+DOMString &TcpSocket::getLastError()
+{
+    return lastError;
+}
+
+
+
 static bool tcp_socket_inited = false;
 
 void TcpSocket::init()
@@ -987,12 +1013,15 @@ void TcpSocket::init()
         WSAStartup( wVersionRequested, &wsaData );
 #endif
 #ifdef HAVE_SSL
+       if (libssl_is_present)
+       {
         sslStream  = NULL;
         sslContext = NULL;
            CRYPTO_set_locking_callback(cryptoLockCallback);
         CRYPTO_set_id_callback(cryptoIdCallback);
         SSL_library_init();
         SSL_load_error_strings();
+       }
 #endif
         tcp_socket_inited = true;
         }
@@ -1019,7 +1048,12 @@ bool TcpSocket::isConnected()
 bool TcpSocket::getHaveSSL()
 {
 #ifdef HAVE_SSL
-    return true;
+    if (libssl_is_present)
+    {
+        return true;
+    } else {
+       return false;
+    }
 #else
     return false;
 #endif
@@ -1082,10 +1116,14 @@ static void infoCallback(const SSL *ssl, int where, int ret)
 bool TcpSocket::startTls()
 {
 #ifndef HAVE_SSL
-    fprintf(stderr,
-           "SSL starttls() error:  client not compiled with SSL enabled\n");
+    error("SSL starttls() error:  client not compiled with SSL enabled");
     return false;
 #else /*HAVE_SSL*/
+    if (!libssl_is_present)
+        {
+        error("SSL starttls() error:  the correct version of libssl was not found");
+        return false;
+        }
 
     sslStream  = NULL;
     sslContext = NULL;
@@ -1135,14 +1173,14 @@ bool TcpSocket::startTls()
     int ret = SSL_connect(sslStream);
     if (ret == 0)
         {
-        fprintf(stderr, "SSL connection not successful\n");
+        error("SSL connection not successful");
         disconnect();
         return false;
         }
     else if (ret < 0)
         {
         int err = SSL_get_error(sslStream, ret);
-        fprintf(stderr, "SSL connect error %d\n", err);
+        error("SSL connect error %d", err);
         disconnect();
         return false;
         }
@@ -1157,20 +1195,20 @@ bool TcpSocket::connect()
 {
     if (hostname.size()<1)
         {
-        fprintf(stderr, "open: null hostname\n");
+        error("open: null hostname");
         return false;
         }
 
     if (portno<1)
         {
-        fprintf(stderr, "open: bad port number\n");
+        error("open: bad port number");
         return false;
         }
 
     sock = socket(PF_INET, SOCK_STREAM, 0);
     if (sock < 0)
         {
-        fprintf(stderr, "open: error creating socket\n");
+        error("open: error creating socket");
         return false;
         }
 
@@ -1178,7 +1216,7 @@ bool TcpSocket::connect()
     struct hostent *server = gethostbyname(c_hostname);
     if (!server)
         {
-        fprintf(stderr, "open: could not locate host '%s'\n", c_hostname);
+        error("open: could not locate host '%s'", c_hostname);
         return false;
         }
 
@@ -1192,7 +1230,7 @@ bool TcpSocket::connect()
     int ret = ::connect(sock, (const sockaddr *)&serv_addr, sizeof(serv_addr));
     if (ret < 0)
         {
-        fprintf(stderr, "open: could not connect to host '%s'\n", c_hostname);
+        error("open: could not connect to host '%s'", c_hostname);
         return false;
         }
 
@@ -1210,6 +1248,8 @@ bool TcpSocket::disconnect()
     bool ret  = true;
     connected = false;
 #ifdef HAVE_SSL
+    if (libssl_is_present)
+    {
     if (sslEnabled)
         {
         if (sslStream)
@@ -1222,7 +1262,7 @@ bool TcpSocket::disconnect()
                 case 0:
                 case -1:
                 default:
-                    //printf("Shutdown failed");
+                    error("Shutdown failed");
                     ret = false;
                 }
             SSL_free(sslStream);
@@ -1232,6 +1272,7 @@ bool TcpSocket::disconnect()
         }
     sslStream  = NULL;
     sslContext = NULL;
+    }
 #endif /*HAVE_SSL*/
 
 #ifdef __WIN32__
@@ -1273,7 +1314,10 @@ long TcpSocket::available()
     if (count<=0 && sslEnabled)
         {
 #ifdef HAVE_SSL
-        return SSL_pending(sslStream);
+           if (libssl_is_present)
+               {
+            return SSL_pending(sslStream);
+               }
 #endif
         }
     return count;
@@ -1285,7 +1329,7 @@ bool TcpSocket::write(int ch)
 {
     if (!isConnected())
         {
-        fprintf(stderr, "write: socket closed\n");
+        error("write: socket closed");
         return false;
         }
     unsigned char c = (unsigned char)ch;
@@ -1293,16 +1337,19 @@ bool TcpSocket::write(int ch)
     if (sslEnabled)
         {
 #ifdef HAVE_SSL
+       if (libssl_is_present)
+       {
         int r = SSL_write(sslStream, &c, 1);
         if (r<=0)
             {
             switch(SSL_get_error(sslStream, r))
                 {
                 default:
-                    fprintf(stderr, "SSL write problem");
+                    error("SSL write problem");
                     return -1;
                 }
             }
+       }
 #endif
         }
     else
@@ -1310,7 +1357,7 @@ bool TcpSocket::write(int ch)
         if (send(sock, (const char *)&c, 1, 0) < 0)
         //if (send(sock, &c, 1, 0) < 0)
             {
-            fprintf(stderr, "write: could not send data\n");
+            error("write: could not send data");
             return false;
             }
         }
@@ -1321,7 +1368,7 @@ bool TcpSocket::write(char *str)
 {
    if (!isConnected())
         {
-        fprintf(stderr, "write(str): socket closed\n");
+        error("write(str): socket closed");
         return false;
         }
     int len = strlen(str);
@@ -1329,16 +1376,19 @@ bool TcpSocket::write(char *str)
     if (sslEnabled)
         {
 #ifdef HAVE_SSL
+       if (libssl_is_present)
+       {
         int r = SSL_write(sslStream, (unsigned char *)str, len);
         if (r<=0)
             {
             switch(SSL_get_error(sslStream, r))
                 {
                 default:
-                    fprintf(stderr, "SSL write problem");
+                    error("SSL write problem");
                     return -1;
                 }
             }
+       }
 #endif
         }
     else
@@ -1346,7 +1396,7 @@ bool TcpSocket::write(char *str)
         if (send(sock, str, len, 0) < 0)
         //if (send(sock, &c, 1, 0) < 0)
             {
-            fprintf(stderr, "write: could not send data\n");
+            error("write: could not send data");
             return false;
             }
         }
@@ -1388,6 +1438,8 @@ int TcpSocket::read()
     if (sslEnabled)
         {
 #ifdef HAVE_SSL
+       if (libssl_is_present)
+       {
         if (!sslStream)
             return -1;
         int r = SSL_read(sslStream, &ch, 1);
@@ -1399,21 +1451,22 @@ int TcpSocket::read()
             case SSL_ERROR_ZERO_RETURN:
                 return -1;
             case SSL_ERROR_SYSCALL:
-                fprintf(stderr, "SSL read problem(syscall) %s\n",
+                error("SSL read problem(syscall) %s",
                      ERR_error_string(ERR_get_error(), NULL));
                 return -1;
             default:
-                fprintf(stderr, "SSL read problem %s\n",
+                error("SSL read problem %s",
                      ERR_error_string(ERR_get_error(), NULL));
                 return -1;
             }
+       }
 #endif
         }
     else
         {
         if (recv(sock, (char *)&ch, 1, 0) <= 0)
             {
-            fprintf(stderr, "read: could not receive data\n");
+            error("read: could not receive data");
             disconnect();
             return -1;
             }