1 package org.bouncycastle.crypto.digests; 2 3 import org.bouncycastle.crypto.ExtendedDigest; 4 import org.bouncycastle.util.Memoable; 5 import org.bouncycastle.util.Pack; 6 7 /** 8 * base implementation of MD4 family style digest as outlined in 9 * "Handbook of Applied Cryptography", pages 344 - 347. 10 */ 11 public abstract class GeneralDigest 12 implements ExtendedDigest, Memoable 13 { 14 private static final int BYTE_LENGTH = 64; 15 16 private final byte[] xBuf = new byte[4]; 17 private int xBufOff; 18 19 private long byteCount; 20 21 /** 22 * Standard constructor 23 */ 24 protected GeneralDigest() 25 { 26 xBufOff = 0; 27 } 28 29 /** 30 * Copy constructor. We are using copy constructors in place 31 * of the Object.clone() interface as this interface is not 32 * supported by J2ME. 33 */ 34 protected GeneralDigest(GeneralDigest t) 35 { 36 copyIn(t); 37 } 38 39 protected GeneralDigest(byte[] encodedState) 40 { 41 System.arraycopy(encodedState, 0, xBuf, 0, xBuf.length); 42 xBufOff = Pack.bigEndianToInt(encodedState, 4); 43 byteCount = Pack.bigEndianToLong(encodedState, 8); 44 } 45 46 protected void copyIn(GeneralDigest t) 47 { 48 System.arraycopy(t.xBuf, 0, xBuf, 0, t.xBuf.length); 49 50 xBufOff = t.xBufOff; 51 byteCount = t.byteCount; 52 } 53 54 public void update( 55 byte in) 56 { 57 xBuf[xBufOff++] = in; 58 59 if (xBufOff == xBuf.length) 60 { 61 processWord(xBuf, 0); 62 xBufOff = 0; 63 } 64 65 byteCount++; 66 } 67 68 public void update( 69 byte[] in, 70 int inOff, 71 int len) 72 { 73 len = Math.max(0, len); 74 75 // 76 // fill the current word 77 // 78 int i = 0; 79 if (xBufOff != 0) 80 { 81 while (i < len) 82 { 83 xBuf[xBufOff++] = in[inOff + i++]; 84 if (xBufOff == 4) 85 { 86 processWord(xBuf, 0); 87 xBufOff = 0; 88 break; 89 } 90 } 91 } 92 93 // 94 // process whole words. 95 // 96 int limit = ((len - i) & ~3) + i; 97 for (; i < limit; i += 4) 98 { 99 processWord(in, inOff + i); 100 } 101 102 // 103 // load in the remainder. 104 // 105 while (i < len) 106 { 107 xBuf[xBufOff++] = in[inOff + i++]; 108 } 109 110 byteCount += len; 111 } 112 113 public void finish() 114 { 115 long bitLength = (byteCount << 3); 116 117 // 118 // add the pad bytes. 119 // 120 update((byte)128); 121 122 while (xBufOff != 0) 123 { 124 update((byte)0); 125 } 126 127 processLength(bitLength); 128 129 processBlock(); 130 } 131 132 public void reset() 133 { 134 byteCount = 0; 135 136 xBufOff = 0; 137 for (int i = 0; i < xBuf.length; i++) 138 { 139 xBuf[i] = 0; 140 } 141 } 142 143 protected void populateState(byte[] state) 144 { 145 System.arraycopy(xBuf, 0, state, 0, xBufOff); 146 Pack.intToBigEndian(xBufOff, state, 4); 147 Pack.longToBigEndian(byteCount, state, 8); 148 } 149 150 public int getByteLength() 151 { 152 return BYTE_LENGTH; 153 } 154 155 protected abstract void processWord(byte[] in, int inOff); 156 157 protected abstract void processLength(long bitLength); 158 159 protected abstract void processBlock(); 160 } 161