blob: 0bac6484a83917a3598c4737f12cbd9e324af7d1 [file] [log] [blame]
package org.apache.java.security;
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2001 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" and
* "Apache Turbine" must not be used to endorse or promote products
* derived from this software without prior written permission. For
* written permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* "Apache Turbine", nor may "Apache" appear in their name, without
* prior written permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
/**
* This class implements the Message Digest 5 algorithm (MD5) as
* defined in RFC-1321.
*
* <p><b>Note:</b> even if standard Java 1.1 APIs already provide a
* MD5 implementation, this class is used on those Java runtime
* environments (like Kaffe) where the package
* <code>java.security</code> is highly improbable to be found.
*
* @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
* @version $Id$
* @deprecated Use the java.security package.
*/
public final class MD5
extends MessageDigest
{
private long counter;
private int reminder;
private byte buffer[];
private int state[];
private int x[];
/*********************** MD5 Functions ***********************/
// 16 * 4 bytes
static byte padding[] =
{
(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
};
/*********************** Self Test ***********************/
private static String[] messages =
{
"",
"a",
"abc",
"message digest",
"abcdefghijklmnopqrstuvwxyz",
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
"12345678901234567890123456789012345678901234567890123456789012345678901234567890",
};
private static String[] digests =
{
"d41d8cd98f00b204e9800998ecf8427e",
"0cc175b9c0f1b6a831c399e269772661",
"900150983cd24fb0d6963f7d28e17f72",
"f96b697d7cb7938d525a2f31aaf161d0",
"c3fcd3d76192e4007dfb496cca67e13b",
"d174ab98d277d9f5a5611c2c9f419d9f",
"57edf4a22be3c955ac49da2e2107b67a",
};
/**
* Creates the algorithm and reset its state.
*/
public MD5()
{
super();
}
/**
* Append another block of specified length to the message
* starting at the given offset.
*
* @param block A byte[].
* @param offset An int.
* @param length An int.
*/
public void append(byte[] block,
int offset,
int length)
{
while (true)
{
if (length >= reminder)
{
System.arraycopy(block, offset, buffer,
(int) (counter & 63L), reminder);
transform(buffer);
counter += reminder;
offset += reminder;
length -= reminder;
reminder = 64;
}
else
{
System.arraycopy(block, offset, buffer,
(int) (counter & 63L), length);
counter += length;
reminder -= length;
break;
}
}
}
/*********************** Byte/Int utilities ***********************/
/**
* Converts a 64-byte array into a 16-int array.
*
* @param in A byte[].
* @param out An int[].
*/
private static void byte2int(byte[] in,
int[] out)
{
for (int inpos = 0, outpos = 0; outpos < 16; outpos++)
{
out[outpos] = ((((int) (in[inpos++] & 0xff))) |
(((int) (in[inpos++] & 0xff)) << 8) |
(((int) (in[inpos++] & 0xff)) << 16) |
(((int) (in[inpos++] & 0xff)) << 24));
}
}
/**
* Appends a message block with specified length starting from the
* given offset, and return its message digest.
*
* @param block A byte[].
* @param offset An int.
* @param length An int.
*/
public byte[] digest(byte[] block,
int offset,
int length)
{
this.append(block, offset, length);
byte[] bits = toBytes(counter << 3);
byte[] digest = new byte[16];
if (reminder > 8)
{
append(padding, 0, reminder - 8);
}
else
{
append(padding, 0, 64 + (reminder - 8));
}
append(bits, 0, 8);
int2byte(state, digest);
this.reset();
return digest;
}
/*
* Method F.
*
* @param x An int.
* @param y An int.
* @param z An int.
* @return An int.
*/
static private int F(int x,
int y,
int z)
{
return (z ^ (x & (y^z)));
}
/*
* Method FF.
*
* @param a An int.
* @param b An int.
* @param c An int.
* @param d An int.
* @param x An int.
* @param s An int.
* @param ac An int.
* @return An int.
*/
static private int FF(int a,
int b,
int c,
int d,
int x,
int s,
int ac)
{
a += x + ac + F(b,c,d);
a = (a << s | a >>> -s);
return a + b;
}
/*
* Method G.
*
* @param x An int.
* @param y An int.
* @param z An int.
* @return An int.
*/
static private int G(int x,
int y,
int z)
{
return (y ^ (z & (x^y)));
}
/*
* Method GG.
*
* @param a An int.
* @param b An int.
* @param c An int.
* @param d An int.
* @param x An int.
* @param s An int.
* @param ac An int.
* @return An int.
*/
static private int GG(int a,
int b,
int c,
int d,
int x,
int s,
int ac)
{
a += x + ac + G(b,c,d);
a = (a << s | a >>> -s);
return a + b;
}
/*
* Method H.
*
* @param x An int.
* @param y An int.
* @param z An int.
* @return An int.
*/
static private int H(int x,
int y,
int z)
{
return (x ^ y ^ z);
}
/*
* Method HH.
*
* @param a An int.
* @param b An int.
* @param c An int.
* @param d An int.
* @param x An int.
* @param s An int.
* @param ac An int.
* @return An int.
*/
static private int HH(int a,
int b,
int c,
int d,
int x,
int s,
int ac)
{
a += x + ac + H(b,c,d);
a = (a << s | a >>> -s);
return a + b;
}
/*
* Method I.
*
* @param x An int.
* @param y An int.
* @param z An int.
* @return An int.
*/
static private int I(int x,
int y,
int z)
{
return (y ^ (x | ~z));
}
/*
* Method II.
*
* @param a An int.
* @param b An int.
* @param c An int.
* @param d An int.
* @param x An int.
* @param s An int.
* @param ac An int.
* @return An int.
*/
static private int II(int a,
int b,
int c,
int d,
int x,
int s,
int ac)
{
a += x + ac + I(b,c,d);
a = (a << s | a >>> -s);
return a + b;
}
/**
* Converts a 4-int array into a 16-byte array.
*
* @param in An int[].
* @param out A byte[].
*/
private static void int2byte(int[] in,
byte[] out)
{
for (int inpos = 0, outpos = 0; inpos < 4; inpos++)
{
out[outpos++] = (byte) (in[inpos] & 0xff);
out[outpos++] = (byte) ((in[inpos] >>> 8) & 0xff);
out[outpos++] = (byte) ((in[inpos] >>> 16) & 0xff);
out[outpos++] = (byte) ((in[inpos] >>> 24) & 0xff);
}
}
/*
* Main routine, for testing purposes only.
*
* @param ignored A String[] with the command line arguments.
*/
public static final void main(String[] ignored)
{
MD5 md5 = new MD5();
for (int i = 0; i < messages.length; i++)
{
String digest = org.apache.java.lang.Bytes.toString(
md5.digest(messages[i].getBytes()));
System.out.println("Computed: " + digest);
System.out.println("Correct: " + digests[i]);
if (digest.equalsIgnoreCase(digests[i]))
{
System.out.println("Test " + i + " passed.");
}
else
{
System.out.println("Test " + i + " failed.");
}
}
}
/**
* Resets the state of the class. <b>Beware</b>: calling this
* method erases all data previously inserted.
*/
public void reset()
{
buffer = new byte[64];
state = new int[4];
x = new int[16];
state[0] = 0x67452301;
state[1] = 0xefcdab89;
state[2] = 0x98badcfe;
state[3] = 0x10325476;
counter = 0;
reminder = 64;
}
/**
* Converts a long to a 8-byte array using low order first.
*
* @param n A long.
* @return A byte[].
*/
public static byte[] toBytes(long n)
{
byte[] b = new byte[8];
b[0] = (byte) (n);
n >>>= 8;
b[1] = (byte) (n);
n >>>= 8;
b[2] = (byte) (n);
n >>>= 8;
b[3] = (byte) (n);
n >>>= 8;
b[4] = (byte) (n);
n >>>= 8;
b[5] = (byte) (n);
n >>>= 8;
b[6] = (byte) (n);
n >>>= 8;
b[7] = (byte) (n);
return b;
}
/*
* TODO: Document.
*
* @param buffer A byte[].
*/
private void transform(byte[] buffer)
{
int a, b, c, d;
byte2int(buffer, x);
a = state[0];
b = state[1];
c = state[2];
d = state[3];
a = FF(a, b, c, d, x[ 0], 7, 0xd76aa478);
d = FF(d, a, b, c, x[ 1], 12, 0xe8c7b756);
c = FF(c, d, a, b, x[ 2], 17, 0x242070db);
b = FF(b, c, d, a, x[ 3], 22, 0xc1bdceee);
a = FF(a, b, c, d, x[ 4], 7, 0xf57c0faf);
d = FF(d, a, b, c, x[ 5], 12, 0x4787c62a);
c = FF(c, d, a, b, x[ 6], 17, 0xa8304613);
b = FF(b, c, d, a, x[ 7], 22, 0xfd469501);
a = FF(a, b, c, d, x[ 8], 7, 0x698098d8);
d = FF(d, a, b, c, x[ 9], 12, 0x8b44f7af);
c = FF(c, d, a, b, x[10], 17, 0xffff5bb1);
b = FF(b, c, d, a, x[11], 22, 0x895cd7be);
a = FF(a, b, c, d, x[12], 7, 0x6b901122);
d = FF(d, a, b, c, x[13], 12, 0xfd987193);
c = FF(c, d, a, b, x[14], 17, 0xa679438e);
b = FF(b, c, d, a, x[15], 22, 0x49b40821);
a = GG(a, b, c, d, x[ 1], 5, 0xf61e2562);
d = GG(d, a, b, c, x[ 6], 9, 0xc040b340);
c = GG(c, d, a, b, x[11], 14, 0x265e5a51);
b = GG(b, c, d, a, x[ 0], 20, 0xe9b6c7aa);
a = GG(a, b, c, d, x[ 5], 5, 0xd62f105d);
d = GG(d, a, b, c, x[10], 9, 0x2441453);
c = GG(c, d, a, b, x[15], 14, 0xd8a1e681);
b = GG(b, c, d, a, x[ 4], 20, 0xe7d3fbc8);
a = GG(a, b, c, d, x[ 9], 5, 0x21e1cde6);
d = GG(d, a, b, c, x[14], 9, 0xc33707d6);
c = GG(c, d, a, b, x[ 3], 14, 0xf4d50d87);
b = GG(b, c, d, a, x[ 8], 20, 0x455a14ed);
a = GG(a, b, c, d, x[13], 5, 0xa9e3e905);
d = GG(d, a, b, c, x[ 2], 9, 0xfcefa3f8);
c = GG(c, d, a, b, x[ 7], 14, 0x676f02d9);
b = GG(b, c, d, a, x[12], 20, 0x8d2a4c8a);
a = HH(a, b, c, d, x[ 5], 4, 0xfffa3942);
d = HH(d, a, b, c, x[ 8], 11, 0x8771f681);
c = HH(c, d, a, b, x[11], 16, 0x6d9d6122);
b = HH(b, c, d, a, x[14], 23, 0xfde5380c);
a = HH(a, b, c, d, x[ 1], 4, 0xa4beea44);
d = HH(d, a, b, c, x[ 4], 11, 0x4bdecfa9);
c = HH(c, d, a, b, x[ 7], 16, 0xf6bb4b60);
b = HH(b, c, d, a, x[10], 23, 0xbebfbc70);
a = HH(a, b, c, d, x[13], 4, 0x289b7ec6);
d = HH(d, a, b, c, x[ 0], 11, 0xeaa127fa);
c = HH(c, d, a, b, x[ 3], 16, 0xd4ef3085);
b = HH(b, c, d, a, x[ 6], 23, 0x4881d05);
a = HH(a, b, c, d, x[ 9], 4, 0xd9d4d039);
d = HH(d, a, b, c, x[12], 11, 0xe6db99e5);
c = HH(c, d, a, b, x[15], 16, 0x1fa27cf8);
b = HH(b, c, d, a, x[ 2], 23, 0xc4ac5665);
a = II(a, b, c, d, x[ 0], 6, 0xf4292244);
d = II(d, a, b, c, x[ 7], 10, 0x432aff97);
c = II(c, d, a, b, x[14], 15, 0xab9423a7);
b = II(b, c, d, a, x[ 5], 21, 0xfc93a039);
a = II(a, b, c, d, x[12], 6, 0x655b59c3);
d = II(d, a, b, c, x[ 3], 10, 0x8f0ccc92);
c = II(c, d, a, b, x[10], 15, 0xffeff47d);
b = II(b, c, d, a, x[ 1], 21, 0x85845dd1);
a = II(a, b, c, d, x[ 8], 6, 0x6fa87e4f);
d = II(d, a, b, c, x[15], 10, 0xfe2ce6e0);
c = II(c, d, a, b, x[ 6], 15, 0xa3014314);
b = II(b, c, d, a, x[13], 21, 0x4e0811a1);
a = II(a, b, c, d, x[ 4], 6, 0xf7537e82);
d = II(d, a, b, c, x[11], 10, 0xbd3af235);
c = II(c, d, a, b, x[ 2], 15, 0x2ad7d2bb);
b = II(b, c, d, a, x[ 9], 21, 0xeb86d391);
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
}
}