1   /* $RCSfile: RIPEMD160ByteBuffer.java,v $
2    * $Revision: 1.10 $
3    * $Date: 2002/01/17 19:24:55 $
4    * $Author: uwe $
5    * $State: Exp $
6    *
7    * Created on July 14, 2001, 11:46 AM
8    *
9    * Copyright (C) 2001 Uwe Guenther <uwe@cscc.de>
10   *
11   * This file is part of the jhbci JCE-ServiceProvider. The jhbci JCE-
12   * ServiceProvider is a library, written in JavaTM, that should be 
13   * used in HBCI banking applications (clients and may be servers),
14   * to do cryptographic operations.
15   *
16   * The jhbci library is free software; you can redistribute it and/or
17   * modify it under the terms of the GNU Lesser General Public
18   * License as published by the Free Software Foundation; either
19   * version 2.1 of the License, or (at your option) any later version.
20   *
21   * The jhbci library is distributed in the hope that it will be useful,
22   * but WITHOUT ANY WARRANTY; without even the implied warranty of
23   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24   * Lesser General Public License for more details.
25   *
26   * You should have received a copy of the GNU Lesser General Public
27   * License along with this library; if not, write to the Free Software
28   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
29   *
30   */
31  
32  package de.cscc.crypto.provider;
33  
34  import java.util.Arrays;
35  
36  import de.cscc.crypto.util.ByteUtil;
37  
38  /** 
39   * Internal byte buffer Class.
40   *
41   * @author  <a href=mailto:uwe@cscc.de>Uwe G&uuml;nther</a>
42   * @version $Revision: 1.10 $
43   */
44  class RIPEMD160ByteBuffer implements Cloneable {
45  
46      /** Length of the internal buffer. */    
47      private static final int BUFFER_LENGTH = 4;
48      
49      /** Internal buffer. */    
50      private byte[] buffer = new byte[BUFFER_LENGTH];
51  
52      /** Counts how full is the internal <CODE>buffer</CODE>. */
53      private int bufferOffset = 0;
54      
55      /** Creates new RIPEMD160ByteBuffer. */
56      public RIPEMD160ByteBuffer() {}
57      
58      /** 
59       * Creates and returns a deep copy of this object.
60       * @return a clone of this instance.
61       * @see java.lang.Cloneable
62       * @exception CloneNotSupportedException if the object's class does not
63       *             support the <code>Cloneable</code> interface. Subclasses
64       *             that override the <code>clone</code> method can also
65       *             throw this exception to indicate that an instance cannot
66       *             be cloned.
67       */
68      public Object clone() throws CloneNotSupportedException {
69          RIPEMD160ByteBuffer result = (RIPEMD160ByteBuffer) super.clone();
70          result.buffer = (byte[]) this.buffer.clone();
71          return result;
72      }    
73      
74      /** 
75       * Indicates whether some other object is "equal to" this one.
76       *
77       * @param   obj   the reference object with which to compare.
78       * @return  <code>true</code> if this object is the same as the obj
79       *         argument; <code>false</code> otherwise.
80       * @see     #hashCode()
81       * @see     java.util.Hashtable
82       */
83      public boolean equals(Object obj) {
84          //Only for performance.
85          if (this == obj) {
86              return true;
87          } 
88          
89          //If obj == null then instanceof returns false, see JLS 15.20.2
90          if (!(obj instanceof RIPEMD160ByteBuffer)) {
91              return false;
92          }
93          
94          RIPEMD160ByteBuffer other = (RIPEMD160ByteBuffer)obj;
95          //return (Arrays.equals(this.buffer, temp.buffer) &&
96          //        this.bufferOffset == temp.bufferOffset  );
97          if (this.bufferOffset != other.bufferOffset) {
98              return false; //not equal
99          }
100         for (int i = 0; i < this.bufferOffset; i++) {
101             if (this.buffer[i] != other.buffer[i]) {
102                 return false; //not equal
103             }
104         }
105         return true; //equal
106     }
107     
108     /** 
109      * Returns a hash code value for the object. This method is
110      * supported for the benefit of hashtables such as those provided by
111      * <code>java.util.Hashtable</code>.
112      *
113      * @return  a hash code value for this object.
114      * @see     #equals(java.lang.Object)
115      * @see     java.util.Hashtable
116      */
117     public int hashCode() {
118         int result = 17;
119         for (int i = 0; i < this.bufferOffset; i++) {
120             result = 37*result + this.buffer[i];
121         }
122         return result;
123     }    
124 
125     /**
126      * Returns a string representation of the object.
127      *
128      * @return  a string representation of the object.
129      */
130     public String toString() {
131         return "[bufferOffset: " + this.bufferOffset + 
132                " buffer: " + ByteUtil.toHex(buffer) + "]";
133     }    
134     
135     /**
136      * Indicates if the buffer is not empty.
137      * @return true if the buffer is not empty.
138      */    
139     public boolean isNotEmpty() {
140         return (this.bufferOffset != 0);
141     }
142     
143     /**
144      * Indicates if the buffer is full.
145      * @return true if the buffer is full.
146      */    
147     public boolean isFull() {
148         return (this.bufferOffset == RIPEMD160ByteBuffer.BUFFER_LENGTH);
149     }
150     
151     /** Resets the internal buffer and its offset counter. */    
152     public void reset() {
153         Arrays.fill(this.buffer, (byte)0x00);
154         bufferOffset = 0;
155     }
156     
157     /** 
158      * Fills the internal buffer with bytes. If there are more than 4 bytes
159      * added, you should call {@link #reset() reset()}. Otherwise the
160      * ArrayIndexOutOfBoundsException will be thrown.
161      *
162      * @param in byte that will be added to the internal buffer.
163      * @throws ArrayIndexOutOfBoundsException there are more than 16 words added.
164      */    
165     public void set(byte in) throws ArrayIndexOutOfBoundsException {
166         
167         // if the Buffer is full, we a ArrayIndexOutOfBoundsException
168         // the user must take of the buffer management with isFull() and 
169         // isEmpty()
170         if (isFull()) {
171             throw new ArrayIndexOutOfBoundsException(bufferOffset);
172         }
173         
174         this.buffer[this.bufferOffset] = in;
175         this.bufferOffset++;
176     }
177     
178     /**
179      * In RIPEMD-160 a "word" is a 32-bit quantity and a "byte" is an
180      * eight-bit quantity. A sequence of bits can be interpreted in a
181      * natural manner as a sequence of bytes, where each consecutive group
182      * of eight bits is interpreted as a byte with the high-order (most
183      * significant) bit of each byte listed first. Similarly, a sequence of
184      * bytes can be interpreted as a sequence of 32-bit words, where each
185      * consecutive group of four bytes is interpreted as a word with the
186      * low-order (least significant) byte given first. This means that the
187      * byteBuffer[4]will be moved to the 32 bit word with little endian 
188      * byte order. Here follows a example:
189      *
190      * <pre>
191      *
192      * Buffer fill operation:
193      * ====================== 
194      * wordBuffer[0] = (byte)0x11;
195      * wordBuffer[1] = (byte)0xaa;
196      * wordBuffer[2] = (byte)0xbb;
197      * wordBuffer[3] = (byte)0xcc;
198      *
199      * wordBuffer memory representation: 0x11aabbcc      <- important!
200      *                                     --    --
201      *                                    /        \
202      *                             lowest           highest        
203      *                             memory           memory
204      *                             address          address
205      *                           (e.g.0x2000)       (e.g.0x2003)
206      *
207      * Now we fill the byte array in 32 bit word (int):
208      * ------------------------------------------------
209      * empty int: 0x00000000
210      *              --    --
211      *             /        \
212      *        most           least
213      *        significant    significant
214      *        byte           byte
215      *       
216      *        lowest         highest
217      *        memory         memory
218      *        address        address
219      *        (e.g.0x2000)   (e.g.0x2003)
220      *
221      * word after fill with the byteBuffer[4] byte array: 0xccbbaa11
222      *                                                    ^^^^^^^^^^
223      *                                                    important!
224      *
225      * word memory representation is also: 0xccbbaa11    <- important!
226      *
227      * </pre>
228      *
229      * <p>For Java conversion and promotion question, see in the Book
230      * "The Java Language Specification Second Edition" by
231      * James Gosling, Bill Joy, Guy Steel and Gilard Bracha
232      * ISBN: 0-202-31008-2
233      *  A serious Java programmer should have this book in his book shelf!!!
234      * 
235      *
236      * @return the word that contains the 4bytes in little endian byte order.
237      */    
238     public int toWord(){
239 
240         return ((this.buffer[0] & 0x000000ff)         |
241                ((this.buffer[1] & 0x000000ff) << 8)   |
242                ((this.buffer[2] & 0x000000ff) << 16)  |
243                ((this.buffer[3] & 0x000000ff) << 24) );        
244     }
245 }
246