com.day.text.MD4 Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aem-sdk-api Show documentation
Show all versions of aem-sdk-api Show documentation
The Adobe Experience Manager SDK
/*************************************************************************
*
* 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();
}
}