|
ISO9796Part1WithRSASignatureImpl |
|
1 /* $RCSfile: ISO9796Part1WithRSASignatureImpl.java,v $
2 * $Revision: 1.3 $
3 * $Date: 2002/11/23 11:09:56 $
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.security.AlgorithmParameters;
35 import java.security.InvalidAlgorithmParameterException;
36 import java.security.InvalidKeyException;
37 import java.security.PrivateKey;
38 import java.security.PublicKey;
39 import java.security.SecureRandom;
40 import java.security.SignatureException;
41 import java.security.interfaces.RSAKey;
42 import java.security.interfaces.RSAPrivateKey;
43 import java.security.interfaces.RSAPublicKey;
44 import java.security.spec.AlgorithmParameterSpec;
45
46 /**
47 * ISO9796Part1WithRSASignatureImpl Class.
48 *
49 * @author <a href=mailto:uwe@cscc.de>Uwe Günther</a>
50 *
51 * @version $Revision: 1.3 $
52 */
53 final class ISO9796Part1WithRSASignatureImpl implements Cloneable {
54
55 /** The ISO9796Part1WithRSASignatureByteBuffer message buffer object. */
56 private ISO9796Part1WithRSASignatureByteBuffer mb =
57 new ISO9796Part1WithRSASignatureByteBuffer();
58
59 /** The RIPEMD160 ISO9796-1:1991 codec object. */
60 private ISO9796Part1RSACodec codec = new ISO9796Part1RSACodec();
61
62 /**
63 * The length of the signature in bits according to the modulus of the
64 * RSA key.
65 */
66 private int ks;
67
68 /** The object state variable. */
69 private State state = State.UNINITIALIZED;
70
71
72 /** Creates new ISO9796Part1WithRSASignatureImpl. */
73 public ISO9796Part1WithRSASignatureImpl() {
74 }
75
76 /**
77 * Creates and returns a copy of this object.
78 *
79 * @return a clone of this instance.
80 * @throws CloneNotSupportedException if the object's class does not
81 * support the <code>Cloneable</code> interface. Subclasses
82 * that override the <code>clone</code> method can also
83 * throw this exception to indicate that an instance cannot
84 * be cloned.
85 */
86 public Object clone() throws CloneNotSupportedException {
87 ISO9796Part1WithRSASignatureImpl result =
88 (ISO9796Part1WithRSASignatureImpl) super.clone();
89 result.mb = (ISO9796Part1WithRSASignatureByteBuffer) this.mb.clone();
90 result.codec = (ISO9796Part1RSACodec) this.codec.clone();
91 return result;
92 }
93
94 /**
95 * Indicates whether some other object is "equal to" this one.
96 *
97 * @param obj the reference object with which to compare.
98 * @return <code>true</code> if this object is the same as the obj
99 * argument; <code>false</code> otherwise.
100 * @see #hashCode()
101 * @see java.util.Hashtable
102 */
103 public boolean equals(Object obj) {
104 //Only for performance.
105 if (this == obj) {
106 return true;
107 }
108
109 //If obj == null then instanceof returns false, see JLS 15.20.2
110 if (!(obj instanceof ISO9796Part1WithRSASignatureImpl)) {
111 return false;
112 }
113
114 ISO9796Part1WithRSASignatureImpl other =
115 (ISO9796Part1WithRSASignatureImpl)obj;
116
117 return this.mb.equals(other.mb) &&
118 this.codec.equals(other.codec) &&
119 this.ks == other.ks &&
120 this.state == other.state;
121 }
122
123 /**
124 * Returns a hash code value for the object.
125 *
126 * @return a hash code value for this object.
127 * @see java.lang.Object#equals(java.lang.Object)
128 * @see java.util.Hashtable
129 */
130 public int hashCode() {
131 int result = 17;
132 result = 37*result + this.mb.hashCode();
133 result = 37*result + this.codec.hashCode();
134 result = 37*result + this.ks;
135 result = 37*result + this.state.hashCode();
136 return result;
137 }
138
139 /**
140 * Returns a string representation of the object.
141 *
142 * @return a string representation of the object.
143 */
144 public String toString() {
145 return "[ISO9796-1WithRSASignatureImpl - state: " + this.state + "]";
146 }
147
148 /**
149 * Initializes this signature object with the specified
150 * private key for signing operations.
151 *
152 * @param privateKey the private key of the identity whose signature
153 * will be generated.
154 *
155 * @throws InvalidKeyException if the key is improperly encoded, parameters
156 * are missing, and so on.
157 */
158 void initSign(PrivateKey privateKey) throws InvalidKeyException {
159 if (privateKey == null) {
160 throw new NullPointerException("Parameter privateKey is null.");
161 }
162 if (privateKey instanceof RSAPrivateKey) {
163 this.ks = ((RSAKey) privateKey).getModulus().bitLength() - 1;
164 } else {
165 throw new InvalidKeyException("Inappropriate Key.");
166 }
167 this.codec.initEncode(privateKey);
168 this.state = State.SIGN;
169 this.mb.reset();
170 }
171
172 /**
173 * Initializes this signature object with the specified
174 * private key and source of randomness for signing operations.
175 *
176 * <p>This concrete method has been added to this previously-defined
177 * abstract class. (For backwards compatibility, it cannot be abstract.)
178 *
179 * @param privateKey the private key of the identity whose signature
180 * will be generated.
181 * @param random the source of randomness
182 *
183 * @throws InvalidKeyException if the key is improperly encoded, parameters
184 * are missing, and so on.
185 */
186 void initSign(PrivateKey privateKey, SecureRandom random)
187 throws InvalidKeyException {
188 initSign(privateKey);
189 }
190
191 /**
192 * Initializes this signature object with the specified
193 * public key for verification operations.
194 *
195 * @param publicKey the public key of the identity whose signature is
196 * going to be verified.
197 *
198 * @throws InvalidKeyException if the key is improperly
199 * encoded, parameters are missing, and so on.
200 */
201 void initVerify(PublicKey publicKey) throws InvalidKeyException {
202 if (publicKey == null) {
203 throw new NullPointerException("Parameter publicKey is null.");
204 }
205 if (publicKey instanceof RSAPublicKey) {
206 this.ks = ((RSAKey) publicKey).getModulus().bitLength() - 1;
207 } else {
208 throw new InvalidKeyException("Inappropriate Key.");
209 }
210 this.codec.initDecode(publicKey);
211 this.state = State.VERIFY;
212 this.mb.reset();
213 }
214
215 /**
216 * Updates the data to be signed or verified
217 * using the specified byte.
218 *
219 * @param value the byte to use for the update.
220 *
221 * @throws SignatureException if the engine is not initialized
222 * properly.
223 */
224 void update(byte value) throws SignatureException {
225 if (this.state == State.UNINITIALIZED) {
226 throw new SignatureException("Signature is not initialized.");
227 }
228 this.mb.add(value);
229 }
230
231 /**
232 * Updates the data to be signed or verified, using the
233 * specified array of bytes, starting at the specified offset.
234 *
235 * @param values the array of bytes
236 * @param offset the offset to start from in the array of bytes
237 * @param len the number of bytes to use, starting at offset
238 *
239 * @throws SignatureException if the engine is not initialized
240 * properly
241 * @throws NullPointerException if outbuf is null.
242 * @throws IllegalArgumentException if offset or len is negative, or the
243 * sum of offset and len is greater than length of the values array.
244 */
245 void update(byte[] values, int offset, int len) throws SignatureException {
246 if (this.state == State.UNINITIALIZED) {
247 throw new SignatureException("Signature is not initialized.");
248 }
249 if (values == null) {
250 throw new NullPointerException("Parameter values is null.");
251 }
252 if (offset < 0) {
253 throw new IllegalArgumentException("Parameter offset is less " +
254 "than zero.");
255 }
256 if (len < 0) {
257 throw new IllegalArgumentException("Parameter len is less " +
258 "than zero.");
259 }
260 if (offset + len > values.length) {
261 throw new IllegalArgumentException("Parameter offset + len is " +
262 "greater than outbuf.length .");
263 }
264 this.mb.add(values, offset, len);
265 }
266
267 /**
268 * Returns the signature bytes of all the data
269 * updated so far.
270 * The format of the signature depends on the underlying
271 * signature scheme.
272 *
273 * @return the signature bytes of the signing operation's result.
274 *
275 * @throws SignatureException if the engine is not initialized properly.
276 */
277 byte[] sign() throws SignatureException {
278 if (this.state != State.SIGN) {
279 throw new SignatureException("Signature is not in SIGN state.");
280 }
281 if (this.mb.isEmpty()) {
282 throw new SignatureException("You have to add at least one byte " +
283 "to sign a message.");
284 }
285
286 try {
287
288 ISO9796Part1BitString signature =
289 this.codec.encodeMessage(this.mb.fetch(), false);
290
291 return signature.getBitString();
292
293 } finally {
294 //If something goes wrong we should reset the mb without fail!
295 //Also, if nothing goes wrong we should reset the mb too.
296 this.mb.reset();
297 }
298 }
299
300 /**
301 * Finishes this signature operation and stores the resulting signature
302 * bytes in the provided buffer <code>outbuf</code>, starting at
303 * <code>offset</code>.
304 * The format of the signature depends on the underlying
305 * signature scheme.
306 *
307 * <p>The signature implementation is reset to its initial state
308 * (the state it was in after a call to one of the
309 * <code>engineInitSign</code> methods)
310 * and can be reused to generate further signatures with the same private
311 * key.
312 *
313 * This method should be abstract, but we leave it concrete for
314 * binary compatibility. Knowledgeable providers should override this
315 * method.
316 *
317 * @param outbuf buffer for the signature result.
318 *
319 * @param offset offset into <code>outbuf</code> where the signature is
320 * stored.
321 *
322 * @param len number of bytes within <code>outbuf</code> allotted for the
323 * signature.
324 * Both this default implementation and the SUN provider do not
325 * return partial digests. If the value of this parameter is less
326 * than the actual signature length, this method will throw a
327 * SignatureException.
328 * This parameter is ignored if its value is greater than or equal to
329 * the actual signature length.
330 *
331 * @return the number of bytes placed into <code>outbuf</code>
332 *
333 * @throws SignatureException if an error occurs or <code>len</code>
334 * is less than the actual signature length.
335 * @throws NullPointerException if outbuf is null.
336 * @throws IllegalArgumentException if offset or len is negative, or the
337 * sum of offset and len is greater than length of the outbuf array.
338 */
339 int sign(byte[] outbuf, int offset, int len) throws SignatureException {
340 if (this.state != State.SIGN) {
341 throw new SignatureException("Signature is not in SIGN state.");
342 }
343 if (outbuf == null) {
344 throw new NullPointerException("Parameter outbuf is null.");
345 }
346 if (offset < 0) {
347 throw new IllegalArgumentException("Parameter offset is less " +
348 "than zero.");
349 }
350 if (len < 0) {
351 throw new IllegalArgumentException("Parameter len is less " +
352 "than zero.");
353 }
354 if (offset + len > outbuf.length) {
355 throw new IllegalArgumentException("Parameter offset + len is " +
356 "greater than outbuf.length .");
357 }
358 if (((ks + 7) / 8) > len) {
359 throw new SignatureException("Existing space in outbuf is less "
360 + "than the signature length would be.");
361 }
362
363 //Calculate the Signature with sign()
364 byte[] result = sign();
365
366 //Copy the Signature into the outbuf starting at offset.
367 System.arraycopy(result, 0, outbuf, offset, result.length);
368
369 //Return the number of bytes placed into outbuf.
370 return result.length;
371 }
372
373 /**
374 * Verifies the passed-in signature.
375 *
376 * @param sigBytes the signature bytes to be verified.
377 *
378 * @return true if the signature was verified, false if not.
379 *
380 * @throws SignatureException if the engine is not initialized
381 * properly, or the passed-in signature is improperly encoded or
382 * of the wrong type, etc.
383 */
384 boolean verify(byte[] sigBytes) throws SignatureException {
385 if (this.state != State.VERIFY) {
386 throw new SignatureException("Signature is not in VERIFY state.");
387 }
388 if (sigBytes == null) {
389 throw new NullPointerException("Parameter signBytes is null.");
390 }
391 if (this.mb.isEmpty()) {
392 throw new SignatureException("You have to add at least one byte " +
393 "to verify a message.");
394 }
395
396 try {
397 ISO9796Part1BitString sigma =
398 new ISO9796Part1BitString (sigBytes, this.ks);
399
400 ISO9796Part1BitString recoveredMessageDigest =
401 this.codec.decodeSignature(sigma);
402
403 if (recoveredMessageDigest == null) {
404 return false;
405
406 } else { //(message != null)
407 if (recoveredMessageDigest.equals(this.mb.fetch())) {
408 return true;
409 } else {
410 return false;
411 }
412 }
413 } finally {
414 //If something goes wrong we should reset the mb without fail!
415 //Also, if nothing goes wrong we should reset the mb too.
416 this.mb.reset();
417 }
418 }
419
420 /**
421 * Verifies the passed-in signature in the specified array
422 * of bytes, starting at the specified offset.
423 *
424 * <p> Note: Subclasses should overwrite the default implementation.
425 *
426 *
427 * @param sigBytes the signature bytes to be verified.
428 * @param offset the offset to start from in the array of bytes.
429 * @param leng the number of bytes to use, starting at offset.
430 *
431 * @return true if the signature was verified, false if not.
432 *
433 * @throws SignatureException if the engine is not initialized
434 * properly, or the passed-in signature is improperly encoded or
435 * of the wrong type, etc.
436 */
437 boolean verify(byte[] sigBytes, int offset, int len)
438 throws SignatureException {
439 if (this.state != State.VERIFY) {
440 throw new SignatureException("Signature is not in VERIFY state.");
441 }
442 if (sigBytes == null) {
443 throw new NullPointerException("Parameter signBytes is null.");
444 }
445 if (offset < 0) {
446 throw new IllegalArgumentException("Parameter offset is less " +
447 "than zero.");
448 }
449 if (len < 0) {
450 throw new IllegalArgumentException("Parameter len is less " +
451 "than zero.");
452 }
453 if (offset + len > sigBytes.length) {
454 throw new IllegalArgumentException("Parameter offset + len is " +
455 "greater than outbuf.length .");
456 }
457 if (((ks + 7) / 8) != len) {
458 throw new SignatureException("Signature in sigBytes is not " +
459 ((ks + 7) / 8) + "bytes long.");
460 }
461
462 //Create a temporaly byte array that holds the 'sigBytes'.
463 byte[] tempSigBytes = new byte[len];
464
465 //Copy the 'sigBytes' to 'tempSigBytes'.
466 System.arraycopy(sigBytes, offset, tempSigBytes, 0, len);
467
468 //Invoke the verify(byte[]) method with the 'tempSigBytesArray'.
469 return verify(tempSigBytes);
470 }
471
472 /**
473 * <p>This method is overridden by providers to initialize
474 * this signature engine with the specified parameter set.
475 *
476 * @param params the parameters
477 *
478 * @exception UnsupportedOperationException if this method is not
479 * overridden by a provider
480 *
481 * @throws InvalidAlgorithmParameterException if this method is
482 * overridden by a provider and the the given parameters
483 * are inappropriate for this signature engine
484 */
485 void setParameter(AlgorithmParameterSpec params)
486 throws InvalidAlgorithmParameterException {
487 throw new UnsupportedOperationException("AlgorithmParameters are not " +
488 "supported for this signature.");
489 }
490
491 /**
492 * <p>This method is overridden by providers to return the
493 * parameters used with this signature engine, or null
494 * if this signature engine does not use any parameters.
495 *
496 * <p>The returned parameters may be the same that were used to initialize
497 * this signature engine, or may contain a combination of default and
498 * randomly generated parameter values used by the underlying signature
499 * implementation if this signature engine requires algorithm parameters
500 * but was not initialized with any.
501 *
502 * @return the parameters used with this signature engine, or null if this
503 * signature engine does not use any parameters
504 *
505 * @throws UnsupportedOperationException if this method is
506 * not overridden by a provider
507 */
508 AlgorithmParameters getParameters() {
509 throw new UnsupportedOperationException("AlgorithmParameters are not " +
510 "supported for this signature.");
511 }
512
513 /** Type safe enum for the enclosing class object state. */
514 private final static class State {
515 /** Name odf the state. */
516 private final String name;
517
518 /** Constructor need only to called within this class. */
519 private State(String name) {
520 this.name = name;
521 }
522
523 /**
524 * Returns a string representation of the object.
525 *
526 * @return a string representation of the object.
527 */
528 public String toString() {
529 return this.name;
530 }
531
532 /** State constante if the enclosing class isn't initialized. */
533 private static final State UNINITIALIZED =
534 new State("Uninitialized");
535
536 /** State constante if the enclossing class is in Sign mode. */
537 private static final State SIGN = new State("Sign");
538
539 /** State constante if the enclossing class is in Verify mode. */
540 private static final State VERIFY = new State("Verify");
541 }
542
543 }
544
|
ISO9796Part1WithRSASignatureImpl |
|