1   /* $RCSfile: RIPEMD160MessageDigestEngine.java,v $
2    * $Revision: 1.6 $
3    * $Date: 2003/10/04 19:18:38 $
4    * $Author: uwe_guenther $
5    * $State: Exp $
6    *
7    * Created on July 4, 2001, 1:01 PM
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.security.DigestException;
35  import java.security.MessageDigestSpi;
36  
37  /**
38   * RIPEMD160MessageDigestEngine Class.
39   * 
40   * This class does the RIPEMD-160 algorithm via delegation to 
41   * RIPEMD160MessageDigestImpl and is implemented as JCA (Java Cryptogrphy Architecture)
42   * Service Provider. You can not instance these class
43   * direct, because it is enabled through the JCA API.
44   *
45   *
46   * <p>The sum of all added bytes from {@link #engineUpdate(byte)
47   * engineUpdate(byte)} and {@link #engineUpdate(byte[], int, int) 
48   * engineUpdate(byte[], int, int)} are processed by the RIPEMD-160
49   * message digest algorithm with {@link #engineDigest() engineDigest()} or
50   * {@link #engineDigest(byte[] , int, int) engineDigest(byte[], int, int)}.
51   *
52   * <pre>
53   *
54   * How does it work:
55   * =================
56   *
57   * RIPEMD-160 works only with whole 512 bit blocks.
58   *
59   *        512bits == 64 bytes == 16 words
60   * -------------------------------------------------
61   * |00|01|02|03|04|05|06|07|08|09|10|11|12|13|14|15|
62   * -------------------------------------------------
63   *                    /  \
64   *                   /    \
65   *                  /      \
66   *                 /        \
67   *                /          \
68   *               -------------
69   *               |32 bit word|   <-- 32 bit word = 4 byte
70   *               -------------
71   *               |00|01|02|03|   <-- 4 bytes = 4 x 8 bit = 32 bit
72   *               -------------
73   *
74   * </pre>
75   *
76   * <p>Here is a simple Code Example:
77   * 
78   * <pre>
79   *
80   * import java.security.Security;
81   * import java.security.Provider;
82   * import java.security.MessageDigest;
83   * import java.security.NoSuchAlgorithmException;
84   * import de.cscc.crypto.provider.HBCI;
85   * import java.io.IOException;
86   *
87   * public class MyMessageDigest{
88   *  public static void main(String args[]){
89   *   
90   *    // add Provider
91   *    int i = Security.addProvider(new de.cscc.crypto.provider.JHBCI());
92   *    System.out.println("Provider inserted at position " + i + ".");
93   *
94   *    // get provider
95   *    Provider p = Security.getProvider("JHBCI");
96   *    System.out.println("My Provider Name is " + p.getName());
97   *    System.out.println("My Provider Version is " + p.getVersion());
98   *    System.out.println("My Provider Info is " + p.getInfo());
99   *
100  *    // get MessageDigest Object through the JCA API
101  *    MessageDigest myRIPEMD1 = null;
102  *    MessageDigest myRIPEMD2 = null,
103  *
104  *    try{
105  *        myRIPEMD1 = MessageDigest.getInstance("RIPEMD160");
106  *    } catch(NoSuchAlgorithmException e){
107  *        e.printStackTrace();
108  *    }
109  *
110  *    // put the messaeg in the MessageDigest object
111  *    byte[] myByte = {'a','b','c'};
112  *    myRIPEMD1.update(myByte);
113  *
114  *    // clone the object
115  *    try {
116  *        myRIPEMD2 = myRIPEMD1.clone
117  *    } catch (CloneNotSupportedException e) {
118  *        e.printStackTrace();
119  *    }
120  *
121  *    // get the Message Digests
122  *    byte[] messageDigest1 = myRIPEMD1.digest();
123  *    byte[] messageDigest2 = myRIPEMD2.digest();
124  *
125  *    // now the byte arrays messageDigest[12] holds a 20 byte long message
126  *    // digest of the message "abc" and should be in binary form:
127  *    // 0x8eb208f7e05d987a9b044a8e98c6b087f15a0bfc
128  *
129  *    // verify the two digests
130  *    boolean verify = MessageDigest.isEqual(messageDigest1, messageDigest2);
131  *    System.out.println("The two digests are equal: " + verify);
132  *  }
133  * }
134  * </pre>
135  *
136  * @author  <a href=mailto:uwe@cscc.de>Uwe G&uuml;nther</a>
137  * @version $Revision: 1.6 $
138  */
139 public final class RIPEMD160MessageDigestEngine 
140 extends MessageDigestSpi implements Cloneable {
141 
142     /**
143      * Object to which we delegate all working crypto stuff from these method.
144      */    
145     private RIPEMD160MessageDigestImpl md = 
146     new RIPEMD160MessageDigestImpl();
147     
148     /**
149      * Creates new RIPEMD160MessageDigestEngine. This default constructor is
150      * invoked from <code>java.security.MessageDigest.getInstance()</code>.
151      */
152     public RIPEMD160MessageDigestEngine() {
153         if (JHBCI.selfIntegrityChecking() == false) {
154             throw new SecurityException("JHBCI-Provider is tampered.");
155         }    
156     }
157     
158     /** 
159      * Creates and returns a deep of this object.
160      * @return a clone of this instance.
161      * @see java.lang.Cloneable
162      * @exception CloneNotSupportedException if the object's class does not
163      *             support the <code>Cloneable</code> interface. Subclasses
164      *             that override the <code>clone</code> method can also
165      *             throw this exception to indicate that an instance cannot
166      *             be cloned.
167      */
168     public Object clone() throws CloneNotSupportedException {
169         RIPEMD160MessageDigestEngine result = 
170         (RIPEMD160MessageDigestEngine) super.clone();
171         result.md = (RIPEMD160MessageDigestImpl) this.md.clone();
172         return result;
173     }        
174     
175     /**
176      * Compares two RIPEMD160MessageDigestEngine objects. If the private members
177      * of obj are equal wtih the private members of this object the method
178      * will return true, otherwise false.
179      * @param obj RIPEMD160MessageDigestEngine object to compare.
180      * @return true if the objects are deeply equal.
181      */    
182     public boolean equals(Object obj) {
183         //Only for performance.
184         if (this == obj) {
185             return true;
186         } 
187         
188         //If obj == null then instanceof returns false, see JLS 15.20.2
189         if (!(obj instanceof RIPEMD160MessageDigestEngine)) {           
190              return false;
191         }
192          
193         RIPEMD160MessageDigestEngine other = (RIPEMD160MessageDigestEngine)obj;
194         return this.md.equals(other.md);
195     }
196     
197     /** 
198      * Returns a hash code value for the object. This method is
199      * supported for the benefit of hashtables such as those provided by
200      * <code>java.util.Hashtable</code>.
201      *
202      * @return  a hash code value for this object.
203      * @see     #equals(java.lang.Object)
204      * @see     java.util.Hashtable
205      */
206     public int hashCode() {
207         int result = 17;
208         result = 37*result + this.md.hashCode();
209         return result;
210     }        
211     
212     /**
213      * Returns a string representation of the object. 
214      * @return  a string representation of the object.
215      */
216     public String toString() {
217         return this.md.toString();
218     }
219     
220     /**
221      * If the whole message added to the message digest object, you should
222      * invoke the digest method at your API object (MessageDigest). The wraper
223      * invokes these method to return the 160 bit RIPEMD-160 digest at a byte
224      * array (20 byte or 160 bit).
225      * @return the message digest in 20 byte long byte array.
226      * This byte array contains the 160 bit digest in binary form.
227      */
228     protected byte[] engineDigest() {
229         return this.md.digest();
230     }
231     
232     /**
233      * If the whole message added to the message digest object, you should
234      * invoke the digest method at your API Object (MessageDigest). The Wraper
235      * invokes these method to return the 160 bit RIPEMD-160 digest at a byte
236      * array (20 byte or 160 bit).
237      * @param buf the message digest in 20 byte long byte array.
238      * This byte array contains the 160 bit digest in binary form.
239      * @param offset begin of buffer.
240      * @param len end of buffer.
241      * @throws DigestException If the difference between len-offset less than
242      * 20 bytes a DigestException will be thrown.
243      * @return the length of the digest stored in the output buffer.
244      */
245     protected int engineDigest(byte[] buf, int offset, int len) 
246     throws DigestException {
247         return this.md.digest(buf, offset, len);
248     }
249     
250     /**
251      * Returns the length of the message digest in byte. In case of RIPEMD-160
252      * it will be 20.
253      * @return digest length (20) in byte.
254      */
255     protected int engineGetDigestLength() {
256         return this.md.getDigestLength();
257     }
258     
259     /** Resets the message digest object, for further use. So if you have
260      * calculated your digest, you should invoke reset() through the JCA API 
261      * that invokes this engineReset method to reset the object to calculate an 
262      * new digest from a new message.
263      */
264     protected void engineReset() {
265         this.md.reset();
266     }
267     
268     /**
269      * Updates the internal message buffer with <CODE>byte value</CODE>.
270      * @param value message byte.
271      */
272     protected void engineUpdate(byte value) {
273         this.md.update(value);
274     }
275     
276     /**
277      * Updates the internal message buffer with <CODE>byte[] value</CODE>,
278      * starting at offset, ending at len.
279      * @param values message byte array.
280      * @param offset begin of message byte array.
281      * @param len end of message byte array.
282      */
283     protected void engineUpdate(byte[] values, int offset, int len) {
284         this.md.update(values, offset, len);
285     }
286 }
287