package org.bouncycastle.crypto.digests; import org.bouncycastle.crypto.ExtendedDigest; import org.bouncycastle.util.Memoable; import org.bouncycastle.util.Pack; /** * base implementation of MD4 family style digest as outlined in * "Handbook of Applied Cryptography", pages 344 - 347. */ public abstract class GeneralDigest implements ExtendedDigest, Memoable { private static final int BYTE_LENGTH = 64; private final byte[] xBuf = new byte[4]; private int xBufOff; private long byteCount; /** * Standard constructor */ protected GeneralDigest() { xBufOff = 0; } /** * Copy constructor. We are using copy constructors in place * of the Object.clone() interface as this interface is not * supported by J2ME. */ protected GeneralDigest(GeneralDigest t) { copyIn(t); } protected GeneralDigest(byte[] encodedState) { System.arraycopy(encodedState, 0, xBuf, 0, xBuf.length); xBufOff = Pack.bigEndianToInt(encodedState, 4); byteCount = Pack.bigEndianToLong(encodedState, 8); } protected void copyIn(GeneralDigest t) { System.arraycopy(t.xBuf, 0, xBuf, 0, t.xBuf.length); xBufOff = t.xBufOff; byteCount = t.byteCount; } public void update( byte in) { xBuf[xBufOff++] = in; if (xBufOff == xBuf.length) { processWord(xBuf, 0); xBufOff = 0; } byteCount++; } public void update( byte[] in, int inOff, int len) { len = Math.max(0, len); // // fill the current word // int i = 0; if (xBufOff != 0) { while (i < len) { xBuf[xBufOff++] = in[inOff + i++]; if (xBufOff == 4) { processWord(xBuf, 0); xBufOff = 0; break; } } } // // process whole words. // int limit = ((len - i) & ~3) + i; for (; i < limit; i += 4) { processWord(in, inOff + i); } // // load in the remainder. // while (i < len) { xBuf[xBufOff++] = in[inOff + i++]; } byteCount += len; } public void finish() { long bitLength = (byteCount << 3); // // add the pad bytes. // update((byte)128); while (xBufOff != 0) { update((byte)0); } processLength(bitLength); processBlock(); } public void reset() { byteCount = 0; xBufOff = 0; for (int i = 0; i < xBuf.length; i++) { xBuf[i] = 0; } } protected void populateState(byte[] state) { System.arraycopy(xBuf, 0, state, 0, xBufOff); Pack.intToBigEndian(xBufOff, state, 4); Pack.longToBigEndian(byteCount, state, 8); } public int getByteLength() { return BYTE_LENGTH; } protected abstract void processWord(byte[] in, int inOff); protected abstract void processLength(long bitLength); protected abstract void processBlock(); }