1   /* $RCSfile: RSAPublicKeyImpl.java,v $
2    * $Revision: 1.9 $
3    * $Date: 2002/11/23 11:09:57 $
4    * $Author: uwe_guenther $
5    * $State: Exp $
6    *
7    * Created on November 6, 2001 10:12 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.io.IOException;
35  import java.io.ObjectInputStream;
36  import java.io.ObjectOutputStream;
37  import java.math.BigInteger;
38  import java.security.interfaces.RSAPrivateCrtKey;
39  import java.security.interfaces.RSAPublicKey;
40  import java.security.spec.KeySpec;
41  import java.security.spec.RSAPublicKeySpec;
42  
43  /** 
44   * RSAPublicKeyImpl Class.
45   *
46   * @author  <a href=mailto:uwe@cscc.de >Uwe G&uuml;nther </a>
47   *
48   * @version $Revision: 1.9 $
49   */
50  final class RSAPublicKeyImpl implements RSAPublicKey {
51  
52      /**
53       * The class fingerprint that is set to indicate 
54       * serialization compatibility with a previous and
55       * future versions of the class.
56       */
57      private static final long serialVersionUID = 3031586598161058255L;
58      
59      /**
60       * RSA modulus. Must be non-null.
61       *
62       * @serial
63       */
64      private transient BigInteger modulus;
65  
66      /**
67       * RSA public exponent. Must be non-null.
68       *
69       * @serial
70       */
71      private transient BigInteger publicExponent;
72  
73      /**
74       * This package private constructor will be used from the 
75       * RSAKeyPairGeneratorEngine. 
76       *
77       * <p>Creates new RSAPublicKeyImpl  from two <code>BigInteger</code>
78       * values. There are no checks for specific invariants. A valid 
79       * <code>BigInteger</code value is also a valid parameter.
80       *
81       * @param modulus The modulus of this public RSA key.
82       * @param publicExponent The public exponent of this public RSA key.
83       * @throws NullPointerException If either <code>modulus</code> or 
84       * <code>publicExponent</code> is <code>null</code>.
85       * @see java.math.BigInteger
86       * @see de.cscc.crypto.provider.RSAKeyPairGeneratorEngine
87       */
88      RSAPublicKeyImpl(BigInteger modulus, BigInteger publicExponent) {
89          //May throws NullPointerException if one of the key data is null.
90          initialize(modulus, publicExponent);
91      }
92  
93      /** 
94       * This package private constructor will be used from the 
95       * RSAKeyFactoryEngine.
96       *
97       * <p>Creates new RSAPublicKeyImpl from an instance of a class that 
98       * implements the RSAPublicKey interface. May be this will be a class
99       * from a foreign provider, so we do all checks, which we have to do with
100      * pur BigIntegers.
101      *
102      * @param key existing key may from a foreign provider.
103      * @throws NullPointerException If <code>key</code> is <code>null</null> or
104      * one of keys 'key data' is <code>null</code>.
105      * @see de.cscc.crypto.provider.RSAKeyFactoryEngine
106      */    
107     RSAPublicKeyImpl(RSAPublicKey key) {
108         //Check params for null.
109         if (key == null) {
110             throw new NullPointerException("Parameter key is null.");
111         }
112         //May throws NullPointerException if one of the key data of a foreign
113         //provider key are null.
114         initialize(key.getModulus(), key.getPublicExponent());
115     }    
116     
117     /** 
118      * This package private constructor will be used from the 
119      * RSAKeyFactoryEngine.
120      *
121      * <p>Creates new RSAPublicKeyImpl from an instance of a class that 
122      * implements the RSAPrivateCrtKey interface. May be this will be a class
123      * from a foreign provider, so we do all checks, which we have to do with
124      * pur BigIntegers.
125      *
126      * @param key existing key may from a foreign provider.
127      * @throws NullPointerException If <code>key</code> is <code>null</null> or
128      * one of keys 'key data' is <code>null</code>.
129      * @see de.cscc.crypto.provider.RSAKeyFactoryEngine
130      */    
131     RSAPublicKeyImpl(RSAPrivateCrtKey key) {
132         //Check params for null.
133         if (key == null) {
134             throw new NullPointerException("Parameter key is null.");
135         }
136         //May throws NullPointerException if one of the key data of a foreign
137         //provider key are null.
138         initialize(key.getModulus(), key.getPublicExponent());
139     }        
140     
141     /** 
142      * This package private constructor will be used from the 
143      * RSAKeyFactoryEngine.
144      *
145      * <p>Creates new RSAPublicKeyImpl from an instance of a RSAPublicKeySpec 
146      * class. May be this class contains null references instead BigInterger,
147      * so we do all checks, which we have to do with pur BigIntegers.
148      *
149      * @param keySpec transparent specification that holds the key material.
150      * @throws NullPointerException If <code>keySpec</code> is <code>null</null>
151      * or one of the key specifakations 'key data' is <code>null</code>.
152      * @see de.cscc.crypto.provider.RSAKeyFactoryEngine
153      */    
154     RSAPublicKeyImpl(RSAPublicKeySpec keySpec) {
155         //Check params for null.
156         if (keySpec == null) {
157             throw new NullPointerException("Parameter keySpec is null.");
158         }
159         //May throws NullPointerException if one of the key data are null.
160         initialize(keySpec.getModulus(), keySpec.getPublicExponent());
161     }        
162     
163     /** 
164      * Private helper method, only used from the constructors and 
165      * pseudo-constructors like readObject.
166      *
167      * Initializes a new RSAPublicKeyImpl  from two <code>BigInteger</code>
168      * values. There are no checks for specific invariants. A valid 
169      * <code>BigInteger</code value is also a valid parameter.
170      *
171      * @param modulus The modulus of this public RSA key.
172      * @param publicExponent The public exponent of this public RSA key.
173      * @throws NullPointerException If either <code>modulus</code> or 
174      * <code>publicExponent</code> is <code>null</code>.
175      * @throws IllegalArgumentException if any Parameter is negative.
176      * @see java.math.BigInteger
177      */
178     private void initialize(BigInteger modulus, BigInteger publicExponent) {
179         //Check params for null.
180         if (modulus == null) {
181             throw new NullPointerException("Parameter modulus is null.");
182         }
183         if (publicExponent == null) {
184             throw new NullPointerException(
185                     "Parameter publicExponent is null.");
186         }
187  
188         //Check params if the they real BigInteger, and not subclasses.
189         //If a param is a subclasses we construct a new real BigInteger from
190         //the specific param value.
191         if (modulus.getClass() != BigInteger.class) {
192             modulus = new BigInteger(modulus.toByteArray());
193         }
194         if (publicExponent.getClass() !=BigInteger.class) {
195             publicExponent = new BigInteger(publicExponent.toByteArray());
196         }
197         
198         //Check if the params not negative
199         if (modulus.compareTo(BigInteger.ZERO) < 0) {
200             throw new IllegalArgumentException(
201             "Parameter modulus is negative. modulus: " + modulus);
202         }
203         if (publicExponent.compareTo(BigInteger.ZERO) < 0) {
204             throw new IllegalArgumentException(
205             "Parameter publicExponent is negative. publicExponent: " +
206             publicExponent);
207         }        
208  
209         //We do only copy the references to the BigInteger objects,
210         //because BigInteger are immutable and this class too.
211         this.modulus = modulus;
212         this.publicExponent = publicExponent;
213     }    
214     
215     /**
216      * Indicates whether some other object is "equal to" this one.
217      *
218      * @param   obj   the reference object with which to compare.
219      * @return  <code>true</code> if this object is the same as the obj
220      *         argument; <code>false</code> otherwise.
221      * @see     #hashCode()
222      * @see     java.util.Hashtable
223      */
224     public boolean equals(Object obj) {
225         //Only for performance.
226         if (this == obj) {
227             return true;
228         } 
229         
230         //If obj == null then instanceof returns false, see JLS 15.20.2
231         if (!(obj instanceof RSAPublicKeyImpl)) {
232             return false;
233         }
234         
235         RSAPublicKeyImpl other = (RSAPublicKeyImpl) obj;
236         return this.modulus.equals(other.modulus) &&
237                this.publicExponent.equals(other.publicExponent);
238     }
239     
240     /**
241      * Returns a hash code value for the object. 
242      *
243      * @return  a hash code value for this object.
244      * @see     java.lang.Object#equals(java.lang.Object)
245      * @see     java.util.Hashtable
246      */
247     public int hashCode() {
248         int result = 17;
249         result = 37*result + this.modulus.hashCode(); 
250         result = 37*result + this.publicExponent.hashCode();         
251         return result;
252     }
253     
254     /**
255      * Returns a string representation of the object.
256      *
257      * @return  a string representation of the object.
258      */
259     public String toString() {
260         StringBuffer sb = new StringBuffer();
261         sb.append("[Modulus-Bit-Length: ");
262         sb.append(this.modulus.bitLength());
263         sb.append(", Modulus: ");
264         sb.append(this.modulus);
265         sb.append(", Public-Exponent: ");
266         sb.append(this.publicExponent);
267         sb.append(']');
268         return sb.toString();
269     }
270     
271     /**
272      * Writes this public key as two <code>BigInteger</code> objects to the
273      * stream for serialization. First the <code>modulus</code>, then the 
274      * <code>publicExponent</code>. 
275      *
276      * @param s the ObjectOutputStream.
277      * @throws IOException if there is something wrong with the
278      * ObjectOutputStream.
279      * @serialData First the <code>modulus</code> will be written as 
280      * <code>BigInteger</code> object, then the <code>publicExponent</code> will
281      * be written as <code>BigInteger</code> too. 
282      * @see java.io.ObjectOutputStream
283      */    
284     private void writeObject(ObjectOutputStream s) throws IOException {
285         s.defaultWriteObject();
286         s.writeObject(this.modulus);
287         s.writeObject(this.publicExponent);
288     }     
289     
290     /**
291      * Reads this public key as two <code>BigInteger</code> objects from the
292      * stream for deserialization. First the <code>modulus</code>, then the 
293      * <code>publicExponent</code>. 
294      *
295      * Keep in mind this is a PSEUDOCONSTRUCTOR and you have to set
296      * do devensive copying, or use the new readUnshared and secondly
297      * you have to check all invariants, or your objects are immutable.
298      *
299      * @see java.io.ObjectInputStream
300      * @param s the ObjectInputStream.
301      * @throws IOException if there is something wrong with the
302      * ObjectInputStream.
303      * @throws ClassNotFoundException if the class can not be found.
304      * @throws InvalidObjectException if the streamm is tampered.
305      */    
306     private void readObject(ObjectInputStream s) 
307             throws IOException, ClassNotFoundException {
308         s.defaultReadObject();
309         BigInteger modulus = (BigInteger) s.readObject();
310         BigInteger publicExponent = (BigInteger) s.readObject();
311         //May throws NullPointerException if one of the key data is null.
312         initialize(modulus, publicExponent);
313     }     
314     
315     
316     /**
317      * Returns the standard algorithm name for this key.
318      *
319      * @return the name of the algorithm associated with this key.
320      */
321     public String getAlgorithm() {
322         return "RSA";
323     }
324     
325     /**
326      * Returns the name of the primary encoding format of this key,
327      * or null if this key does not support encoding. 
328      *
329      * <p>We don't support encoding for this key, so this methods
330      * returns <code>null</code>.
331      *
332      * @return the primary encoding format of the key.
333      */
334     public String getFormat() {
335         return null;
336     }
337     
338     /**
339      * Returns the key in its primary encoding format, or null
340      * if this key does not support encoding.
341      *
342      * <p>We don't support encoding for this key, so this methods
343      * returns <code>null</code>.
344      *
345      * @return the encoded key, or null if the key does not support
346      * encoding.
347      */
348     public byte[] getEncoded() {
349         return null;
350     }
351     
352     /**
353      * Returns the modulus.
354      *
355      * @return the modulus
356      */
357     public BigInteger getModulus() {
358         return this.modulus;
359     }
360     
361     /**
362      * Returns the public exponent.
363      *
364      * @return the public exponent
365      */
366     public BigInteger getPublicExponent() {
367         return this.publicExponent;
368     }
369     
370     /**
371      * This package private method will be used from the RSAKeyFactoryEngine.
372      *
373      * Return the matching key spec of this key.
374      *
375      * @return the matching key spec to this key.
376      * @see de.cscc.crypto.provider.RSAKeyFactoryEngine
377      */
378     KeySpec getKeySpec() {
379         return new RSAPublicKeySpec(this.modulus, this.publicExponent);
380     }
381         
382 }
383