001: /* This was:
002: * Id: PaddingMD.java,v 1.8 2001/06/25 15:39:55 gelderen Exp
003: * http://anoncvs.cryptix.org/cvs.php/projects/jce/src/cryptix.jce.provider.md/PaddingMD.java
004: * Copyright (C) 1995-2000 The Cryptix Foundation Limited.
005: * All rights reserved.
006: *
007: * Use, modification, copying and distribution of this software is subject to
008: * the terms and conditions of the Cryptix General Licence. You should have
009: * received a copy of the Cryptix General Licence along with this library;
010: * if not, you can download a copy from http://www.cryptix.org/
011:
012: * Redistribution and use in source and binary forms, with or without
013: * modification, are permitted provided that the following conditions
014: * are met:
015:
016: * Redistributions of source code must retain the copyright notice,
017: * this list of conditions and the following disclaimer.
018:
019: * Redistributions in binary form must reproduce the above copyright
020: * notice, this list of conditions and the following disclaimer in the
021: * documentation and/or other materials provided with the
022: * distribution.
023:
024: * THIS SOFTWARE IS PROVIDED BY THE CRYPTIX FOUNDATION LIMITED AND
025: * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
026: * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
027: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
028: * DISCLAIMED. IN NO EVENT SHALL THE CRYPTIX FOUNDATION LIMITED OR
029: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
030: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
031: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
032: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
033: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
034: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
035: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
036: * SUCH DAMAGE.
037: */
038:
039: package uk.org.ponder.hashutil;
040:
041: import java.security.DigestException;
042:
043: /**
044: * This abstract class implements the MD4-like block/padding structure as it is
045: * used by most hashes (MD4, MD5, SHA-0, SHA-1, RIPEMD-128, RIPEMD-160, Tiger).
046: *
047: * This class handles the message buffering, bit counting and padding.
048: * Subclasses need implement only the three abstract functions to create a
049: * working hash.
050: *
051: * This class has three padding modes: MD5-like, SHA-like and Tiger-like.
052: * This applies to the padding and encoding of the 64-bit length counter.
053: *
054: * @version Revision: 1.8
055: * @author Jeroen C. van Gelderen (gelderen@cryptix.org)
056: */
057:
058: abstract class PaddingMD extends MessageDigestSpi {
059:
060: // Constants
061: //...........................................................................
062:
063: private static final int DEFAULT_BLOCKSIZE = 64;
064:
065: // Instance variables
066: //...........................................................................
067:
068: /** Size (in bytes) of the blocks. */
069: private final int blockSize;
070:
071: /** Size (in bytes) of the digest */
072: private final int hashSize;
073:
074: /** 64 byte buffer */
075: private final byte[] buf;
076:
077: /** Buffer offset */
078: private int bufOff;
079:
080: /** Number of bytes hashed 'till now. */
081: private long byteCount;
082:
083: /** Mode */
084: private final int mode;
085:
086: /*package*/static final int MODE_MD = 0, MODE_SHA = 1,
087: MODE_TIGER = 2;
088:
089: // Constructors
090: //...........................................................................
091:
092: /**
093: * Construct a 64-byte PaddingMD in MD-like, SHA-like or Tiger-like
094: * padding mode.
095: *
096: * The subclass must call this constructor, giving the length of its hash
097: * in bytes.
098: *
099: * @param hashSize Length of the hash in bytes.
100: */
101: protected PaddingMD(int hashSize, int mode) {
102: // THIS METHOD HACKED BY AMB 12/7/01 to avoid blank final error with
103: // prehistoric javac.
104: this .blockSize = DEFAULT_BLOCKSIZE;
105: this .hashSize = hashSize;
106: this .buf = new byte[blockSize];
107: this .bufOff = 0;
108: this .byteCount = 0;
109: this .mode = mode;
110:
111: }
112:
113: /**
114: * Construct a 64 or 128-byte PaddingMD in MD-like, SHA-like or Tiger-like
115: * padding mode.
116: *
117: * @param hashSize Length of the hash in bytes.
118: */
119: protected PaddingMD(int blockSize, int hashSize, int mode) {
120: if (blockSize != 64 && blockSize != 128)
121: throw new RuntimeException("blockSize must be 64 or 128!");
122:
123: this .blockSize = blockSize;
124: this .hashSize = hashSize;
125: this .buf = new byte[blockSize];
126: this .bufOff = 0;
127: this .byteCount = 0;
128: this .mode = mode;
129: }
130:
131: protected PaddingMD(PaddingMD src) {
132: this .blockSize = src.blockSize;
133: this .hashSize = src.hashSize;
134: this .buf = (byte[]) src.buf.clone();
135: this .bufOff = src.bufOff;
136: this .byteCount = src.byteCount;
137: this .mode = src.mode;
138: }
139:
140: public Object clone() throws CloneNotSupportedException {
141: throw new CloneNotSupportedException(
142: "You have just found a bug!");
143: }
144:
145: // Implementation
146: //...........................................................................
147:
148: protected int engineGetDigestLength() {
149: return this .hashSize;
150: }
151:
152: protected void engineUpdate(byte input) {
153: //#ASSERT(this.bufOff < blockSize);
154:
155: byteCount += 1;
156: buf[bufOff++] = input;
157: if (bufOff == blockSize) {
158: coreUpdate(buf, 0);
159: bufOff = 0;
160: }
161:
162: //#ASSERT(this.bufOff < blockSize);
163: }
164:
165: protected void engineUpdate(byte[] input, int offset, int length) {
166: byteCount += length;
167:
168: //#ASSERT(this.bufOff < blockSize);
169:
170: int todo;
171: while (length >= (todo = blockSize - this .bufOff)) {
172: System
173: .arraycopy(input, offset, this .buf, this .bufOff,
174: todo);
175: coreUpdate(this .buf, 0);
176: length -= todo;
177: offset += todo;
178: this .bufOff = 0;
179: }
180:
181: //#ASSERT(this.bufOff < blockSize);
182:
183: System.arraycopy(input, offset, this .buf, this .bufOff, length);
184: bufOff += length;
185: }
186:
187: protected byte[] engineDigest() {
188: byte[] tmp = new byte[hashSize];
189: privateDigest(tmp, 0, hashSize);
190: return tmp;
191: }
192:
193: protected int engineDigest(byte[] buf, int offset, int len)
194: throws DigestException {
195: if (len < hashSize)
196: throw new DigestException();
197:
198: return privateDigest(buf, offset, len);
199: }
200:
201: /**
202: * Same as protected int engineDigest(byte[] buf, int offset, int len)
203: * except that we don't validate arguments.
204: */
205: private int privateDigest(byte[] buf, int offset, int len) {
206: //#ASSERT(this.bufOff < blockSize);
207:
208: this .buf[this .bufOff++] = (mode == MODE_TIGER) ? (byte) 0x01
209: : (byte) 0x80;
210:
211: int lenOfBitLen = (blockSize == 128) ? 16 : 8;
212: int C = blockSize - lenOfBitLen;
213: if (this .bufOff > C) {
214: while (this .bufOff < blockSize)
215: this .buf[this .bufOff++] = (byte) 0x00;
216:
217: coreUpdate(this .buf, 0);
218: this .bufOff = 0;
219: }
220:
221: while (this .bufOff < C)
222: this .buf[this .bufOff++] = (byte) 0x00;
223:
224: long bitCount = byteCount * 8;
225: if (blockSize == 128)
226: for (int i = 0; i < 8; i++)
227: this .buf[this .bufOff++] = 0x00;
228:
229: if (mode == MODE_SHA) {
230: // 64-bit length is appended in big endian order
231: for (int i = 56; i >= 0; i -= 8)
232: this .buf[this .bufOff++] = (byte) (bitCount >>> (i));
233: } else {
234: // 64-bit length is appended in little endian order
235: for (int i = 0; i < 64; i += 8)
236: this .buf[this .bufOff++] = (byte) (bitCount >>> (i));
237: }
238:
239: coreUpdate(this .buf, 0);
240: coreDigest(buf, offset);
241:
242: engineReset();
243: return hashSize;
244: }
245:
246: protected void engineReset() {
247: this .bufOff = 0;
248: this .byteCount = 0;
249: coreReset();
250: }
251:
252: // Delegated methods
253: //...........................................................................
254:
255: /**
256: * Return the hash bytes in <code>buf</code>, starting at offset
257: * <code>off</code>.
258: *
259: * The subclass is expected to write exactly <code>hashSize</code> bytes
260: * in the given buffer. The buffer is guaranteed to be large enough.
261: */
262: protected abstract void coreDigest(byte[] buf, int off);
263:
264: /**
265: * Reset the hash internal structures to initial state.
266: */
267: protected abstract void coreReset();
268:
269: /**
270: * Update the internal state with a single block.
271: *
272: * <code>buf</code> contains a single block (64 bytes, 512 bits) of data,
273: * starting at offset <code>off</code>.
274: */
275: protected abstract void coreUpdate(byte[] buf, int off);
276: }
|