All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.day.text.MD4 Maven / Gradle / Ivy

/*************************************************************************
 *
 * ADOBE CONFIDENTIAL
 * __________________
 *
 *  Copyright 2012 Adobe Systems Incorporated
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of Adobe Systems Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to Adobe Systems Incorporated and its
 * suppliers and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from Adobe Systems Incorporated.
 **************************************************************************/

package com.day.text;

/**
 * MD4 digest algorithm. Not contained in the standard message digest
 * implementations. Used by the {@link Text#digest} methods.
 */
public class MD4 {

    /**
     * Padding.
     */
    private static final byte[] PADDING = new byte[] {
        (byte) 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
    };

    /**
     * Constants for transform routine.
     */
    private static final int S11 = 3;
    private static final int S12 = 7;
    private static final int S13 = 11;
    private static final int S14 = 19;
    private static final int S21 = 3;
    private static final int S22 = 5;
    private static final int S23 = 9;
    private static final int S24 = 13;
    private static final int S31 = 3;
    private static final int S32 = 9;
    private static final int S33 = 11;
    private static final int S34 = 15;

    /**
     * State (ABCD).
     */
    private int state[] = new int[4];

    /**
     * Number of bits, module 2^64 (lsb first).
     */
    private int count[] = new int[2];

    /**
     * Input buffer.
     */
    private byte buffer[] = new byte[64];

    /**
     * Create a new instance of this class.
     */
    public MD4() {
        init();
    }

    /**
     * Initialization. Begins an MD4 operation, writing a new context.
     */
    private void init() {
        count[0] = count[1] = 0;
        state[0] = 0x67452301;
        state[1] = 0xefcdab89;
        state[2] = 0x98badcfe;
        state[3] = 0x10325476;
    }

    /**
     * Feed some more input.
     *
     * @param input input block
     * @param off offset inside input block
     * @param len number of valid bytes
     */
    public void update(byte[] input, int off, int len) {
        /* Compute number of bytes mod 64 */
        int index = (count[0] >> 3) & 0x3F;
        /* Update number of bits */
        int bitlen = len << 3;
        if ((count[0] += bitlen) < bitlen) {
            count[1]++;
        }
        count[1] += len >> 29;

        int partlen = 64 - index;

        /* Transform as many times as possible. */
        int i;
        if (len >= partlen) {
            System.arraycopy(input, off, buffer, index, partlen);
            transform(buffer, 0);
            for (i = partlen; i + 63 < len; i += 64) {
                transform(input, off + i);
            }
            index = 0;
        } else {
            i = 0;
        }
        /* Buffer remaining input */
        System.arraycopy(input, off + i, buffer, index, len - i);
    }


    /**
     * MD4 finalization. Ends an MD4 message-digest operation, writing the
     * message digest.
     *
     * @return message digest
     */
    public byte[] finish() {
        byte[] digest = new byte[16], bits = new byte[8];
        int index, padlen;

        /* Save number of bits */
        encode(count, bits, 0, bits.length);

        /* Pad out to 56 mod 64. */
        index = (count[0] >> 3) & 0x3f;
        padlen = (index < 56) ? (56 - index) : (120 - index);
        update(PADDING, 0, padlen);

        /* Append length (before padding) */
        update(bits, 0, bits.length);

        /* Store state in digest */
        encode(state, digest, 0, digest.length);
        return digest;
    }

    /**
     * MD4 basic transformation. Transforms state based on block,
     * which is assumed to have at least length 64.
     *
     * @param block block
     * @param offset offset inside block
     */
    private void transform(byte[] block, int offset) {
        int a = state[0], b = state[1], c = state[2], d = state[3];
        int x[] = new int[16];

        decode(block, offset, 64, x);

        /* Round 1 */
        a = FF(a, b, c, d, x[ 0], S11); /* 1 */
        d = FF(d, a, b, c, x[ 1], S12); /* 2 */
        c = FF(c, d, a, b, x[ 2], S13); /* 3 */
        b = FF(b, c, d, a, x[ 3], S14); /* 4 */
        a = FF(a, b, c, d, x[ 4], S11); /* 5 */
        d = FF(d, a, b, c, x[ 5], S12); /* 6 */
        c = FF(c, d, a, b, x[ 6], S13); /* 7 */
        b = FF(b, c, d, a, x[ 7], S14); /* 8 */
        a = FF(a, b, c, d, x[ 8], S11); /* 9 */
        d = FF(d, a, b, c, x[ 9], S12); /* 10 */
        c = FF(c, d, a, b, x[10], S13); /* 11 */
        b = FF(b, c, d, a, x[11], S14); /* 12 */
        a = FF(a, b, c, d, x[12], S11); /* 13 */
        d = FF(d, a, b, c, x[13], S12); /* 14 */
        c = FF(c, d, a, b, x[14], S13); /* 15 */
        b = FF(b, c, d, a, x[15], S14); /* 16 */

        /* Round 2 */
        a = GG(a, b, c, d, x[ 0], S21); /* 17 */
        d = GG(d, a, b, c, x[ 4], S22); /* 18 */
        c = GG(c, d, a, b, x[ 8], S23); /* 19 */
        b = GG(b, c, d, a, x[12], S24); /* 20 */
        a = GG(a, b, c, d, x[ 1], S21); /* 21 */
        d = GG(d, a, b, c, x[ 5], S22); /* 22 */
        c = GG(c, d, a, b, x[ 9], S23); /* 23 */
        b = GG(b, c, d, a, x[13], S24); /* 24 */
        a = GG(a, b, c, d, x[ 2], S21); /* 25 */
        d = GG(d, a, b, c, x[ 6], S22); /* 26 */
        c = GG(c, d, a, b, x[10], S23); /* 27 */
        b = GG(b, c, d, a, x[14], S24); /* 28 */
        a = GG(a, b, c, d, x[ 3], S21); /* 29 */
        d = GG(d, a, b, c, x[ 7], S22); /* 30 */
        c = GG(c, d, a, b, x[11], S23); /* 31 */
        b = GG(b, c, d, a, x[15], S24); /* 32 */

        /* Round 3 */
        a = HH(a, b, c, d, x[ 0], S31); /* 33 */
        d = HH(d, a, b, c, x[ 8], S32); /* 34 */
        c = HH(c, d, a, b, x[ 4], S33); /* 35 */
        b = HH(b, c, d, a, x[12], S34); /* 36 */
        a = HH(a, b, c, d, x[ 2], S31); /* 37 */
        d = HH(d, a, b, c, x[10], S32); /* 38 */
        c = HH(c, d, a, b, x[ 6], S33); /* 39 */
        b = HH(b, c, d, a, x[14], S34); /* 40 */
        a = HH(a, b, c, d, x[ 1], S31); /* 41 */
        d = HH(d, a, b, c, x[ 9], S32); /* 42 */
        c = HH(c, d, a, b, x[ 5], S33); /* 43 */
        b = HH(b, c, d, a, x[13], S34); /* 44 */
        a = HH(a, b, c, d, x[ 3], S31); /* 45 */
        d = HH(d, a, b, c, x[11], S32); /* 46 */
        c = HH(c, d, a, b, x[ 7], S33); /* 47 */
        b = HH(b, c, d, a, x[15], S34); /* 48 */

        state[0] += a;
        state[1] += b;
        state[2] += c;
        state[3] += d;
    }

    /**
     * Encodes input (int) into output (byte). Assumes
     * len is a multiple of 4.
     *
     * @param input input
     * @param len length
     * @param output output
     */
     private static void encode(int[] input, byte[] output, int off, int len) {
        for (int i = 0, j = off; j < off + len; i++, j += 4) {
            output[j] = (byte) (input[i] & 0xff);
            output[j + 1] = (byte)((input[i] >> 8) & 0xff);
            output[j + 2] = (byte)((input[i] >> 16) & 0xff);
            output[j + 3] = (byte)((input[i] >> 24) & 0xff);
        }
    }

    /**
     * Decodes input (byte) into output (int). Assumes
     * len is a multiple of 4.
     *
     * @param input input
     * @param off offset
     * @param len length
     * @param output output
     */
    private static void decode(byte[] input, int off, int len, int[] output) {
        for (int i = 0, j = off; j < off + len; i++, j += 4) {
            int ch1 = ((int) input[j]) & 0xff;
            int ch2 = ((int) input[j + 1]) & 0xff;
            int ch3 = ((int) input[j + 2]) & 0xff;
            int ch4 = ((int) input[j + 3]) & 0xff;
            output[i] = ch1 | (ch2 << 8) | (ch3 << 16) | (ch4 << 24);
        }
    }

    /**
     * FF, GG and HH are transformations for rounds 1, 2 and 3. Rotation
     * is separate from addition to prevent recomputation.
     */
    private static int FF(int a, int b, int c, int d, int x, int s) {
        a += ((b & c) | ((~b) & d)) + x;
        return (a << s) | (a >>> (32 - s));
    }

    private static int GG(int a, int b, int c, int d, int x, int s) {
        a += ((b & c) | (b & d) | (c & d)) + x + 0x5a827999;
        return (a << s) | (a >>> (32 - s));
    }

    private static int HH(int a, int b, int c, int d, int x, int s) {
        a += (b ^ c ^ d) + x + 0x6ed9eba1;
        return (a << s) | (a >>> (32 - s));
    }

    /**
     * Utility method that makes a single update and then finishes.
     *
     * @param input input
     * @return digest digest
     */
    public static byte[] digest(byte[] input) {
        MD4 md4 = new MD4();
        md4.update(input, 0, input.length);
        return md4.finish();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy