summaryrefslogtreecommitdiffstats
path: root/src/jake2/qcommon/MD4.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/jake2/qcommon/MD4.java')
-rw-r--r--src/jake2/qcommon/MD4.java312
1 files changed, 312 insertions, 0 deletions
diff --git a/src/jake2/qcommon/MD4.java b/src/jake2/qcommon/MD4.java
new file mode 100644
index 0000000..45fdf7c
--- /dev/null
+++ b/src/jake2/qcommon/MD4.java
@@ -0,0 +1,312 @@
+/*
+Copyright (C) 1997-2001 Id Software, Inc.
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+*/
+
+// Created on 02.02.2004 by RST.
+// $Id: MD4.java,v 1.1 2004-07-07 19:59:31 hzi Exp $
+
+package jake2.qcommon;
+
+import java.nio.ByteBuffer;
+import java.security.MessageDigest;
+
+import jake2.*;
+import jake2.client.*;
+import jake2.game.*;
+import jake2.render.*;
+import jake2.server.*;
+import jake2.util.Lib;
+
+
+public class MD4 extends MessageDigest implements Cloneable {
+ // MD4 specific object variables
+ //...........................................................................
+
+ /**
+ * The size in bytes of the input block to the tranformation algorithm.
+ */
+ private static final int BLOCK_LENGTH = 64; // = 512 / 8;
+
+ /**
+ * 4 32-bit words (interim result)
+ */
+ private int[] context = new int[4];
+
+ /**
+ * Number of bytes processed so far mod. 2 power of 64.
+ */
+ private long count;
+
+ /**
+ * 512 bits input buffer = 16 x 32-bit words holds until reaches 512 bits.
+ */
+ private byte[] buffer = new byte[BLOCK_LENGTH];
+
+ /**
+ * 512 bits work buffer = 16 x 32-bit words
+ */
+ private int[] X = new int[16];
+
+ // Constructors
+ //...........................................................................
+
+ public MD4() {
+ super("MD4");
+ engineReset();
+ }
+
+ /**
+ * This constructor is here to implement cloneability of this class.
+ */
+ private MD4(MD4 md) {
+ this();
+ context = (int[]) md.context.clone();
+ buffer = (byte[]) md.buffer.clone();
+ count = md.count;
+ }
+
+ // Cloneable method implementation
+ //...........................................................................
+
+ /**
+ * Returns a copy of this MD object.
+ */
+ public Object clone() {
+ return new MD4(this);
+ }
+
+ // JCE methods
+ //...........................................................................
+
+ /**
+ * Resets this object disregarding any temporary data present at the
+ * time of the invocation of this call.
+ */
+ 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;
+ }
+
+ /**
+ * Continues an MD4 message digest using the input byte.
+ */
+ 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);
+ }
+
+ /**
+ * 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
+ */
+ 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);
+
+ transform(buffer, 0);
+
+ for (i = partLen; i + BLOCK_LENGTH - 1 < len; i += BLOCK_LENGTH)
+ transform(input, offset + i);
+ bufferNdx = 0;
+ }
+ // buffer remaining input
+ if (i < len)
+ System.arraycopy(input, offset + i, buffer, bufferNdx, len - i);
+ }
+
+ /**
+ * 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.
+ */
+ 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;
+ }
+
+ // own methods
+ //...........................................................................
+
+ /**
+ * 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.
+ */
+ 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;
+ }
+
+ // The basic MD4 atomic functions.
+
+ 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);
+ }
+
+ public static int Com_BlockChecksum(byte[] buffer, int length) {
+ byte digest[] = new byte[16];
+ int val;
+ MD4 md4 = new MD4();
+
+ md4.engineUpdate(buffer, 0, length);
+ byte data[] = md4.engineDigest();
+ Com.Printf("md4: " + Lib.hexDump(data, 16, false));
+
+ ByteBuffer bb = ByteBuffer.wrap(data);
+ //val = digest[0] ^ digest[1] ^ digest[2] ^ digest[3];
+ val = bb.getInt() ^ bb.getInt() ^ bb.getInt() ^ bb.getInt();
+ return val;
+ }
+}