1 package org.bouncycastle.crypto.engines;
3 import java.math.BigInteger;
5 import org.bouncycastle.crypto.CipherParameters;
6 import org.bouncycastle.crypto.DataLengthException;
7 import org.bouncycastle.crypto.AsymmetricBlockCipher;
8 import org.bouncycastle.crypto.params.RSAKeyParameters;
9 import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
12 * this does your basic RSA algorithm.
14 public class RSAEngine
15 implements AsymmetricBlockCipher
17 private RSAKeyParameters key;
18 private boolean forEncryption;
21 * initialise the RSA engine.
23 * @param forEncryption true if we are encrypting, false otherwise.
24 * @param param the necessary RSA key parameters.
27 boolean forEncryption,
28 CipherParameters param)
30 this.key = (RSAKeyParameters)param;
31 this.forEncryption = forEncryption;
35 * Return the maximum size for an input block to this engine.
36 * For RSA this is always one byte less than the key size on
37 * encryption, and the same length as the key size on decryption.
39 * @return maximum size for an input block.
41 public int getInputBlockSize()
43 int bitSize = key.getModulus().bitLength();
47 return (bitSize + 7) / 8 - 1;
51 return (bitSize + 7) / 8;
56 * Return the maximum size for an output block to this engine.
57 * For RSA this is always one byte less than the key size on
58 * decryption, and the same length as the key size on encryption.
60 * @return maximum size for an output block.
62 public int getOutputBlockSize()
64 int bitSize = key.getModulus().bitLength();
68 return (bitSize + 7) / 8;
72 return (bitSize + 7) / 8 - 1;
77 * Process a single block using the basic RSA algorithm.
79 * @param in the input array.
80 * @param inOff the offset into the input buffer where the data starts.
81 * @param inLen the length of the data to be processed.
82 * @return the result of the RSA process.
83 * @exception DataLengthException the input block is too large.
85 public byte[] processBlock(
90 if (inLen > (getInputBlockSize() + 1))
92 throw new DataLengthException("input too large for RSA cipher.\n");
94 else if (inLen == (getInputBlockSize() + 1) && (in[inOff] & 0x80) != 0)
96 throw new DataLengthException("input too large for RSA cipher.\n");
101 if (inOff != 0 || inLen != in.length)
103 block = new byte[inLen];
105 System.arraycopy(in, inOff, block, 0, inLen);
112 BigInteger input = new BigInteger(1, block);
115 if (key instanceof RSAPrivateCrtKeyParameters)
118 // we have the extra factors, use the Chinese Remainder Theorem - the author
119 // wishes to express his thanks to Dirk Bonekaemper at rtsffm.com for
120 // advice regarding the expression of this.
122 RSAPrivateCrtKeyParameters crtKey = (RSAPrivateCrtKeyParameters)key;
124 BigInteger d = crtKey.getExponent();
125 BigInteger p = crtKey.getP();
126 BigInteger q = crtKey.getQ();
127 BigInteger dP = crtKey.getDP();
128 BigInteger dQ = crtKey.getDQ();
129 BigInteger qInv = crtKey.getQInv();
131 BigInteger mP, mQ, h, m;
133 // mP = ((input mod p) ^ dP)) mod p
134 mP = (input.remainder(p)).modPow(dP, p);
136 // mQ = ((input mod q) ^ dQ)) mod q
137 mQ = (input.remainder(q)).modPow(dQ, q);
139 // h = qInv * (mP - mQ) mod p
141 h = h.multiply(qInv);
142 h = h.mod(p); // mod (in Java) returns the positive residual
148 output = m.toByteArray();
152 output = input.modPow(
153 key.getExponent(), key.getModulus()).toByteArray();
158 if (output[0] == 0 && output.length > getOutputBlockSize()) // have ended up with an extra zero byte, copy down.
160 byte[] tmp = new byte[output.length - 1];
162 System.arraycopy(output, 1, tmp, 0, tmp.length);
167 if (output.length < getOutputBlockSize()) // have ended up with less bytes than normal, lengthen
169 byte[] tmp = new byte[getOutputBlockSize()];
171 System.arraycopy(output, 0, tmp, tmp.length - output.length, output.length);
178 if (output[0] == 0) // have ended up with an extra zero byte, copy down.
180 byte[] tmp = new byte[output.length - 1];
182 System.arraycopy(output, 1, tmp, 0, tmp.length);