md5 hash files aren't currently portable between EBCDIC and ASCII machines,
 (sha is, and the initial work to make md5 portable is there).

md5 hash files created using htpasswd -cm are not portable, i.e. you can not create them on an EBCDIC platform,  move them to an ASCII platform and get them to work successfully.
This is true for both apr-util 1.2.8  and earlier versions.

There does not appear to be any installed EBCDIC base that would require a compatability option to generate the current hash.
(These changes do not affect the hash created on ASCII in anyway)

patch does following:

1) The context->xlate field needs to be initialized in both contexts for the apr_xlate_conv_buffer to occur.
2) the apr_xlate_conv_buffer needs to be skipped not just for apr_md5_final as is done now,
    but also when final is passed into apr_md5_update.



Index: apr_md5.c
===================================================================
--- apr_md5.c    (revision 573406)
+++ apr_md5.c    (working copy)
@@ -112,6 +112,8 @@
 #if APR_CHARSET_EBCDIC
 static apr_xlate_t *xlate_ebcdic_to_ascii; /* used in apr_md5_encode() */
 #endif
+#define DO_XLATE 0
+#define SKIP_XLATE 1
 
 /* F, G, H and I are basic MD5 functions.
  */
@@ -195,9 +197,10 @@
  * operation, processing another message block, and updating the
  * context.
  */
-APU_DECLARE(apr_status_t) apr_md5_update(apr_md5_ctx_t *context,
-                                         const void *_input,
-                                         apr_size_t inputLen)
+static apr_status_t md5_update_buffer(apr_md5_ctx_t *context,
+                               const void *_input,
+                               apr_size_t inputLen,
+                               int xlate_buffer)
 {
     const unsigned char *input = _input;
     unsigned int i, idx, partLen;
@@ -234,7 +237,7 @@
     memcpy(&context->buffer[idx], &input[i], inputLen - i);
 #else /*APR_HAS_XLATE*/
     if (inputLen >= partLen) {
-        if (context->xlate) {
+        if (context->xlate && (xlate_buffer == DO_XLATE)) {
             inbytes_left = outbytes_left = partLen;
             apr_xlate_conv_buffer(context->xlate, (const char *)input,
                                   &inbytes_left,
@@ -247,7 +250,7 @@
         MD5Transform(context->state, context->buffer);
 
         for (i = partLen; i + 63 < inputLen; i += 64) {
-            if (context->xlate) {
+            if (context->xlate && (xlate_buffer == DO_XLATE)) {
                 unsigned char inp_tmp[64];
                 inbytes_left = outbytes_left = 64;
                 apr_xlate_conv_buffer(context->xlate, (const char *)&input[i],
@@ -266,7 +269,7 @@
         i = 0;
 
     /* Buffer remaining input */
-    if (context->xlate) {
+    if (context->xlate && (xlate_buffer == DO_XLATE)) {
         inbytes_left = outbytes_left = inputLen - i;
         apr_xlate_conv_buffer(context->xlate, (const char *)&input[i],
                               &inbytes_left, (char *)&context->buffer[idx],
@@ -279,6 +282,16 @@
     return APR_SUCCESS;
 }
 
+/* MD5 block update operation. API with the default setting
+ * for EBCDIC translations
+ */ 
+APU_DECLARE(apr_status_t) apr_md5_update(apr_md5_ctx_t *context,
+                                         const void *_input,
+                                         apr_size_t inputLen)
+{
+    md5_update_buffer( context, _input, inputLen, DO_XLATE);
+}
+
 /* MD5 finalization. Ends an MD5 message-digest operation, writing the
  * the message digest and zeroizing the context.
  */
@@ -553,13 +566,14 @@
      * Then just as many characters of the MD5(pw, salt, pw)
      */
     apr_md5_init(&ctx1);
+    apr_md5_set_xlate(&ctx1, xlate_ebcdic_to_ascii);
     apr_md5_update(&ctx1, pw, strlen(pw));
     apr_md5_update(&ctx1, sp, sl);
     apr_md5_update(&ctx1, pw, strlen(pw));
     apr_md5_final(final, &ctx1);
     for (pl = strlen(pw); pl > 0; pl -= APR_MD5_DIGESTSIZE) {
-        apr_md5_update(&ctx, final,
-                      (pl > APR_MD5_DIGESTSIZE) ? APR_MD5_DIGESTSIZE : pl);
+        md5_update_buffer(&ctx, final,
+                      (pl > APR_MD5_DIGESTSIZE) ? APR_MD5_DIGESTSIZE : pl, SKIP_XLATE);
     }
 
     /*
@@ -572,7 +586,7 @@
      */
     for (i = strlen(pw); i != 0; i >>= 1) {
         if (i & 1) {
-            apr_md5_update(&ctx, final, 1);
+            md5_update_buffer(&ctx, final, 1, SKIP_XLATE);
         }
         else {
             apr_md5_update(&ctx, pw, 1);
@@ -596,11 +610,16 @@
      */
     for (i = 0; i < 1000; i++) {
         apr_md5_init(&ctx1);
+         /*
+          * apr_md5_final clears out ctx1.xlate at the end of each loop,
+          * so need to to set it each time through
+          */
+        apr_md5_set_xlate(&ctx1, xlate_ebcdic_to_ascii);
         if (i & 1) {
             apr_md5_update(&ctx1, pw, strlen(pw));
         }
         else {
-            apr_md5_update(&ctx1, final, APR_MD5_DIGESTSIZE);
+            md5_update_buffer(&ctx1, final, APR_MD5_DIGESTSIZE, SKIP_XLATE);
         }
         if (i % 3) {
             apr_md5_update(&ctx1, sp, sl);
@@ -611,7 +630,7 @@
         }
 
         if (i & 1) {
-            apr_md5_update(&ctx1, final, APR_MD5_DIGESTSIZE);
+            md5_update_buffer(&ctx1, final, APR_MD5_DIGESTSIZE, SKIP_XLATE);
         }
         else {
             apr_md5_update(&ctx1, pw, strlen(pw));