Index: /pjproject/trunk/pjlib-util/include/pjlib-util/hmac_md5.h
===================================================================
--- /pjproject/trunk/pjlib-util/include/pjlib-util/hmac_md5.h	(revision 1264)
+++ /pjproject/trunk/pjlib-util/include/pjlib-util/hmac_md5.h	(revision 1265)
@@ -30,4 +30,5 @@
 
 #include <pj/types.h>
+#include <pjlib-util/md5.h>
 
 PJ_BEGIN_DECL
@@ -41,4 +42,13 @@
  * for Message Authentication, as described in RFC 2104
  */
+
+/**
+ * The HMAC-MD5 context used in the incremental HMAC calculation.
+ */
+typedef struct pj_hmac_md5_context
+{
+    pj_md5_context  context;	/**< MD5 context	    */
+    pj_uint8_t	    k_opad[64];	/**< opad xor-ed with key   */
+} pj_hmac_md5_context;
 
 
@@ -58,4 +68,34 @@
 
 /**
+ * Initiate HMAC-MD5 context for incremental hashing.
+ *
+ * @param hctx		HMAC-MD5 context.
+ * @param key		Pointer to the authentication key.
+ * @param key_len	Length of the authentication key.
+ */
+PJ_DECL(void) pj_hmac_md5_init(pj_hmac_md5_context *hctx, 
+			       const pj_uint8_t *key, unsigned key_len);
+
+/**
+ * Append string to the message.
+ *
+ * @param hctx		HMAC-MD5 context.
+ * @param input		Pointer to the input stream.
+ * @param input_len	Length of input stream in bytes.
+ */
+PJ_DECL(void) pj_hmac_md5_update(pj_hmac_md5_context *hctx,
+				 const pj_uint8_t *input, 
+				 unsigned input_len);
+
+/**
+ * Finish the message and return the digest. 
+ *
+ * @param hctx		HMAC-MD5 context.
+ * @param digest	Buffer to be filled with HMAC MD5 digest.
+ */
+PJ_DECL(void) pj_hmac_md5_final(pj_hmac_md5_context *hctx,
+				pj_uint8_t digest[16]);
+
+/**
  * @}
  */
Index: /pjproject/trunk/pjlib-util/include/pjlib-util/hmac_sha1.h
===================================================================
--- /pjproject/trunk/pjlib-util/include/pjlib-util/hmac_sha1.h	(revision 1264)
+++ /pjproject/trunk/pjlib-util/include/pjlib-util/hmac_sha1.h	(revision 1265)
@@ -26,4 +26,5 @@
 
 #include <pj/types.h>
+#include <pjlib-util/sha1.h>
 
 PJ_BEGIN_DECL
@@ -35,10 +36,20 @@
  *
  * This module contains the implementation of HMAC: Keyed-Hashing 
- * for Message Authentication, as described in RFC 2104
+ * for Message Authentication, as described in RFC 2104.
  */
+
+/**
+ * The HMAC-SHA1 context used in the incremental HMAC calculation.
+ */
+typedef struct pj_hmac_sha1_context
+{
+    pj_sha1_context context;	/**< SHA1 context	    */
+    pj_uint8_t	    k_opad[64];	/**< opad xor-ed with key   */
+} pj_hmac_sha1_context;
 
 
 /**
- * Calculate HMAC SHA1 digest for the specified input and key.
+ * Calculate HMAC-SHA1 digest for the specified input and key with this
+ * single function call.
  *
  * @param input		Pointer to the input stream.
@@ -54,4 +65,35 @@
 
 /**
+ * Initiate HMAC-SHA1 context for incremental hashing.
+ *
+ * @param hctx		HMAC-SHA1 context.
+ * @param key		Pointer to the authentication key.
+ * @param key_len	Length of the authentication key.
+ */
+PJ_DECL(void) pj_hmac_sha1_init(pj_hmac_sha1_context *hctx, 
+			        const pj_uint8_t *key, unsigned key_len);
+
+/**
+ * Append string to the message.
+ *
+ * @param hctx		HMAC-SHA1 context.
+ * @param input		Pointer to the input stream.
+ * @param input_len	Length of input stream in bytes.
+ */
+PJ_DECL(void) pj_hmac_sha1_update(pj_hmac_sha1_context *hctx,
+				  const pj_uint8_t *input, 
+				  unsigned input_len);
+
+/**
+ * Finish the message and return the digest. 
+ *
+ * @param hctx		HMAC-SHA1 context.
+ * @param digest	Buffer to be filled with HMAC SHA1 digest.
+ */
+PJ_DECL(void) pj_hmac_sha1_final(pj_hmac_sha1_context *hctx,
+				 pj_uint8_t digest[20]);
+
+
+/**
  * @}
  */
Index: /pjproject/trunk/pjlib-util/src/pjlib-util/hmac_md5.c
===================================================================
--- /pjproject/trunk/pjlib-util/src/pjlib-util/hmac_md5.c	(revision 1264)
+++ /pjproject/trunk/pjlib-util/src/pjlib-util/hmac_md5.c	(revision 1265)
@@ -17,18 +17,12 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
  */
-#include <pjlib-util/md5.h>
+#include <pjlib-util/hmac_md5.h>
 #include <pj/string.h>
 
 
-/* This code is taken from RFC 2104 */
-
-
-PJ_DEF(void) pj_hmac_md5( const pj_uint8_t *input, unsigned input_len, 
-			  const pj_uint8_t *key, unsigned key_len, 
-			  pj_uint8_t digest[16] )
+PJ_DEF(void) pj_hmac_md5_init(pj_hmac_md5_context *hctx, 
+			      const pj_uint8_t *key, unsigned key_len)
 {
-    pj_md5_context context;
-    pj_uint8_t k_ipad[65];
-    pj_uint8_t k_opad[65];
+    pj_uint8_t k_ipad[64];
     pj_uint8_t tk[16];
     int i;
@@ -46,30 +40,57 @@
     }
 
+    /*
+     * HMAC = H(K XOR opad, H(K XOR ipad, text))
+     */
+
     /* start out by storing key in pads */
     pj_bzero( k_ipad, sizeof(k_ipad));
-    pj_bzero( k_opad, sizeof(k_opad));
+    pj_bzero( hctx->k_opad, sizeof(hctx->k_opad));
     pj_memcpy( k_ipad, key, key_len);
-    pj_memcpy( k_opad, key, key_len);
+    pj_memcpy( hctx->k_opad, key, key_len);
 
     /* XOR key with ipad and opad values */
     for (i=0; i<64; i++) {
         k_ipad[i] ^= 0x36;
-        k_opad[i] ^= 0x5c;
+        hctx->k_opad[i] ^= 0x5c;
     }
     /*
      * perform inner MD5
      */
-    pj_md5_init(&context);
-    pj_md5_update(&context, k_ipad, 64);
-    pj_md5_update(&context, input, input_len);
-    pj_md5_final(&context, digest);
+    pj_md5_init(&hctx->context);
+    pj_md5_update(&hctx->context, k_ipad, 64);
+
+}
+
+PJ_DEF(void) pj_hmac_md5_update(pj_hmac_md5_context *hctx,
+				 const pj_uint8_t *input, 
+				 unsigned input_len)
+{
+    pj_md5_update(&hctx->context, input, input_len);
+}
+
+PJ_DEF(void) pj_hmac_md5_final(pj_hmac_md5_context *hctx,
+				pj_uint8_t digest[16])
+{
+    pj_md5_final(&hctx->context, digest);
 
     /*
      * perform outer MD5
      */
-    pj_md5_init(&context);
-    pj_md5_update(&context, k_opad, 64);
-    pj_md5_update(&context, digest, 16);
-    pj_md5_final(&context, digest);
+    pj_md5_init(&hctx->context);
+    pj_md5_update(&hctx->context, hctx->k_opad, 64);
+    pj_md5_update(&hctx->context, digest, 16);
+    pj_md5_final(&hctx->context, digest);
 }
 
+PJ_DEF(void) pj_hmac_md5( const pj_uint8_t *input, unsigned input_len, 
+			  const pj_uint8_t *key, unsigned key_len, 
+			  pj_uint8_t digest[16] )
+{
+    pj_hmac_md5_context ctx;
+
+    pj_hmac_md5_init(&ctx, key, key_len);
+    pj_hmac_md5_update(&ctx, input, input_len);
+    pj_hmac_md5_final(&ctx, digest);
+}
+
Index: /pjproject/trunk/pjlib-util/src/pjlib-util/hmac_sha1.c
===================================================================
--- /pjproject/trunk/pjlib-util/src/pjlib-util/hmac_sha1.c	(revision 1264)
+++ /pjproject/trunk/pjlib-util/src/pjlib-util/hmac_sha1.c	(revision 1265)
@@ -18,17 +18,13 @@
  */
 #include <pjlib-util/hmac_sha1.h>
-#include <pjlib-util/sha1.h>
 #include <pj/string.h>
 
 
-PJ_DEF(void) pj_hmac_sha1(const pj_uint8_t *input, unsigned input_len, 
-			  const pj_uint8_t *key, unsigned key_len, 
-			  pj_uint8_t digest[20] )
+PJ_DEF(void) pj_hmac_sha1_init(pj_hmac_sha1_context *hctx, 
+			       const pj_uint8_t *key, unsigned key_len)
 {
-    pj_sha1_context context;
-    pj_uint8_t k_ipad[65];
-    pj_uint8_t k_opad[65];
+    pj_uint8_t k_ipad[64];
     pj_uint8_t tk[20];
-    int i;
+    unsigned i;
 
     /* if key is longer than 64 bytes reset it to key=SHA1(key) */
@@ -44,31 +40,55 @@
     }
 
+    /*
+     * HMAC = H(K XOR opad, H(K XOR ipad, text))
+     */
+
     /* start out by storing key in pads */
     pj_bzero( k_ipad, sizeof(k_ipad));
-    pj_bzero( k_opad, sizeof(k_opad));
+    pj_bzero( hctx->k_opad, sizeof(hctx->k_opad));
     pj_memcpy( k_ipad, key, key_len);
-    pj_memcpy( k_opad, key, key_len);
+    pj_memcpy( hctx->k_opad, key, key_len);
 
     /* XOR key with ipad and opad values */
     for (i=0; i<64; i++) {
         k_ipad[i] ^= 0x36;
-        k_opad[i] ^= 0x5c;
+        hctx->k_opad[i] ^= 0x5c;
     }
     /*
      * perform inner SHA1
      */
-    pj_sha1_init(&context);
-    pj_sha1_update(&context, k_ipad, 64);
-    pj_sha1_update(&context, input, input_len);
-    pj_sha1_final(&context, digest);
+    pj_sha1_init(&hctx->context);
+    pj_sha1_update(&hctx->context, k_ipad, 64);
+}
+
+PJ_DEF(void) pj_hmac_sha1_update(pj_hmac_sha1_context *hctx,
+				 const pj_uint8_t *input, unsigned input_len)
+{
+    pj_sha1_update(&hctx->context, input, input_len);
+}
+
+PJ_DEF(void) pj_hmac_sha1_final(pj_hmac_sha1_context *hctx,
+				pj_uint8_t digest[20])
+{
+    pj_sha1_final(&hctx->context, digest);
 
     /*
      * perform outer SHA1
      */
-    pj_sha1_init(&context);
-    pj_sha1_update(&context, k_opad, 64);
-    pj_sha1_update(&context, digest, 20);
-    pj_sha1_final(&context, digest);
+    pj_sha1_init(&hctx->context);
+    pj_sha1_update(&hctx->context, hctx->k_opad, 64);
+    pj_sha1_update(&hctx->context, digest, 20);
+    pj_sha1_final(&hctx->context, digest);
 }
 
+PJ_DEF(void) pj_hmac_sha1(const pj_uint8_t *input, unsigned input_len, 
+			  const pj_uint8_t *key, unsigned key_len, 
+			  pj_uint8_t digest[20] )
+{
+    pj_hmac_sha1_context ctx;
 
+    pj_hmac_sha1_init(&ctx, key, key_len);
+    pj_hmac_sha1_update(&ctx, input, input_len);
+    pj_hmac_sha1_final(&ctx, digest);
+}
+
Index: /pjproject/trunk/pjnath/src/pjnath/stun_auth.c
===================================================================
--- /pjproject/trunk/pjnath/src/pjnath/stun_auth.c	(revision 1264)
+++ /pjproject/trunk/pjnath/src/pjnath/stun_auth.c	(revision 1265)
@@ -120,4 +120,5 @@
     const pj_stun_realm_attr *arealm;
     const pj_stun_realm_attr *anonce;
+    pj_hmac_sha1_context ctx;
     pj_uint8_t digest[PJ_SHA1_DIGEST_SIZE];
     pj_uint8_t md5_digest[16];
@@ -328,6 +329,15 @@
     }
 
-    /* Now calculate HMAC of the message */
-    pj_hmac_sha1(pkt, amsgi_pos, (pj_uint8_t*)key.ptr, key.slen, digest);
+    /* Now calculate HMAC of the message, adding zero padding if necessary
+     * to make the input 64 bytes aligned.
+     */
+    pj_hmac_sha1_init(&ctx, (pj_uint8_t*)key.ptr, key.slen);
+    pj_hmac_sha1_update(&ctx, pkt, amsgi_pos);
+    if (amsgi_pos & 0x3F) {
+	pj_uint8_t zeroes[64];
+	pj_bzero(zeroes, sizeof(zeroes));
+	pj_hmac_sha1_update(&ctx, zeroes, 64-(amsgi_pos & 0x3F));
+    }
+    pj_hmac_sha1_final(&ctx, digest);
 
     /* Compare HMACs */
Index: /pjproject/trunk/pjnath/src/pjnath/stun_msg.c
===================================================================
--- /pjproject/trunk/pjnath/src/pjnath/stun_msg.c	(revision 1264)
+++ /pjproject/trunk/pjnath/src/pjnath/stun_msg.c	(revision 1265)
@@ -2140,4 +2140,5 @@
 
 	pj_uint8_t md5_key_buf[16];
+	pj_hmac_sha1_context ctx;
 	pj_str_t key;
 
@@ -2182,8 +2183,15 @@
 	}
 
-	/* Calculate HMAC-SHA1 digest */
-	pj_hmac_sha1((pj_uint8_t*)start, buf-start, 
-		     (pj_uint8_t*)key.ptr, key.slen,
-		     amsgint->hmac);
+	/* Calculate HMAC-SHA1 digest, add zero padding to input
+	 * if necessary to make the input 64 bytes aligned.
+	 */
+	pj_hmac_sha1_init(&ctx, (pj_uint8_t*)key.ptr, key.slen);
+	pj_hmac_sha1_update(&ctx, (pj_uint8_t*)start, buf-start);
+	if ((buf-start) & 0x3F) {
+	    pj_uint8_t zeroes[64];
+	    pj_bzero(zeroes, sizeof(zeroes));
+	    pj_hmac_sha1_update(&ctx, zeroes, 64-((buf-start) & 0x3F));
+	}
+	pj_hmac_sha1_final(&ctx, amsgint->hmac);
 
 	/* Put this attribute in the message */
