1   /* $RCSfile: ISO9796Part1WithRSASignatureByteBuffer.java,v $
2    * $Revision: 1.2 $
3    * $Date: 2002/11/03 17:38:42 $
4    * $Author: uwe_guenther $
5    * $State: Exp $
6    *
7    * Created on October 20, 2002 3:27 PM
8    *
9    * Copyright (C) 2002 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  /** 
40   * ISO9796Part1WithRSASignatureByteBuffer Class.
41   *
42   * @author  <a href=mailto:uwe@cscc.de>Uwe G&uuml;nther</a>
43   *
44   * @version $Revision: 1.2 $
45   */
46  final class ISO9796Part1WithRSASignatureByteBuffer implements Cloneable {
47  
48      private static final int MESSAGE_LENGTH = 20;
49  
50      private byte[] buffer;
51      private int bufferCounter;
52  
53      /**
54       * Constructor for ISO9796Part1WithRSASignatureByteBuffer.
55       */
56      public ISO9796Part1WithRSASignatureByteBuffer() {
57          reset();
58      }
59      
60      /**
61       * Creates and returns a deep copy of this object.
62       *
63       * @return a clone of this instance.
64       * @see java.lang.Cloneable
65       * @exception CloneNotSupportedException if the object's class does not
66       *             support the <code>Cloneable</code> interface. Subclasses
67       *             that override the <code>clone</code> method can also
68       *             throw this exception to indicate that an instance cannot
69       *             be cloned. */
70      public Object clone() throws CloneNotSupportedException {
71  
72          //Create the new object "result".
73          ISO9796Part1WithRSASignatureByteBuffer result = 
74                  (ISO9796Part1WithRSASignatureByteBuffer) super.clone();
75          
76          //Fix the shallow copies to deep copies
77          result.buffer = (byte[]) this.buffer.clone();
78          
79          //Return the new fixed object "result".
80          return result;
81      }
82      
83      /** 
84       * Indicates whether some other object is "equal to" this one.
85       *
86       * @param   obj   the reference object with which to compare.
87       * @return  <code>true</code> if this object is the same as the obj
88       *           argument; <code>false</code> otherwise.
89       * @see     #hashCode()
90       * @see     java.util.Hashtable
91       */
92      public boolean equals(Object obj) {
93          
94          //Only for performance.
95          if (this == obj) {
96              return true;
97          }
98          
99          //If obj == null then instanceof returns false, see JLS 15.20.2                   
100         if (!(obj instanceof ISO9796Part1WithRSASignatureByteBuffer)) {            
101             return false;
102         }
103         
104         ISO9796Part1WithRSASignatureByteBuffer other = 
105                 (ISO9796Part1WithRSASignatureByteBuffer) obj;
106                 
107         return this.bufferCounter == other.bufferCounter &&
108                 Arrays.equals(this.buffer, other.buffer);
109     }
110     
111     /**
112      * Returns a hash code value for the object. 
113      *
114      * @return  a hash code value for this object.
115      * @see     #equals(java.lang.Object)
116      * @see     java.util.Hashtable
117      */
118     public int hashCode() {
119        
120         int result = 17;
121         
122         result = 37*result + bufferCounter;
123         
124         for (int i = 0; i < this.buffer.length; i++) {
125             result = 37*result + buffer[i];
126         } 
127         
128         return result;
129     }
130     
131     /**
132      * Returns a string representation of the object. 
133      *
134      * @return  a string representation of the object.
135      */
136     public String toString() {
137         
138         return "buffer: [" + ByteUtil.toHex(this.buffer) + "] " +
139                "bufferCounter: [" + this.bufferCounter + "]";
140     }
141 
142    /**
143      * Appends value to the internal buffer.
144      *
145      * @param value message byte.
146      */
147     public void add(byte value) {
148         if (isMessageBufferLargeEnough()) {
149             //append byte to buffer
150             this.buffer[this.bufferCounter] = value;
151             this.bufferCounter++;
152         } else {  // internal buffer isn't large enough
153             //enlarge our internal buffer 
154             byte[] tempMessage = this.buffer;
155             this.buffer = new byte[tempMessage.length + MESSAGE_LENGTH];
156             System.arraycopy(tempMessage, 0, this.buffer, 0, tempMessage.length);
157             
158             //append byte into our internal buffer
159             this.buffer[this.bufferCounter] = value;
160             this.bufferCounter++;
161         }
162     }
163     
164     /**
165      * Appends <code>byte[] value</code> (starting at offset, ending at len) to 
166      * the internal buffer.
167      * 
168      * @param values buffer byte array.
169      * @param offset begin of buffer byte array.
170      * @param len end of buffer byte array.
171      * 
172      * @throws NullPointerException if values is null.
173      * @throws IllegalArgumentException if the combination of 
174      *         <code>values</code>, <code>offset</code> and <code>len</code>
175      *         isn't plausible.
176      *         
177      */
178     public void add(byte[] values, int offset, int len) {
179         
180         if (values == null) {
181             throw new NullPointerException("Parameter values is null.");
182         }
183         if (offset < 0) {
184             throw new IllegalArgumentException("Parameter offset is less " +
185             "than zero.");
186         }
187         if (len < 0) {
188             throw new IllegalArgumentException("Parameter len is less " +
189             "than zero.");        
190         }
191         if (offset + len > values.length) {
192             throw new IllegalArgumentException("Parameter offset + len is " +
193             "greater than outbuf.length .");
194         }                
195         
196         //append our values to the internal buffer.
197         for (int i = offset; i < offset+len; i++) {
198             add(values[i]);
199         }
200     } 
201     
202     /**
203      * Fetches the whole buffer from our internal buffer.
204      * 
205      * @return the buffer as ISO9796Part1BitString.
206      */
207     public ISO9796Part1BitString fetch() {
208         if (isEmpty()) {
209             throw new IllegalStateException(
210                     "You have to add at least one byte to the buffer " +
211                     "after an new object instatiation or an reset() " +
212                     "befor you can fetch.");
213         }
214         
215         
216         //copy _only_ the used bytes from this.buffer to the result.
217         byte[] tempMessage = new byte[this.bufferCounter];
218         System.arraycopy(this.buffer, 0, tempMessage, 0, tempMessage.length);
219         
220         return new ISO9796Part1BitString(tempMessage, this.bufferCounter * 8);
221     }    
222        
223     /**
224      * Resets our internal buffer to the same state as you ould be create a new
225      * object. Say we recycle the object with reset.
226      */
227     public void reset() {
228         //release the old buffer byte array and get a new one.
229         this.buffer = new byte[MESSAGE_LENGTH ];
230         this.bufferCounter = 0;
231     }  
232     
233     /**
234      * Checks if our internal buffer is empty.
235      *
236      * @return true if the buffer is empty, false otherwise.
237      */
238     public boolean isEmpty() {
239         return this.bufferCounter < 1;
240     }  
241             
242     /**
243      * Method isMessageBufferLargeEnough cecks if our internal buffer is large
244      * enough.
245      * 
246      * @return true if our internal buffer is large enough.
247      */
248     private boolean isMessageBufferLargeEnough() {
249         return (this.bufferCounter < this.buffer.length);
250     }    
251 
252 }
253