You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@directory.apache.org by dr...@apache.org on 2015/01/12 14:06:44 UTC

[36/50] [abbrv] directory-kerberos git commit: Some clearance

Some clearance


Project: http://git-wip-us.apache.org/repos/asf/directory-kerberos/repo
Commit: http://git-wip-us.apache.org/repos/asf/directory-kerberos/commit/d0c6e321
Tree: http://git-wip-us.apache.org/repos/asf/directory-kerberos/tree/d0c6e321
Diff: http://git-wip-us.apache.org/repos/asf/directory-kerberos/diff/d0c6e321

Branch: refs/heads/master
Commit: d0c6e32143b59a6276f9b710b1e5fe6554b4b7ec
Parents: 0d0acfa
Author: Drankye <dr...@gmail.com>
Authored: Fri Dec 26 07:13:52 2014 +0800
Committer: Drankye <dr...@gmail.com>
Committed: Fri Dec 26 07:13:52 2014 +0800

----------------------------------------------------------------------
 .../apache/kerberos/kerb/crypto/Camellia.java   |   2 +
 .../kerberos/kerb/crypto/CamelliaKey.java       |   2 +
 .../org/apache/kerberos/kerb/crypto/Crc32.java  | 120 ++---
 .../org/apache/kerberos/kerb/crypto/Md4.java    | 490 +++++++++++--------
 4 files changed, 324 insertions(+), 290 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/d0c6e321/haox-kerb/kerb-crypto/src/main/java/org/apache/kerberos/kerb/crypto/Camellia.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-crypto/src/main/java/org/apache/kerberos/kerb/crypto/Camellia.java b/haox-kerb/kerb-crypto/src/main/java/org/apache/kerberos/kerb/crypto/Camellia.java
index 232f70c..89db740 100644
--- a/haox-kerb/kerb-crypto/src/main/java/org/apache/kerberos/kerb/crypto/Camellia.java
+++ b/haox-kerb/kerb-crypto/src/main/java/org/apache/kerberos/kerb/crypto/Camellia.java
@@ -2,6 +2,8 @@ package org.apache.kerberos.kerb.crypto;
 
 /**
  * Camellia - based on RFC 3713, about half the size of CamelliaEngine.
+ *
+ * This is based on CamelliaEngine.java from bouncycastle library.
  */
 
 public class Camellia {

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/d0c6e321/haox-kerb/kerb-crypto/src/main/java/org/apache/kerberos/kerb/crypto/CamelliaKey.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-crypto/src/main/java/org/apache/kerberos/kerb/crypto/CamelliaKey.java b/haox-kerb/kerb-crypto/src/main/java/org/apache/kerberos/kerb/crypto/CamelliaKey.java
index 72354a8..f31085e 100644
--- a/haox-kerb/kerb-crypto/src/main/java/org/apache/kerberos/kerb/crypto/CamelliaKey.java
+++ b/haox-kerb/kerb-crypto/src/main/java/org/apache/kerberos/kerb/crypto/CamelliaKey.java
@@ -2,6 +2,8 @@ package org.apache.kerberos.kerb.crypto;
 
 /**
  * Camellia - based on RFC 3713, about half the size of CamelliaEngine.
+ *
+ * This is based on CamelliaEngine.java from bouncycastle library.
  */
 
 public class CamelliaKey {

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/d0c6e321/haox-kerb/kerb-crypto/src/main/java/org/apache/kerberos/kerb/crypto/Crc32.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-crypto/src/main/java/org/apache/kerberos/kerb/crypto/Crc32.java b/haox-kerb/kerb-crypto/src/main/java/org/apache/kerberos/kerb/crypto/Crc32.java
index 52441c8..2c9f600 100644
--- a/haox-kerb/kerb-crypto/src/main/java/org/apache/kerberos/kerb/crypto/Crc32.java
+++ b/haox-kerb/kerb-crypto/src/main/java/org/apache/kerberos/kerb/crypto/Crc32.java
@@ -1,99 +1,59 @@
 package org.apache.kerberos.kerb.crypto;
 
+/**
+ * Reference: http://introcs.cs.princeton.edu/java/51data/CRC32.java
+ */
 public class Crc32 {
 
-    private static long[] crcTable = {
-            0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
-            0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
-            0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
-            0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
-            0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
-            0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
-            0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
-            0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
-            0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
-            0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
-            0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
-            0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
-            0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
-            0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
-            0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
-            0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
-            0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
-            0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
-            0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
-            0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
-            0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
-            0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
-            0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
-            0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
-            0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
-            0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
-            0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
-            0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
-            0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
-            0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
-            0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
-            0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
-            0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
-            0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
-            0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
-            0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
-            0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
-            0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
-            0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
-            0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
-            0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
-            0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
-            0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
-            0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
-            0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
-            0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
-            0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
-            0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
-            0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
-            0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
-            0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
-            0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
-            0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
-            0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
-            0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
-            0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
-            0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
-            0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
-            0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
-            0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
-            0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
-            0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
-            0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
-            0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+    private static long[] table = {
+            0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+            0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+            0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+            0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+            0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+            0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+            0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+            0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+            0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+            0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+            0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+            0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+            0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+            0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+            0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+            0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+            0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+            0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+            0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+            0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+            0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+            0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+            0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+            0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+            0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+            0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+            0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+            0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+            0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+            0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+            0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+            0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
     };
 
     public static byte[] crc(byte[] data, int start, int size) {
         long c = crc(0, data, start, size);
-        return convert((int) c);
+        return BytesUtil.int2bytes((int) c, false);
     }
 
-    public static long crc(long seed, byte[] data, int start, int len) {
-        long c = seed;
+    public static long crc(long initial, byte[] data, int start, int len) {
+        long c = initial;
 
         int idx;
         for (int i = 0; i < len; i++) {
             idx = (int) ((data[start + i] ^ c) & 0xff);
-            c = ((c & 0xffffffffL) >>> 8) ^ crcTable[idx]; // why?
+            c = ((c & 0xffffffffL) >>> 8) ^ table[idx]; // why?
         }
 
         return c;
     }
-
-    private static byte[] convert(int val) {
-        byte[] p = new byte[4];
-
-        p[3] = (byte) ((val >> 24) & 0xff);
-        p[2] = (byte) ((val >> 16) & 0xff);
-        p[1] = (byte) ((val >>  8) & 0xff);
-        p[0] = (byte) ((val      ) & 0xff);
-
-        return p;
-    }
 }

http://git-wip-us.apache.org/repos/asf/directory-kerberos/blob/d0c6e321/haox-kerb/kerb-crypto/src/main/java/org/apache/kerberos/kerb/crypto/Md4.java
----------------------------------------------------------------------
diff --git a/haox-kerb/kerb-crypto/src/main/java/org/apache/kerberos/kerb/crypto/Md4.java b/haox-kerb/kerb-crypto/src/main/java/org/apache/kerberos/kerb/crypto/Md4.java
index 7f72058..5877234 100644
--- a/haox-kerb/kerb-crypto/src/main/java/org/apache/kerberos/kerb/crypto/Md4.java
+++ b/haox-kerb/kerb-crypto/src/main/java/org/apache/kerberos/kerb/crypto/Md4.java
@@ -1,269 +1,339 @@
-package org.apache.kerberos.kerb.crypto;
-
-//http://www.java2s.com/Code/Java/Security/ImplementstheMD4messagedigestalgorithminJava.htm
-
 /*
- * Copyright (c) 1997 Systemics Ltd
- * on behalf of the Cryptix Development Team.  All rights reserved.
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
  */
+package org.apache.kerberos.kerb.crypto;
 
+import java.security.DigestException;
 import java.security.MessageDigest;
+import java.security.MessageDigestSpi;
 
 /**
- * Implements the MD4 message digest algorithm in Java.
- * <p>
- * <b>References:</b>
- * <ol>
- *   <li> Ronald L. Rivest,
- *        "<a href="http://www.roxen.com/rfc/rfc1320.html">
- *        The MD4 Message-Digest Algorithm</a>",
- *        IETF RFC-1320 (informational).
- * </ol>
+ * MD4.java - An implementation of Ron Rivest's MD4 message digest algorithm.
+ * The MD4 algorithm is designed to be quite fast on 32-bit machines. In
+ * addition, the MD4 algorithm does not require any large substitution
+ * tables.
+ *
+ * @see The <a href="http://www.ietf.org/rfc/rfc1320.txt">MD4</a> Message-
+ *    Digest Algorithm by R. Rivest.
  *
- * <p><b>$Revision: 1.2 $</b>
- * @author  Raif S. Naffah
+ * @author <a href="http://mina.apache.org">Apache MINA Project</a>
+ * @since MINA 2.0.0-M3
+ */
+
+/**
+ * Copied from Mina project and modified a bit
  */
-public  class Md4 extends MessageDigest implements Cloneable
-{
+public class Md4 extends MessageDigest {
+
     /**
-     * The size in bytes of the input block to the tranformation algorithm.
+     * The MD4 algorithm message digest length is 16 bytes wide.
      */
-    private static final int BLOCK_LENGTH = 64;       //    = 512 / 8;
+    public static final int BYTE_DIGEST_LENGTH = 16;
 
     /**
-     * 4 32-bit words (interim result)
+     * The MD4 algorithm block length is 64 bytes wide.
      */
-    private int[] context = new int[4];
+    public static final int BYTE_BLOCK_LENGTH = 64;
 
     /**
-     * Number of bytes processed so far mod. 2 power of 64.
+     * The initial values of the four registers. RFC gives the values 
+     * in LE so we converted it as JAVA uses BE endianness.
      */
-    private long count;
+    private final static int A = 0x67452301;
+
+    private final static int B = 0xefcdab89;
+
+    private final static int C = 0x98badcfe;
+
+    private final static int D = 0x10325476;
 
     /**
-     * 512 bits input buffer = 16 x 32-bit words holds until reaches 512 bits.
+     * The four registers initialized with the above IVs.
      */
-    private byte[] buffer = new byte[BLOCK_LENGTH];
+    private int a = A;
+
+    private int b = B;
+
+    private int c = C;
+
+    private int d = D;
 
     /**
-     * 512 bits work buffer = 16 x 32-bit words
+     * Counts the total length of the data being digested.
      */
-    private int[] X = new int[16];
+    private long msgLength;
 
+    /**
+     * The internal buffer is {@link BLOCK_LENGTH} wide.
+     */
+    private final byte[] buffer = new byte[BYTE_BLOCK_LENGTH];
+
+    /**
+     * Default constructor.
+     */
     public Md4() {
         super("MD4");
         engineReset();
     }
 
     /**
-     *    This constructor is here to implement cloneability of this class.
+     * Returns the digest length in bytes.
+     *
+     * @return the digest length in bytes.
      */
-    private Md4(Md4 md) {
-        this();
-        context = (int[])md.context.clone();
-        buffer = (byte[])md.buffer.clone();
-        count = md.count;
+    protected int engineGetDigestLength() {
+        return BYTE_DIGEST_LENGTH;
     }
 
     /**
-     * Returns a copy of this MD object.
-     */
-    public Object clone() { return new Md4(this); }
-
-    /**
-     * Resets this object disregarding any temporary data present at the
-     * time of the invocation of this call.
+     * {@inheritDoc}
      */
-    public void engineReset () {
-        // initial values of MD4 i.e. A, B, C, D
-        // as per rfc-1320; they are low-order byte first
-        context[0] = 0x67452301;
-        context[1] = 0xEFCDAB89;
-        context[2] = 0x98BADCFE;
-        context[3] = 0x10325476;
-        count = 0L;
-        for (int i = 0; i < BLOCK_LENGTH; i++)
-            buffer[i] = 0;
+    protected void engineUpdate(byte b) {
+        int pos = (int) (msgLength % BYTE_BLOCK_LENGTH);
+        buffer[pos] = b;
+        msgLength++;
+
+        // If buffer contains enough data then process it.
+        if (pos == (BYTE_BLOCK_LENGTH - 1)) {
+            process(buffer, 0);
+        }
     }
 
     /**
-     * Continues an MD4 message digest using the input byte.
+     * {@inheritDoc}
      */
-    public void engineUpdate (byte b) {
-        // compute number of bytes still unhashed; ie. present in buffer
-        int i = (int)(count % BLOCK_LENGTH);
-        count++;                                        // update number of bytes
-        buffer[i] = b;
-        if (i == BLOCK_LENGTH - 1)
-            transform(buffer, 0);
+    protected void engineUpdate(byte[] b, int offset, int len) {
+        int pos = (int) (msgLength % BYTE_BLOCK_LENGTH);
+        int nbOfCharsToFillBuf = BYTE_BLOCK_LENGTH - pos;
+        int blkStart = 0;
+
+        msgLength += len;
+
+        // Process each full block
+        if (len >= nbOfCharsToFillBuf) {
+            System.arraycopy(b, offset, buffer, pos, nbOfCharsToFillBuf);
+            process(buffer, 0);
+            for (blkStart = nbOfCharsToFillBuf; blkStart + BYTE_BLOCK_LENGTH - 1 < len; blkStart += BYTE_BLOCK_LENGTH) {
+                process(b, offset + blkStart);
+            }
+            pos = 0;
+        }
+
+        // Fill buffer with the remaining data
+        if (blkStart < len) {
+            System.arraycopy(b, offset + blkStart, buffer, pos, len - blkStart);
+        }
     }
 
     /**
-     * MD4 block update operation.
-     * <p>
-     * Continues an MD4 message digest operation, by filling the buffer,
-     * transform(ing) data in 512-bit message block(s), updating the variables
-     * context and count, and leaving (buffering) the remaining bytes in buffer
-     * for the next update or finish.
-     *
-     * @param    input    input block
-     * @param    offset    start of meaningful bytes in input
-     * @param    len        count of bytes in input block to consider
+     * {@inheritDoc}
      */
-    public void engineUpdate (byte[] input, int offset, int len) {
-        // make sure we don't exceed input's allocated size/length
-        if (offset < 0 || len < 0 || (long)offset + len > input.length)
-            throw new ArrayIndexOutOfBoundsException();
-
-        // compute number of bytes still unhashed; ie. present in buffer
-        int bufferNdx = (int)(count % BLOCK_LENGTH);
-        count += len;                                        // update number of bytes
-        int partLen = BLOCK_LENGTH - bufferNdx;
-        int i = 0;
-        if (len >= partLen) {
-            System.arraycopy(input, offset, buffer, bufferNdx, partLen);
+    protected byte[] engineDigest() {
+        byte[] p = pad();
+        engineUpdate(p, 0, p.length);
+        byte[] digest = { (byte) a, (byte) (a >>> 8), (byte) (a >>> 16), (byte) (a >>> 24), (byte) b, (byte) (b >>> 8),
+                (byte) (b >>> 16), (byte) (b >>> 24), (byte) c, (byte) (c >>> 8), (byte) (c >>> 16), (byte) (c >>> 24),
+                (byte) d, (byte) (d >>> 8), (byte) (d >>> 16), (byte) (d >>> 24) };
 
+        engineReset();
 
-            transform(buffer, 0);
+        return digest;
+    }
 
-            for (i = partLen; i + BLOCK_LENGTH - 1 < len; i+= BLOCK_LENGTH)
-                transform(input, offset + i);
-            bufferNdx = 0;
+    /**
+     * {@inheritDoc}
+     */
+    protected int engineDigest(byte[] buf, int offset, int len) throws DigestException {
+        if (offset < 0 || offset + len >= buf.length) {
+            throw new DigestException("Wrong offset or not enough space to store the digest");
         }
-        // buffer remaining input
-        if (i < len)
-            System.arraycopy(input, offset + i, buffer, bufferNdx, len - i);
+        int destLength = Math.min(len, BYTE_DIGEST_LENGTH);
+        System.arraycopy(engineDigest(), 0, buf, offset, destLength);
+        return destLength;
     }
 
     /**
-     * Completes the hash computation by performing final operations such
-     * as padding. At the return of this engineDigest, the MD engine is
-     * reset.
-     *
-     * @return the array of bytes for the resulting hash value.
+     * {@inheritDoc}
      */
-    public byte[] engineDigest () {
-        // pad output to 56 mod 64; as RFC1320 puts it: congruent to 448 mod 512
-        int bufferNdx = (int)(count % BLOCK_LENGTH);
-        int padLen = (bufferNdx < 56) ? (56 - bufferNdx) : (120 - bufferNdx);
-
-        // padding is alwas binary 1 followed by binary 0s
-        byte[] tail = new byte[padLen + 8];
-        tail[0] = (byte)0x80;
-
-        // append length before final transform:
-        // save number of bits, casting the long to an array of 8 bytes
-        // save low-order byte first.
-        for (int i = 0; i < 8; i++)
-            tail[padLen + i] = (byte)((count * 8) >>> (8 * i));
-
-        engineUpdate(tail, 0, tail.length);
-
-        byte[] result = new byte[16];
-        // cast this MD4's context (array of 4 ints) into an array of 16 bytes.
-        for (int i = 0; i < 4; i++)
-            for (int j = 0; j < 4; j++)
-                result[i * 4 + j] = (byte)(context[i] >>> (8 * j));
-
-        // reset the engine
-        engineReset();
-        return result;
+    protected void engineReset() {
+        a = A;
+        b = B;
+        c = C;
+        d = D;
+        msgLength = 0;
     }
 
     /**
-     *    MD4 basic transformation.
-     *    <p>
-     *    Transforms context based on 512 bits from input block starting
-     *    from the offset'th byte.
-     *
-     *    @param    block    input sub-array.
-     *    @param    offset    starting position of sub-array.
+     * Pads the buffer by appending the byte 0x80, then append as many zero 
+     * bytes as necessary to make the buffer length a multiple of 64 bytes.  
+     * The last 8 bytes will be filled with the length of the buffer in bits.
+     * If there's no room to store the length in bits in the block i.e the block 
+     * is larger than 56 bytes then an additionnal 64-bytes block is appended.
+     * 
+     * @see sections 3.1 & 3.2 of the RFC 1320.
+     * 
+     * @return the pad byte array
      */
-    private void transform (byte[] block, int offset) {
-
-        // encodes 64 bytes from input block into an array of 16 32-bit
-        // entities. Use A as a temp var.
-        for (int i = 0; i < 16; i++)
-            X[i] = (block[offset++] & 0xFF)       |
-                    (block[offset++] & 0xFF) <<  8 |
-                    (block[offset++] & 0xFF) << 16 |
-                    (block[offset++] & 0xFF) << 24;
-
-
-        int A = context[0];
-        int B = context[1];
-        int C = context[2];
-        int D = context[3];
-
-        A = FF(A, B, C, D, X[ 0],  3);
-        D = FF(D, A, B, C, X[ 1],  7);
-        C = FF(C, D, A, B, X[ 2], 11);
-        B = FF(B, C, D, A, X[ 3], 19);
-        A = FF(A, B, C, D, X[ 4],  3);
-        D = FF(D, A, B, C, X[ 5],  7);
-        C = FF(C, D, A, B, X[ 6], 11);
-        B = FF(B, C, D, A, X[ 7], 19);
-        A = FF(A, B, C, D, X[ 8],  3);
-        D = FF(D, A, B, C, X[ 9],  7);
-        C = FF(C, D, A, B, X[10], 11);
-        B = FF(B, C, D, A, X[11], 19);
-        A = FF(A, B, C, D, X[12],  3);
-        D = FF(D, A, B, C, X[13],  7);
-        C = FF(C, D, A, B, X[14], 11);
-        B = FF(B, C, D, A, X[15], 19);
-
-        A = GG(A, B, C, D, X[ 0],  3);
-        D = GG(D, A, B, C, X[ 4],  5);
-        C = GG(C, D, A, B, X[ 8],  9);
-        B = GG(B, C, D, A, X[12], 13);
-        A = GG(A, B, C, D, X[ 1],  3);
-        D = GG(D, A, B, C, X[ 5],  5);
-        C = GG(C, D, A, B, X[ 9],  9);
-        B = GG(B, C, D, A, X[13], 13);
-        A = GG(A, B, C, D, X[ 2],  3);
-        D = GG(D, A, B, C, X[ 6],  5);
-        C = GG(C, D, A, B, X[10],  9);
-        B = GG(B, C, D, A, X[14], 13);
-        A = GG(A, B, C, D, X[ 3],  3);
-        D = GG(D, A, B, C, X[ 7],  5);
-        C = GG(C, D, A, B, X[11],  9);
-        B = GG(B, C, D, A, X[15], 13);
-
-        A = HH(A, B, C, D, X[ 0],  3);
-        D = HH(D, A, B, C, X[ 8],  9);
-        C = HH(C, D, A, B, X[ 4], 11);
-        B = HH(B, C, D, A, X[12], 15);
-        A = HH(A, B, C, D, X[ 2],  3);
-        D = HH(D, A, B, C, X[10],  9);
-        C = HH(C, D, A, B, X[ 6], 11);
-        B = HH(B, C, D, A, X[14], 15);
-        A = HH(A, B, C, D, X[ 1],  3);
-        D = HH(D, A, B, C, X[ 9],  9);
-        C = HH(C, D, A, B, X[ 5], 11);
-        B = HH(B, C, D, A, X[13], 15);
-        A = HH(A, B, C, D, X[ 3],  3);
-        D = HH(D, A, B, C, X[11],  9);
-        C = HH(C, D, A, B, X[ 7], 11);
-        B = HH(B, C, D, A, X[15], 15);
-
-        context[0] += A;
-        context[1] += B;
-        context[2] += C;
-        context[3] += D;
+    private byte[] pad() {
+        int pos = (int) (msgLength % BYTE_BLOCK_LENGTH);
+        int padLength = (pos < 56) ? (64 - pos) : (128 - pos);
+        byte[] pad = new byte[padLength];
+
+        // First bit of the padding set to 1
+        pad[0] = (byte) 0x80;
+
+        long bits = msgLength << 3;
+        int index = padLength - 8;
+        for (int i = 0; i < 8; i++) {
+            pad[index++] = (byte) (bits >>> (i << 3));
+        }
+
+        return pad;
     }
 
-    // The basic MD4 atomic functions.
+    /** 
+     * Process one 64-byte block. Algorithm is constituted by three rounds.
+     * Note that F, G and H functions were inlined for improved performance.
+     * 
+     * @param in the byte array to process
+     * @param offset the offset at which the 64-byte block is stored
+     */
+    private void process(byte[] in, int offset) {
+        // Save previous state.
+        int aa = a;
+        int bb = b;
+        int cc = c;
+        int dd = d;
+
+        // Copy the block to process into X array
+        int[] X = new int[16];
+        for (int i = 0; i < 16; i++) {
+            X[i] = (in[offset++] & 0xff) | (in[offset++] & 0xff) << 8 | (in[offset++] & 0xff) << 16
+                    | (in[offset++] & 0xff) << 24;
+        }
 
-    private int FF (int a, int b, int c, int d, int x, int s) {
-        int t = a + ((b & c) | (~b & d)) + x;
-        return t << s | t >>> (32 - s);
-    }
-    private int GG (int a, int b, int c, int d, int x, int s) {
-        int t = a + ((b & (c | d)) | (c & d)) + x + 0x5A827999;
-        return t << s | t >>> (32 - s);
-    }
-    private int HH (int a, int b, int c, int d, int x, int s) {
-        int t = a + (b ^ c ^ d) + x + 0x6ED9EBA1;
-        return t << s | t >>> (32 - s);
+        // Round 1
+        a += ((b & c) | (~b & d)) + X[0];
+        a = a << 3 | a >>> (32 - 3);
+        d += ((a & b) | (~a & c)) + X[1];
+        d = d << 7 | d >>> (32 - 7);
+        c += ((d & a) | (~d & b)) + X[2];
+        c = c << 11 | c >>> (32 - 11);
+        b += ((c & d) | (~c & a)) + X[3];
+        b = b << 19 | b >>> (32 - 19);
+        a += ((b & c) | (~b & d)) + X[4];
+        a = a << 3 | a >>> (32 - 3);
+        d += ((a & b) | (~a & c)) + X[5];
+        d = d << 7 | d >>> (32 - 7);
+        c += ((d & a) | (~d & b)) + X[6];
+        c = c << 11 | c >>> (32 - 11);
+        b += ((c & d) | (~c & a)) + X[7];
+        b = b << 19 | b >>> (32 - 19);
+        a += ((b & c) | (~b & d)) + X[8];
+        a = a << 3 | a >>> (32 - 3);
+        d += ((a & b) | (~a & c)) + X[9];
+        d = d << 7 | d >>> (32 - 7);
+        c += ((d & a) | (~d & b)) + X[10];
+        c = c << 11 | c >>> (32 - 11);
+        b += ((c & d) | (~c & a)) + X[11];
+        b = b << 19 | b >>> (32 - 19);
+        a += ((b & c) | (~b & d)) + X[12];
+        a = a << 3 | a >>> (32 - 3);
+        d += ((a & b) | (~a & c)) + X[13];
+        d = d << 7 | d >>> (32 - 7);
+        c += ((d & a) | (~d & b)) + X[14];
+        c = c << 11 | c >>> (32 - 11);
+        b += ((c & d) | (~c & a)) + X[15];
+        b = b << 19 | b >>> (32 - 19);
+
+        // Round 2
+        a += ((b & (c | d)) | (c & d)) + X[0] + 0x5a827999;
+        a = a << 3 | a >>> (32 - 3);
+        d += ((a & (b | c)) | (b & c)) + X[4] + 0x5a827999;
+        d = d << 5 | d >>> (32 - 5);
+        c += ((d & (a | b)) | (a & b)) + X[8] + 0x5a827999;
+        c = c << 9 | c >>> (32 - 9);
+        b += ((c & (d | a)) | (d & a)) + X[12] + 0x5a827999;
+        b = b << 13 | b >>> (32 - 13);
+        a += ((b & (c | d)) | (c & d)) + X[1] + 0x5a827999;
+        a = a << 3 | a >>> (32 - 3);
+        d += ((a & (b | c)) | (b & c)) + X[5] + 0x5a827999;
+        d = d << 5 | d >>> (32 - 5);
+        c += ((d & (a | b)) | (a & b)) + X[9] + 0x5a827999;
+        c = c << 9 | c >>> (32 - 9);
+        b += ((c & (d | a)) | (d & a)) + X[13] + 0x5a827999;
+        b = b << 13 | b >>> (32 - 13);
+        a += ((b & (c | d)) | (c & d)) + X[2] + 0x5a827999;
+        a = a << 3 | a >>> (32 - 3);
+        d += ((a & (b | c)) | (b & c)) + X[6] + 0x5a827999;
+        d = d << 5 | d >>> (32 - 5);
+        c += ((d & (a | b)) | (a & b)) + X[10] + 0x5a827999;
+        c = c << 9 | c >>> (32 - 9);
+        b += ((c & (d | a)) | (d & a)) + X[14] + 0x5a827999;
+        b = b << 13 | b >>> (32 - 13);
+        a += ((b & (c | d)) | (c & d)) + X[3] + 0x5a827999;
+        a = a << 3 | a >>> (32 - 3);
+        d += ((a & (b | c)) | (b & c)) + X[7] + 0x5a827999;
+        d = d << 5 | d >>> (32 - 5);
+        c += ((d & (a | b)) | (a & b)) + X[11] + 0x5a827999;
+        c = c << 9 | c >>> (32 - 9);
+        b += ((c & (d | a)) | (d & a)) + X[15] + 0x5a827999;
+        b = b << 13 | b >>> (32 - 13);
+
+        // Round 3
+        a += (b ^ c ^ d) + X[0] + 0x6ed9eba1;
+        a = a << 3 | a >>> (32 - 3);
+        d += (a ^ b ^ c) + X[8] + 0x6ed9eba1;
+        d = d << 9 | d >>> (32 - 9);
+        c += (d ^ a ^ b) + X[4] + 0x6ed9eba1;
+        c = c << 11 | c >>> (32 - 11);
+        b += (c ^ d ^ a) + X[12] + 0x6ed9eba1;
+        b = b << 15 | b >>> (32 - 15);
+        a += (b ^ c ^ d) + X[2] + 0x6ed9eba1;
+        a = a << 3 | a >>> (32 - 3);
+        d += (a ^ b ^ c) + X[10] + 0x6ed9eba1;
+        d = d << 9 | d >>> (32 - 9);
+        c += (d ^ a ^ b) + X[6] + 0x6ed9eba1;
+        c = c << 11 | c >>> (32 - 11);
+        b += (c ^ d ^ a) + X[14] + 0x6ed9eba1;
+        b = b << 15 | b >>> (32 - 15);
+        a += (b ^ c ^ d) + X[1] + 0x6ed9eba1;
+        a = a << 3 | a >>> (32 - 3);
+        d += (a ^ b ^ c) + X[9] + 0x6ed9eba1;
+        d = d << 9 | d >>> (32 - 9);
+        c += (d ^ a ^ b) + X[5] + 0x6ed9eba1;
+        c = c << 11 | c >>> (32 - 11);
+        b += (c ^ d ^ a) + X[13] + 0x6ed9eba1;
+        b = b << 15 | b >>> (32 - 15);
+        a += (b ^ c ^ d) + X[3] + 0x6ed9eba1;
+        a = a << 3 | a >>> (32 - 3);
+        d += (a ^ b ^ c) + X[11] + 0x6ed9eba1;
+        d = d << 9 | d >>> (32 - 9);
+        c += (d ^ a ^ b) + X[7] + 0x6ed9eba1;
+        c = c << 11 | c >>> (32 - 11);
+        b += (c ^ d ^ a) + X[15] + 0x6ed9eba1;
+        b = b << 15 | b >>> (32 - 15);
+
+        //Update state.
+        a += aa;
+        b += bb;
+        c += cc;
+        d += dd;
     }
 }