|
RSACipherImpl |
|
1 /* $RCSfile: RSACipherImpl.java,v $
2 * $Revision: 1.5 $
3 * $Date: 2002/11/23 11:09:57 $
4 * $Author: uwe_guenther $
5 * $State: Exp $
6 *
7 * Created on December 1, 2001 1:36 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.math.BigInteger;
35 import java.security.AlgorithmParameters;
36 import java.security.InvalidAlgorithmParameterException;
37 import java.security.InvalidKeyException;
38 import java.security.Key;
39 import java.security.NoSuchAlgorithmException;
40 import java.security.SecureRandom;
41 import java.security.interfaces.RSAKey;
42 import java.security.interfaces.RSAPrivateCrtKey;
43 import java.security.interfaces.RSAPrivateKey;
44 import java.security.interfaces.RSAPublicKey;
45 import java.security.spec.AlgorithmParameterSpec;
46
47 import javax.crypto.BadPaddingException;
48 import javax.crypto.Cipher;
49 import javax.crypto.IllegalBlockSizeException;
50 import javax.crypto.NoSuchPaddingException;
51 import javax.crypto.ShortBufferException;
52
53 import de.cscc.crypto.util.BigIntegerUtil;
54
55 /**
56 * RSACipherImpl Class.
57 *
58 * @author <a href=mailto:uwe@cscc.de>Uwe Günther</a>
59 * @version $Revision: 1.5 $
60 */
61 final class RSACipherImpl {
62
63 private SecureRandom random = new SecureRandom();
64
65 private boolean initialized = false;
66
67 private int opmode;
68
69 /** RSAKey for the Cipher Object */
70 private RSAKey key;
71
72 //not yet implemented (needed for update and doFinal)
73 private byte[] inputBuffer;
74 private int inputBufferCounter;
75
76 RSACipherImpl() {}
77
78 /**
79 * Returns a string representation of the object.
80 *
81 * @return a string representation of the object.
82 */
83 public String toString() {
84 return "[RSA-Cipher]";
85 }
86
87 /**
88 * Sets the mode of this cipher.
89 * @param mode the cipher mode.
90 * @throws NoSuchAlgorithmException if the requested cipher mode does not exist.
91 */
92 void setMode(String mode) throws NoSuchAlgorithmException {
93 throw new NoSuchAlgorithmException("No Feedback mode supported.");
94 }
95
96 /**
97 * Sets the padding mechanism of this cipher.
98 *
99 * @param padding the padding mechanism.
100 * @throws NoSuchPaddingException if the requested padding mechanism does not exist.
101 */
102 void setPadding(String padding)
103 throws NoSuchPaddingException {
104 throw new NoSuchPaddingException("No Padding Supported.");
105 }
106
107 /**
108 * Initializes this cipher with a key and a source of randomness.
109 *
110 * @param opmode the operation mode of this cipher.
111 * This is one of the following:
112 * javax.crypto.Cipher.ENCRYPT_MODE
113 * javax.crypto.Cipher.DECRYPT_MODE
114 * javax.crypto.Cipher.WRAP_MODE
115 * javax.crypto.Cipher.UNWRAP_MODE
116 * @param key the key to encrypt or to decrypt.
117 * @param random the source of randomness.
118 * @throws InvalidKeyException if the given key is inappropriate for
119 * initializing this cipher, this means if the key does not match to
120 * the specific opmode.
121 * @throws NullPointerException if key is null.
122 */
123 void init(int opmode, Key key, SecureRandom random)
124 throws InvalidKeyException {
125 if (key == null) {
126 throw new NullPointerException("Prameter key is null.");
127 }
128
129 //We use only keys of the JHBCI Provider, so if you want to
130 //use other keys,you have to convert them with the RSAKeyFactory.
131 //We do this, because other RSAKeys may be insecure.
132 if (opmode == Cipher.ENCRYPT_MODE) {
133 this.opmode = Cipher.ENCRYPT_MODE;
134 if (key instanceof RSAPublicKeyImpl) {
135 this.key = (RSAKey) key;
136 } else {
137 throw new InvalidKeyException(
138 "Key does not match to opmode constant.");
139 }
140 } else if (opmode == Cipher.WRAP_MODE) {
141 this.opmode = Cipher.WRAP_MODE;
142 if (key instanceof RSAPublicKeyImpl) {
143 this.key = (RSAKey) key;
144 } else {
145 throw new InvalidKeyException(
146 "Key does not match to opmode constant.");
147 }
148 } else if (opmode == Cipher.DECRYPT_MODE) {
149 this.opmode = Cipher.DECRYPT_MODE;
150 if (key instanceof RSAPrivateCrtKeyImpl) {
151 this.key = (RSAKey) key;
152 } else if (key instanceof RSAPrivateKeyImpl) {
153 this.key = (RSAKey) key;
154 } else {
155 throw new InvalidKeyException(
156 "Key does not match to opmode constant.");
157 }
158 } else if (opmode == Cipher.UNWRAP_MODE) {
159 this.opmode = Cipher.UNWRAP_MODE;
160 if (key instanceof RSAPrivateCrtKeyImpl) {
161 this.key = (RSAKey) key;
162 } else if (key instanceof RSAPrivateKeyImpl) {
163 this.key = (RSAKey) key;
164 } else {
165 throw new InvalidKeyException(
166 "Key does not match to opmode constant.");
167 }
168 } else {
169 throw new IllegalArgumentException("Illegal opmode constant.");
170 }
171 if (random != null) {
172 this.random = random;
173 }
174 this.initialized = true; //set to true before call engineGetBlockSize
175
176 this.inputBuffer = new byte [getBlockSize()];
177 this.inputBufferCounter = 0;
178 }
179
180 /**
181 * Initializes this cipher with a key, a set of algorithm parameters,
182 * and a source of randomness.
183 *
184 * @param opmode the operation mode of this cipher.
185 * This is one of the following:
186 * javax.crypto.Cipher.ENCRYPT_MODE
187 * javax.crypto.Cipher.DECRYPT_MODE
188 * javax.crypto.Cipher.WRAP_MODE
189 * javax.crypto.Cipher.UNWRAP_MODE
190 * @param key the key to encrypt or to decrypt.
191 * @param params the algorithm paramter.
192 * @param random the source of randomness.
193 * @throws InvalidKeyException if the given key is inappropriate for
194 * initializing this cipher.
195 * @throws InvalidAlgorithmParameterException if params isn't null, because
196 * we don't support AlgorithmParameters.
197 */
198 void init(int opmode, Key key, AlgorithmParameters params,
199 SecureRandom random)
200 throws InvalidKeyException, InvalidAlgorithmParameterException {
201 if (params != null) {
202 throw new InvalidAlgorithmParameterException("Parameter params " +
203 "isn't null. We currently don't support AlgortihmParameters.");
204 }
205 init(opmode, key, random);
206 }
207
208 /**
209 * Initializes this cipher with a key, a set of algorithm parameters,
210 * and a source of randomness.
211 *
212 * @param opmode the operation mode of this cipher.
213 * This is one of the following:
214 * javax.crypto.Cipher.ENCRYPT_MODE
215 * javax.crypto.Cipher.DECRYPT_MODE
216 * javax.crypto.Cipher.WRAP_MODE
217 * javax.crypto.Cipher.UNWRAP_MODE
218 * @param key the key to encrypt or to decrypt.
219 * @param params the algorithm paramter.
220 * @param random the source of randomness.
221 * @throws InvalidKeyException if the given key is inappropriate for
222 * initializing this cipher.
223 * @throws InvalidAlgorithmParameterException if params isn't null, because
224 * we don't support AlgorithmParameterSpecs.
225 */
226 void init(int opmode, Key key, AlgorithmParameterSpec params,
227 SecureRandom random)
228 throws InvalidKeyException, InvalidAlgorithmParameterException {
229 if (params != null) {
230 throw new InvalidAlgorithmParameterException("Parameter params " +
231 "isn't null. We currently don't support AlgortihmParameterSpecs.");
232 }
233 init(opmode, key, random);
234 }
235
236 /**
237 * Continues a multiple-part encryption or decryption operation
238 * (depending on how this cipher was initialized), processing another data
239 * part.
240 *
241 * @param input the input buffer.
242 * @param inputOffset the offset in input where the input starts.
243 * @param inputLen the input length.
244 * @throws IllegalStateException if the Cipher was not initialized, or you
245 * invoke this method in WRAP_MODE or UNWRAP_MODE.
246 * @return the new buffer with the result, or null if the
247 * underlying cipher is a block cipher and the input
248 * data is too short to result in a new block.
249 */
250 byte[] update(byte[] input, int inputOffset, int inputLen) {
251 if (this.initialized == false) {
252 throw new IllegalStateException("Cipher not initialized");
253 }
254 if (this.opmode == Cipher.ENCRYPT_MODE) {
255 //Put here code for encryption and remove the exception.
256 throw new UnsupportedOperationException(
257 "We support only Key wrap and Key unwrap.");
258
259 } else if (this.opmode == Cipher.DECRYPT_MODE) {
260 //Put here code for decryption and remove the exception.
261 throw new UnsupportedOperationException(
262 "We support only Key wrap and Key unwrap.");
263
264 } else {
265 //Wrong opmode, we lose.
266 throw new IllegalStateException("Cipher has unappropriate " +
267 "opmode , to invoke this method.");
268 }
269 }
270
271 /**
272 * Continues a multiple-part encryption or decryption operation
273 * (depending on how this cipher was initialized), processing another data
274 * part.
275 *
276 * @param input the input buffer.
277 * @param inputOffset the offset in input where the input starts.
278 * @param inputLen the input length.
279 * @param output the buffer for the result.
280 * @param outputOffset the offset in output where the result is stored.
281 * @throws ShortBufferException if the given output buffer is too small to
282 * hold the result.
283 * @throws IllegalStateException if the Cipher was not initialized, or you
284 * invoke this method in WRAP_MODE or UNWRAP_MODE.
285 * @return the number of bytes stored in output
286 */
287 int update(byte[] input, int inputOffset, int inputLen,
288 byte[] output, int outputOffset)
289 throws ShortBufferException {
290 if (this.initialized == false) {
291 throw new IllegalStateException("Cipher not initialized");
292 }
293 if (this.opmode == Cipher.ENCRYPT_MODE) {
294 //Put here code for encryption and remove the exception.
295 throw new UnsupportedOperationException(
296 "We support only Key wrap and Key unwrap.");
297
298 } else if (this.opmode == Cipher.DECRYPT_MODE) {
299 //Put here code for decryption and remove the exception.
300 throw new UnsupportedOperationException(
301 "We support only Key wrap and Key unwrap.");
302
303 } else {
304 //Wrong opmode, we lose.
305 throw new IllegalStateException("Cipher has unappropriate " +
306 "opmode , to invoke this method.");
307 }
308 }
309
310
311 /**
312 * Encrypts or decrypts data in a single-part operation, or finishes a
313 * multiple-part operation.
314 *
315 * @param input the input buffer.
316 * @param inputOffset the offset in input where the input starts.
317 * @param inputLen the input length.
318 * @throws IllegalBlockSizeException if this cipher is a block cipher, no padding
319 * has been requested (only in encryption mode),
320 * and the total input length of the data processed
321 * by this cipher is not a multiple of block size.
322 * @throws BadPaddingException if this cipher is in decryption mode,
323 * and (un)padding has been requested,
324 * but the decrypted data is not bounded
325 * by the appropriate padding bytes.
326 * @throws IllegalStateException if the Cipher was not initialized, or you
327 * invoke this method in WRAP_MODE or UNWRAP_MODE.
328 * @return the new buffer with the finally result.
329 */
330 byte[] doFinal(byte[] input, int inputOffset, int inputLen)
331 throws IllegalBlockSizeException, BadPaddingException {
332 if (this.initialized == false) {
333 throw new IllegalStateException("Cipher not initialized");
334 }
335 if (this.opmode == Cipher.ENCRYPT_MODE) {
336 //Put here code for encryption and remove the exception.
337 throw new UnsupportedOperationException(
338 "We support only Key wrap and Key unwrap.");
339
340 } else if (this.opmode == Cipher.DECRYPT_MODE) {
341 //Put here code for decryption and remove the exception.
342 throw new UnsupportedOperationException(
343 "We support only Key wrap and Key unwrap.");
344
345 } else {
346 //Wrong opmode, we lose.
347 throw new IllegalStateException("Cipher has unappropriate " +
348 "opmode , to invoke this method.");
349 }
350 }
351
352
353 /**
354 * Encrypts or decrypts data in a single-part operation, or finishes a
355 * multiple-part operation.
356 *
357 * @param input the input buffer.
358 * @param inputOffset the offset in input where the input starts.
359 * @param inputLen the input length.
360 * @param output the buffer for the finally result.
361 * @param outputOffset the offset in output where the result is stored.
362 * @throws ShortBufferException if the given output buffer is too small to
363 * hold the result.
364 * @throws IllegalBlockSizeException if this cipher is a block cipher, no padding
365 * has been requested (only in encryption mode),
366 * and the total input length of the data processed
367 * by this cipher is not a multiple of block size.
368 * @throws BadPaddingException if this cipher is in decryption mode,
369 * and (un)padding has been requested,
370 * but the decrypted data is not bounded
371 * by the appropriate padding bytes.
372 * @throws IllegalStateException if the Cipher was not initialized, or you
373 * invoke this method in WRAP_MODE or UNWRAP_MODE.
374 * @return the number of bytes stored in output.
375 */
376 int doFinal(byte[] input, int inputOffset, int inputLen,
377 byte[] output, int outputOffset) throws ShortBufferException,
378 IllegalBlockSizeException, BadPaddingException {
379 if (this.initialized == false) {
380 throw new IllegalStateException("Cipher not initialized");
381 }
382 if (this.opmode == Cipher.ENCRYPT_MODE) {
383 //Put here code for encryption and remove the exception.
384 throw new UnsupportedOperationException(
385 "We support only Key wrap and Key unwrap.");
386
387 } else if (this.opmode == Cipher.DECRYPT_MODE) {
388 //Put here code for decryption and remove the exception.
389 throw new UnsupportedOperationException(
390 "We support only Key wrap and Key unwrap.");
391
392 } else {
393 //Wrong opmode, we lose.
394 throw new IllegalStateException("Cipher has unappropriate " +
395 "opmode , to invoke this method.");
396 }
397 }
398
399
400 /**
401 * Wrap a key.
402 *
403 * @param key the key to be wrapped.
404 * @throws NullpointerException if <code>key.getEncoded()</code> is null.
405 * This means the key does not support encoding.
406 * @throws IllegalBlockSizeException if the unsigned number representation
407 * of the encoded key is equal or greater than the modulus of the RSAKey.
408 * @throws InvalidKeyException if it is impossible or unsafe to wrap the
409 * key with this cipher (e.g., a hardware
410 * public key is being passed to a
411 * software-only cipher).
412 * @throws IllegalStateException if the Cipher was not initialized, or you
413 * invoke this method in ENCRYPT_MODE or DECRTYPT_MODE.
414 * @return the wrapped key.
415 */
416 byte[] wrap(Key key) throws IllegalBlockSizeException, InvalidKeyException {
417 if (this.initialized == false) {
418 throw new IllegalStateException("Cipher not initialized");
419 }
420 if (key == null) {
421 throw new NullPointerException("Prameter key is null.");
422 }
423 if (this.opmode == Cipher.WRAP_MODE) {
424 //DES1Key
425 if (key.getAlgorithm().equalsIgnoreCase("DES1Key")) {
426 if (key.getFormat().equalsIgnoreCase("RAW")) {
427 //throws NullPointerException or IllegalBlockSizeException
428 return wrapKey(key);
429 }
430 //We are wrong...
431 throw new InvalidKeyException("Key has inappropriate encoding.");
432 }
433 //DESede2Key
434 if (key.getAlgorithm().equalsIgnoreCase("DESede2Key")) {
435 if(key.getFormat().equalsIgnoreCase("RAW")) {
436 //throws NullPointerException or IllegalBlockSizeException
437 return wrapKey(key);
438 }
439 //We are wrong...
440 throw new InvalidKeyException("Key has inappropriate encoding.");
441 }
442 //DESede3Key
443 if (key.getAlgorithm().equalsIgnoreCase("DESede3Key")) {
444 if(key.getFormat().equalsIgnoreCase("RAW")) {
445 //throws NullPointerException or IllegalBlockSizeException
446 return wrapKey(key);
447 }
448 //We are wrong...
449 throw new InvalidKeyException("Key has inappropriate encoding.");
450 }
451 //We are wong...
452 throw new InvalidKeyException("Key has inappropriate algorithm.");
453 }
454 //We are wrong... (default case - shouldn't really happen!)
455 //If we are ditching here, there are something wrong with initialization.
456 throw new IllegalStateException("Cipher contains an unappropriate " +
457 "opmode to invoke this method.");
458 }
459
460 /**
461 * Wraps a key.
462 *
463 * @throws NullpointerException if <code>key.getEncoded()</code> is null.
464 * This means the key does not support encoding.
465 * @throws IllegalBlockSizeException if the unsigned number representation
466 * of the encoded key is equal or greater than the modulus of the RSAKey.
467 * @return the wrapped key as byte array with an unsigned number in binary
468 * representation.
469 */
470 private byte[] wrapKey(Key key) throws IllegalBlockSizeException {
471 byte[] encodedKey = key.getEncoded();
472 if (encodedKey == null) {
473 throw new NullPointerException("Key does not support encoding.");
474 }
475 //Convert the binary representation of the key in non negative number.
476 BigInteger keyAsNumber = new BigInteger(1, encodedKey);
477 BigInteger modulus = this.key.getModulus();
478 // keyAsNumber >= modulus
479 if (keyAsNumber.compareTo(modulus) >= 0) {
480 throw new IllegalBlockSizeException("Keys encoding data to large " +
481 "for the modulus.");
482 }
483 //Do RSA encryption: wrappedKey = keyAsNumber^publicExponent mod modulus
484 BigInteger publicExponent = ((RSAPublicKey) this.key).getPublicExponent();
485 return BigIntegerUtil.toUnsignedByteArray(
486 keyAsNumber.modPow(publicExponent, modulus));
487 }
488
489 /**
490 * Unwrap a previously wrapped key.
491 *
492 * @param wrappedKey the wrapped key to unwrap.
493 * @param wrappedKeyAlgorithm the algorithm associated with the key wrapped
494 * key.
495 * @param wrappedKeyType the type of the wrapped key. This is one of
496 * javax.crypto.Cipher.SECRET_KEY,
497 * javax.crypto.Cipher.PRIVATE_KEY,
498 * javax.crypto.Cipher.PUBLIC_KEY.
499 * @throws InvalidKeyException if wrappedKey does not represent a wrapped
500 * key, or if the algorithm associated with the wrapped key is different
501 * from wrappedKeyAlgorithm and/or its key type is different from
502 * wrappedKeyType.
503 * @throws NoSuchAlgorithmException if no installed providers can create
504 * keys for the wrappedKeyAlgorithm.
505 * @throws IllegalStateException if the Cipher was not initialized.
506 * @return the unwrapped key.
507 */
508 Key unwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, int wrappedKeyType)
509 throws InvalidKeyException, NoSuchAlgorithmException {
510 if (this.initialized == false) {
511 throw new IllegalStateException("Cipher not initialized");
512 }
513 if (wrappedKey == null) {
514 throw new NullPointerException("Prameter wrappedKey is null.");
515 }
516 if (wrappedKeyAlgorithm == null) {
517 throw new NullPointerException("Prameter wrappedKeyAlgorithm is " +
518 "null.");
519 }
520 if (wrappedKeyType != Cipher.SECRET_KEY) {
521 throw new InvalidKeyException("Unsupported wrapped key type.");
522 }
523 if (this.opmode == Cipher.UNWRAP_MODE) {
524 if (wrappedKeyType == Cipher.SECRET_KEY) {
525 if (wrappedKeyAlgorithm.equalsIgnoreCase("DES1Key")) {
526 byte[] unwrappedKey = unwrapKey(wrappedKey);
527 //This check is addressed to the attack described by Dr. Ulrich Kuehn (many thanks!)
528 if (unwrappedKey.length > 8) {
529 throw new InvalidKeyException("Unwrapped DES1Key is longer than 64 bit.");
530 }
531 return new DES1KeySecretKeyImpl(unwrappedKey);
532 }
533 if (wrappedKeyAlgorithm.equalsIgnoreCase("DESede2Key")) {
534 byte[] unwrappedKey = unwrapKey(wrappedKey);
535 //This check is addressed to the attack described by Dr. Ulrich Kuehn (many thanks!)
536 if (unwrappedKey.length > 16) {
537 throw new InvalidKeyException("Unwrapped DESede2Key is longer than 128 bit.");
538 }
539 return new DESede2KeySecretKeyImpl(unwrappedKey);
540 }
541 if (wrappedKeyAlgorithm.equalsIgnoreCase("DESede3Key")) {
542 byte[] unwrappedKey = unwrapKey(wrappedKey);
543 //This check is addressed to the attack described by Dr. Ulrich Kuehn (many thanks!)
544 if (unwrappedKey.length > 24) {
545 throw new InvalidKeyException("Unwrapped DESede3Key is longer than 168 bit.");
546 }
547 return new DESede3KeySecretKeyImpl(unwrapKey(wrappedKey));
548 }
549 //We are wrong...
550 throw new NoSuchAlgorithmException("Requested wrapped key " +
551 "algorithm not supported by the requested wrapped key type.");
552 } if (wrappedKeyType == Cipher.PUBLIC_KEY) {
553 //
554 //put here code for Public Key unwrapping
555 //
556 //We don't support public key unwrapping
557 throw new InvalidKeyException("Requested wrapped key type " +
558 "not supported.");
559 } if (wrappedKeyType == Cipher.PRIVATE_KEY) {
560 //
561 //put here code for Public Key unwrapping
562 //
563 //We don't support private key unwrapping
564 throw new InvalidKeyException("Requested wrapped key type " +
565 "not supported.");
566 }
567 //We are wrong...
568 throw new IllegalArgumentException("Cipher contains an unknown " +
569 "wrapped key type.");
570 }
571 //We are wrong... (default case - shouldn't really happen!)
572 //If we are ditching here, there are something wrong with initialization.
573 throw new IllegalStateException("Cipher contains an unappropriate " +
574 "opmode to invoke this method.");
575 }
576
577
578 /**
579 * Unwrap (decrypt) a wrappedKey in a byte array.
580 *
581 * @param wrapped key the wrapped key in its binary representation.
582 * @throws InvalidKeyException if the unsigned BigInteger representation of
583 * the wrappedKey byte array is equals or greater than the modulus of the
584 * RSAKey.
585 * @throws IllegalStateException if the internal key of the Cipher
586 * is inappropriate (Should not happen).
587 * @return the unwrapped key in its binary representation.
588 */
589 private byte[] unwrapKey(byte[] wrappedKey) throws InvalidKeyException {
590 BigInteger wrappedKeyAsNumber = new BigInteger(1, wrappedKey);
591 BigInteger modulus = this.key.getModulus();
592 if (wrappedKeyAsNumber.compareTo(modulus) >= 0) {
593 throw new InvalidKeyException("Wrapped key data data to " +
594 "large for the modulus.");
595 }
596 //Chinese remainder theorem RSA decryption
597 if (this.key instanceof RSAPrivateCrtKey) {
598 BigInteger primeP =
599 ((RSAPrivateCrtKey) this.key).getPrimeP();
600 BigInteger primeQ =
601 ((RSAPrivateCrtKey) this.key).getPrimeQ();
602 BigInteger primeExponentP =
603 ((RSAPrivateCrtKey) this.key).getPrimeExponentP();
604 BigInteger primeExponentQ =
605 ((RSAPrivateCrtKey) this.key).getPrimeExponentQ();
606 BigInteger crtCoefficient =
607 ((RSAPrivateCrtKey) this.key).getCrtCoefficient();
608
609 BigInteger messageOne =
610 wrappedKeyAsNumber.modPow(primeExponentP, primeP);
611 BigInteger messageTwo =
612 wrappedKeyAsNumber.modPow(primeExponentQ, primeQ);
613 BigInteger h =
614 messageOne.subtract(messageTwo).multiply(crtCoefficient).mod(primeP);
615 BigInteger message = primeQ.multiply(h).add(messageTwo);
616
617 byte[] unWrappedKey = BigIntegerUtil.toUnsignedByteArray(message);
618 return unWrappedKey;
619 }
620 //original RSA decryption
621 if (this.key instanceof RSAPrivateKey) {
622 BigInteger privateExponent =
623 ((RSAPrivateKey) this.key).getPrivateExponent();
624 BigInteger message =
625 wrappedKeyAsNumber.modPow(privateExponent, modulus);
626 byte[] unWrappedKey = BigIntegerUtil.toUnsignedByteArray(message);
627 return unWrappedKey;
628 }
629 //We are wrong... (default case - shouldn't really happen!)
630 //If we are ditching here, there are something wrong with initialization.
631 throw new IllegalStateException("Cipher contains inappropriate Key.");
632 }
633
634 /**
635 * Returns the block size (in bytes) that can be processed while a
636 * multipart cipher operation.
637 *
638 * @throws IllegalStateException if the Cipher was not initialized or a
639 * opmode does not match.
640 * @return the input block size (in bytes).
641 */
642 int getBlockSize() {
643 //Input Block Size
644 if (this.initialized == false) {
645 throw new IllegalStateException("Cipher not initialized");
646 }
647 //Encryption
648 if (this.opmode == Cipher.ENCRYPT_MODE) {
649 return (this.key.getModulus().bitLength() - 1) / 8;
650 }
651 if (this.opmode == Cipher.WRAP_MODE) {
652 return (this.key.getModulus().bitLength() - 1) / 8;
653 }
654 //Decryption
655 if (this.opmode == Cipher.DECRYPT_MODE) {
656 return (this.key.getModulus().bitLength() + 7) / 8;
657 }
658 if (this.opmode == Cipher.UNWRAP_MODE) {
659 return (this.key.getModulus().bitLength() + 7) / 8;
660 }
661 //We are wrong...
662 throw new IllegalStateException("Unknown opmode.");
663 }
664
665 /**
666 * Returns the length in bytes that an output buffer would need to be in
667 * order to hold the result of the next update or doFinal operation, given
668 * the input length inputLen (in bytes).
669 *
670 * @param inputLen the input length in bytes.
671 * @throws IllegalStateException if the Cipher was not initialized or a
672 * opmode does not match.
673 * @return the reqired output buffer size in bytes.
674 */
675 int getOutputSize(int inputLen) {
676 /*
677 * In our case the output size is independend of the input length,
678 * because our ouput blocks have always a length that depends on the
679 * modulus bit length.
680 */
681
682 //Output Block Size
683 if (this.initialized == false) {
684 throw new IllegalStateException("Cipher not initialized");
685 }
686 //Encryption
687 if (this.opmode == Cipher.ENCRYPT_MODE) {
688 return (this.key.getModulus().bitLength() + 7) / 8;
689 }
690 if (this.opmode == Cipher.WRAP_MODE) {
691 return (this.key.getModulus().bitLength() + 7) / 8;
692 }
693 //Decryption
694 if (this.opmode == Cipher.DECRYPT_MODE) {
695 return (this.key.getModulus().bitLength() - 1) / 8;
696 }
697 if (this.opmode == Cipher.UNWRAP_MODE) {
698 return (this.key.getModulus().bitLength() - 1) / 8;
699 }
700 //We are wrong...
701 throw new IllegalStateException("Unknown opmode.");
702 }
703
704 /**
705 * Returns the key size of the given key object in bit. This method will be
706 * invoked trough the JCE before engineInit is invoked.
707 *
708 * @param key the key object.
709 * @throws InvalidKeyException if key is invalid.
710 * @return the key size of the given key object.
711 */
712 int getKeySize(Key key) throws InvalidKeyException {
713 //We check only keys of the JHBCI Provider, so if you want to
714 //use other keys,you have to convert them with the RSAKeyFactory.
715 //We do this, because other RSAKeys may be insecure.
716 if (key instanceof RSAPublicKeyImpl) {
717 return ((RSAKey) key).getModulus().bitLength();
718 }
719 if (key instanceof RSAPrivateKeyImpl) {
720 return ((RSAKey) key).getModulus().bitLength();
721 }
722 if (key instanceof RSAPrivateCrtKeyImpl) {
723 return ((RSAKey) key).getModulus().bitLength();
724 }
725 //We are wrong...
726 throw new InvalidKeyException("Inappropriate Key.");
727 }
728
729 /**
730 * Returns the parameters used with this cipher.
731 *
732 * @throws IllegalStateException if the Cipher was not initialized.
733 * @return the parameters used with this cipher,
734 * or null if this cipher does not use
735 * any parameters.
736 */
737 AlgorithmParameters getParameters() {
738 if (this.initialized == false) {
739 throw new IllegalStateException("Cipher not initialized");
740 }
741 return null;
742 }
743
744 /**
745 * Returns the initialization vector (IV) in a new buffer.
746 *
747 * @throws IllegalStateException if the Cipher was not initialized.
748 * @return the initialization vector in a new buffer,
749 * or null if the underlying algorithm does not
750 * use an IV, or if the IV has not yet been set.
751 */
752 byte[] getIV() {
753 if (this.initialized == false) {
754 throw new IllegalStateException("Cipher not initialized");
755 }
756 return null;
757 }
758 }
759
|
RSACipherImpl |
|