You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by ed...@apache.org on 2008/08/20 01:39:32 UTC

svn commit: r687196 - in /mina/trunk/core/src: main/java/org/apache/mina/proxy/utils/MD4.java main/java/org/apache/mina/proxy/utils/MD4Provider.java test/java/org/apache/mina/proxy/MD4Test.java

Author: edeoliveira
Date: Tue Aug 19 16:39:31 2008
New Revision: 687196

URL: http://svn.apache.org/viewvc?rev=687196&view=rev
Log:
Added a MD4 provider and its JUNIT tests

Added:
    mina/trunk/core/src/main/java/org/apache/mina/proxy/utils/MD4.java   (with props)
    mina/trunk/core/src/main/java/org/apache/mina/proxy/utils/MD4Provider.java   (with props)
    mina/trunk/core/src/test/java/org/apache/mina/proxy/MD4Test.java   (with props)

Added: mina/trunk/core/src/main/java/org/apache/mina/proxy/utils/MD4.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/proxy/utils/MD4.java?rev=687196&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/proxy/utils/MD4.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/proxy/utils/MD4.java Tue Aug 19 16:39:31 2008
@@ -0,0 +1,320 @@
+package org.apache.mina.proxy.utils;
+
+import java.security.DigestException;
+import java.security.MessageDigestSpi;
+
+/**
+ * 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.
+ *
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ * @version $Rev$, $Date$
+ * @since MINA 2.0.0-M3
+ */
+public class MD4 extends MessageDigestSpi {
+
+    /**
+     * The MD4 algorithm message digest length is 16 bytes wide.
+     */
+    public static final int BYTE_DIGEST_LENGTH = 16;
+
+    /**
+     * The MD4 algorithm block length is 64 bytes wide.
+     */
+    public static final int BYTE_BLOCK_LENGTH = 64;
+
+    /**
+     * The initial values of the four registers. RFC gives the values 
+     * in LE so we converted it as JAVA uses BE endianness.
+     */
+    private final static int A = 0x67452301;
+
+    private final static int B = 0xefcdab89;
+
+    private final static int C = 0x98badcfe;
+
+    private final static int D = 0x10325476;
+
+    /**
+     * The four registers initialized with the above IVs.
+     */
+    private int a = A;
+
+    private int b = B;
+
+    private int c = C;
+
+    private int d = D;
+
+    /**
+     * Counts the total length of the data being digested.
+     */
+    private long msgLength;
+
+    /**
+     * The internal buffer is {@link BLOCK_LENGTH} wide.
+     */
+    private final byte[] buffer = new byte[BYTE_BLOCK_LENGTH];
+
+    /**
+     * Default constructor.
+     */
+    public MD4() {
+    }
+
+    /**
+     * Returns the digest length in bytes.
+     *
+     * @return the digest length in bytes.
+     */
+    protected int engineGetDigestLength() {
+        return BYTE_DIGEST_LENGTH;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    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);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    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);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    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();
+
+        return digest;
+    }
+
+    /**
+     * {@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");
+        }
+        int destLength = Math.min(len, BYTE_DIGEST_LENGTH);
+        System.arraycopy(engineDigest(), 0, buf, offset, destLength);
+        return destLength;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected void engineReset() {
+        a = A;
+        b = B;
+        c = C;
+        d = D;
+        msgLength = 0;
+    }
+
+    /**
+     * 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 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;
+    }
+
+    /** 
+     * 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;
+        }
+
+        // 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;
+    }
+}

Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/utils/MD4.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/utils/MD4.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: mina/trunk/core/src/main/java/org/apache/mina/proxy/utils/MD4Provider.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/main/java/org/apache/mina/proxy/utils/MD4Provider.java?rev=687196&view=auto
==============================================================================
--- mina/trunk/core/src/main/java/org/apache/mina/proxy/utils/MD4Provider.java (added)
+++ mina/trunk/core/src/main/java/org/apache/mina/proxy/utils/MD4Provider.java Tue Aug 19 16:39:31 2008
@@ -0,0 +1,61 @@
+/*
+ *  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.mina.proxy.utils;
+
+import java.security.Provider;
+
+/**
+ * MD4Provider.java - A security provider that only provides a MD4 implementation.
+ * 
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ * @version $Rev$, $Date$
+ * @since MINA 2.0.0-M3
+ */
+public class MD4Provider extends Provider {
+
+    /**
+     * The serial version UID.
+     */
+    private final static long serialVersionUID = -1616816866935565456L;
+
+    /**
+     * Provider name.
+     */
+    public final static String PROVIDER_NAME = "MINA";
+
+    /**
+     * Provider version.
+     */    
+    public final static double VERSION = 1.00;
+
+    /**
+     * Provider information.
+     */
+    public final static String INFO = "MINA MD4 Provider v" + VERSION;
+
+    /**
+     * Default constructor that registers {@link MD4} as the <i>Service Provider 
+     * Interface</i> (<b>SPI</b>) of the MD4 message digest algorithm.
+     */
+    public MD4Provider() {
+        super(PROVIDER_NAME, VERSION, INFO);
+        put("MessageDigest.MD4", MD4.class.getName());
+    }
+}

Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/utils/MD4Provider.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: mina/trunk/core/src/main/java/org/apache/mina/proxy/utils/MD4Provider.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: mina/trunk/core/src/test/java/org/apache/mina/proxy/MD4Test.java
URL: http://svn.apache.org/viewvc/mina/trunk/core/src/test/java/org/apache/mina/proxy/MD4Test.java?rev=687196&view=auto
==============================================================================
--- mina/trunk/core/src/test/java/org/apache/mina/proxy/MD4Test.java (added)
+++ mina/trunk/core/src/test/java/org/apache/mina/proxy/MD4Test.java Tue Aug 19 16:39:31 2008
@@ -0,0 +1,108 @@
+/*
+ *  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.mina.proxy;
+
+import static org.apache.mina.proxy.utils.ByteUtilities.asHex;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Security;
+
+import org.apache.mina.proxy.utils.MD4Provider;
+
+import junit.framework.TestCase;
+
+/**
+ * MD4Test.java - JUnit testcase that tests the rfc 1320 test suite.
+ * @see <a href="http://www.ietf.org/rfc/rfc1320.txt">RFC 1320</a>
+ * 
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ * @version $Rev$, $Date$
+ * @since MINA 2.0.0-M3
+ */
+public class MD4Test extends TestCase {
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void setUp() throws Exception {
+        if (Security.getProvider(MD4Provider.PROVIDER_NAME) == null) {
+            System.out.print("Adding MINA provider...");
+            Security.addProvider(new MD4Provider());
+            System.out.println(" [Ok]");
+        }
+    }
+
+    /**
+     * Test suite for the MD4 algorithm. 
+     */
+    public void testRFCVectors() throws NoSuchAlgorithmException,
+            NoSuchProviderException {
+        MessageDigest md4 = MessageDigest.getInstance("MD4",
+                MD4Provider.PROVIDER_NAME);
+        doTest(md4, "31d6cfe0d16ae931b73c59d7e0c089c0", "");
+        doTest(md4, "bde52cb31de33e46245e05fbdbd6fb24", "a");
+        doTest(md4, "a448017aaf21d8525fc10ae87aa6729d", "abc");
+        doTest(md4, "d9130a8164549fe818874806e1c7014b", "message digest");
+        doTest(md4, "d79e1c308aa5bbcdeea8ed63df412da9",
+                "abcdefghijklmnopqrstuvwxyz");
+        doTest(md4, "043f8582f241db351ce627e153e7f0e4",
+                "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
+        doTest(
+                md4,
+                "e33b4ddc9c38f2199c3e7b164fcc0536",
+                "12345678901234567890123456789012345678901234567890123456789012345678901234567890");
+    }
+
+    /**
+     * Original test vector found on <a href="http://en.wikipedia.org/wiki/MD4">wikipedia(en)</a>
+     * and <a href="http://fr.wikipedia.org/wiki/MD4">wikipedia(fr)</a>
+     */
+    public void testWikipediaVectors() throws NoSuchAlgorithmException,
+            NoSuchProviderException {
+        MessageDigest md4 = MessageDigest.getInstance("MD4",
+                MD4Provider.PROVIDER_NAME);
+        doTest(md4, "b94e66e0817dd34dc7858a0c131d4079",
+                "Wikipedia, l'encyclopedie libre et gratuite");
+        doTest(md4, "1bee69a46ba811185c194762abaeae90",
+                "The quick brown fox jumps over the lazy dog");
+        doTest(md4, "b86e130ce7028da59e672d56ad0113df",
+                "The quick brown fox jumps over the lazy cog");
+    }
+
+    /**
+     * Performs md4 digesting on the provided test vector and verifies that the
+     * result equals to the expected result.
+     * 
+     * @param md4 the md4 message digester
+     * @param expected the expected hex formatted string
+     * @param testVector the string message
+     */
+    private static void doTest(MessageDigest md4, String expected,
+            String testVector) {
+        System.out.print("Testing vector [" + testVector + "]: ");
+        String result = asHex(md4.digest(testVector.getBytes()));
+        System.out.print(result);
+        assertEquals(expected, result);
+        System.out.println(" ... Ok");
+    }
+}

Propchange: mina/trunk/core/src/test/java/org/apache/mina/proxy/MD4Test.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: mina/trunk/core/src/test/java/org/apache/mina/proxy/MD4Test.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain