1   /* $RCSfile: PaddingSingleBuffer.java,v $
2    * $Revision: 1.8 $
3    * $Date: 2002/01/17 19:24:55 $
4    * $Author: uwe $
5    * $State: Exp $
6    *
7    * Created on August 20, 2001 1:58 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.util.Arrays;
35  
36  import javax.crypto.IllegalBlockSizeException;
37  
38  import de.cscc.crypto.util.ByteUtil;
39  
40  /** 
41   * PaddingSingleBuffer Class.
42   *
43   * @author  <a href=mailto:uwe@cscc.de>Uwe G&uuml;nther</a>
44   * @version $Revision: 1.8 $
45   */
46  class PaddingSingleBuffer implements Cloneable {
47  
48      /** The internal buffer. */    
49      private byte[] buffer;
50      
51      /** The internal buffer counter. */    
52      private int bufferCounter;
53      
54      /** Don't create PaddingSingleBuffer with default constructor. */
55      private PaddingSingleBuffer() {}
56      
57      /** 
58       * Create a new buffer with size bytes.
59       * @param size the buffer length in bytes.
60       */    
61      public PaddingSingleBuffer(int size) {
62          
63          this.buffer        = new byte[size];
64          this.bufferCounter = 0;
65      }    
66      
67      /** 
68       * Create a new buffer from an existing buffer.
69       * @param buffer the existing buffer.
70       */    
71      public PaddingSingleBuffer(PaddingSingleBuffer buffer) {
72          
73          this.buffer = new byte[buffer.buffer.length];
74          System.arraycopy(buffer.buffer, 0, this.buffer, 0, buffer.buffer.length);
75          
76          this.bufferCounter = buffer.bufferCounter;
77      }    
78  
79      /** 
80       * Creates and returns a deep copy of this object.
81       *
82       * @return a clone of this instance.
83       * @see java.lang.Cloneable
84       * @exception CloneNotSupportedException if the object's class does not
85       *             support the <code>Cloneable</code> interface. Subclasses
86       *             that override the <code>clone</code> method can also
87       *             throw this exception to indicate that an instance cannot
88       *             be cloned. 
89       */
90      public Object clone() throws CloneNotSupportedException {
91          PaddingSingleBuffer result = (PaddingSingleBuffer) super.clone();
92          result.buffer = (byte[]) this.buffer.clone();
93          return result;
94      }
95      
96      /** 
97       * Indicates whether some other object is "equal to" this one.
98       *
99       * @param   obj   the reference object with which to compare.
100      * @return  <code>true</code> if this object is the same as the obj
101      *         argument; <code>false</code> otherwise.
102      * @see     #hashCode()
103      * @see     java.util.Hashtable
104      */
105     public boolean equals(Object obj) {
106 
107         //Only for performance.
108         if (this == obj) {
109             return true;
110         } 
111         
112         //If obj == null then instanceof returns false, see JLS 15.20.2
113         if (!(obj instanceof PaddingSingleBuffer)) {            
114             return false;
115         }
116 
117         PaddingSingleBuffer other = (PaddingSingleBuffer) obj;
118         return this.bufferCounter == other.bufferCounter &&
119                Arrays.equals(this.buffer, other.buffer)   ;
120     }
121     
122     /**
123      * Returns a hash code value for the object. 
124      *
125      * @return  a hash code value for this object.
126      * @see     #equals(java.lang.Object)
127      * @see     java.util.Hashtable
128      */
129     public int hashCode() {
130         
131         int result = 17;
132         
133         result = 37*result + bufferCounter;
134         
135         for (int i = 0; i < this.buffer.length; i++) {
136             result = 37*result + buffer[i];
137         } 
138         
139         return result;
140     }
141     
142     /**
143      * Returns a string representation of the object. 
144      *
145      * @return  a string representation of the object.
146      */
147     public String toString() {
148         
149         return "buffer: [" + ByteUtil.toHex(this.buffer) + "] " +
150                "bufferCounter: [" + this.bufferCounter + "]";
151     }
152     
153     /** 
154      * Add a byte to the buffer.
155      * @param b the byte to add.
156      * @throws IllegalArgumentException if the internal buffer is full.
157      */    
158     public void add(byte b) throws IllegalArgumentException {
159         
160         if (isFull()) {
161             throw new IllegalArgumentException("Buffer is full.");
162         }
163         
164         this.buffer[this.bufferCounter] = b;
165         this.bufferCounter++;
166     }
167     
168     /** 
169      * Returns the internal buffer and create an new internal buffer.
170      * This means we will return the internal byte array and will reset it.
171      *
172      * @return the number off bytes that stored in output.
173      * @param output the output buffer.
174      * @param outputOffset the offset in output where output starts.
175      * @throws IllegalBlockSizeException if the usable range is lesser than the
176      * initial size  with this buffer was constructed.
177      */    
178     public int fetch(byte[] output, int outputOffset) 
179             throws IllegalBlockSizeException {
180                 
181         if (output.length-outputOffset < this.buffer.length) {
182             throw new IllegalBlockSizeException("The input block range is " 
183                     + (output.length-outputOffset) 
184                     + " bytes long, but it should be " +  this.buffer.length  
185                     + " or longer.");
186         }                  
187 
188         // Copy the content to output and reset buffer with (byte)0x00.
189         for (int i = 0; i < this.buffer.length; i++) {
190             output[outputOffset+i] = this.buffer[i];
191             this.buffer[i]   = (byte) 0x00;
192         }
193         
194         // Reset the bufferCounter.
195         this.bufferCounter = 0;
196 
197          //Returns the buffer content.
198          return this.buffer.length;
199     }    
200     
201     /** 
202      * Returns true if the internal buffer is full.
203      * 
204      * @return true if the buffer is full, false otherwise.
205      */    
206     public boolean isFull() {
207         return this.bufferCounter == this.buffer.length;
208     }
209     
210     /** 
211      * Write the number of free bytes in the last byte,
212      * and set the bufferCounter to end of buffer.
213      * @throws IllegalStateException if the buffer is full.
214      */    
215     public void doISO10126OctetPadding() throws IllegalStateException {    
216 
217         //If the buffer is full, we can pad the buffer, becaus
218         //we would lose the last byte in the buffer.
219         if (isFull()){
220             throw new IllegalStateException("The buffer is full, you can not " 
221                     + "pad a full buffer, fetch the data with fetch(), " 
222                     + "and invoke reset().");
223         }
224         
225         //Write the number of free bytes in the last byte.
226         this.buffer[this.buffer.length-1] = 
227                 (byte) ((this.buffer.length-this.bufferCounter) & 0x000000ff);  
228  
229         //set the bufferCounter to end of buffer.
230         this.bufferCounter = this.buffer.length;
231     }
232     
233     /**
234      * Returns the length of the buffer in bytes.
235      *
236      * @return the length of the buffer in bytes.
237      */
238     public int getLength() {
239         return this.buffer.length;
240     }    
241     
242     /** 
243      * Returns the number of bytes that the buffer contains.
244      * @return the number of bytes that the buffer contains.
245      */    
246     public int hasBytes() {
247         return this.bufferCounter;
248     }
249 }
250