| package org.bouncycastle.crypto.engines; |
| |
| import org.bouncycastle.crypto.CipherParameters; |
| import org.bouncycastle.crypto.DataLengthException; |
| import org.bouncycastle.crypto.params.ParametersWithRandom; |
| import org.bouncycastle.crypto.params.RSAKeyParameters; |
| import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; |
| |
| import java.math.BigInteger; |
| |
| /** |
| * this does your basic RSA algorithm. |
| */ |
| class RSACoreEngine |
| { |
| private RSAKeyParameters key; |
| private boolean forEncryption; |
| |
| /** |
| * initialise the RSA engine. |
| * |
| * @param forEncryption true if we are encrypting, false otherwise. |
| * @param param the necessary RSA key parameters. |
| */ |
| public void init( |
| boolean forEncryption, |
| CipherParameters param) |
| { |
| if (param instanceof ParametersWithRandom) |
| { |
| ParametersWithRandom rParam = (ParametersWithRandom)param; |
| |
| key = (RSAKeyParameters)rParam.getParameters(); |
| } |
| else |
| { |
| key = (RSAKeyParameters)param; |
| } |
| |
| this.forEncryption = forEncryption; |
| } |
| |
| /** |
| * Return the maximum size for an input block to this engine. |
| * For RSA this is always one byte less than the key size on |
| * encryption, and the same length as the key size on decryption. |
| * |
| * @return maximum size for an input block. |
| */ |
| public int getInputBlockSize() |
| { |
| int bitSize = key.getModulus().bitLength(); |
| |
| if (forEncryption) |
| { |
| return (bitSize + 7) / 8 - 1; |
| } |
| else |
| { |
| return (bitSize + 7) / 8; |
| } |
| } |
| |
| /** |
| * Return the maximum size for an output block to this engine. |
| * For RSA this is always one byte less than the key size on |
| * decryption, and the same length as the key size on encryption. |
| * |
| * @return maximum size for an output block. |
| */ |
| public int getOutputBlockSize() |
| { |
| int bitSize = key.getModulus().bitLength(); |
| |
| if (forEncryption) |
| { |
| return (bitSize + 7) / 8; |
| } |
| else |
| { |
| return (bitSize + 7) / 8 - 1; |
| } |
| } |
| |
| public BigInteger convertInput( |
| byte[] in, |
| int inOff, |
| int inLen) |
| { |
| if (inLen > (getInputBlockSize() + 1)) |
| { |
| throw new DataLengthException("input too large for RSA cipher."); |
| } |
| else if (inLen == (getInputBlockSize() + 1) && !forEncryption) |
| { |
| throw new DataLengthException("input too large for RSA cipher."); |
| } |
| |
| byte[] block; |
| |
| if (inOff != 0 || inLen != in.length) |
| { |
| block = new byte[inLen]; |
| |
| System.arraycopy(in, inOff, block, 0, inLen); |
| } |
| else |
| { |
| block = in; |
| } |
| |
| BigInteger res = new BigInteger(1, block); |
| if (res.compareTo(key.getModulus()) >= 0) |
| { |
| throw new DataLengthException("input too large for RSA cipher."); |
| } |
| |
| return res; |
| } |
| |
| public byte[] convertOutput( |
| BigInteger result) |
| { |
| byte[] output = result.toByteArray(); |
| |
| if (forEncryption) |
| { |
| if (output[0] == 0 && output.length > getOutputBlockSize()) // have ended up with an extra zero byte, copy down. |
| { |
| byte[] tmp = new byte[output.length - 1]; |
| |
| System.arraycopy(output, 1, tmp, 0, tmp.length); |
| |
| return tmp; |
| } |
| |
| if (output.length < getOutputBlockSize()) // have ended up with less bytes than normal, lengthen |
| { |
| byte[] tmp = new byte[getOutputBlockSize()]; |
| |
| System.arraycopy(output, 0, tmp, tmp.length - output.length, output.length); |
| |
| return tmp; |
| } |
| } |
| else |
| { |
| if (output[0] == 0) // have ended up with an extra zero byte, copy down. |
| { |
| byte[] tmp = new byte[output.length - 1]; |
| |
| System.arraycopy(output, 1, tmp, 0, tmp.length); |
| |
| return tmp; |
| } |
| } |
| |
| return output; |
| } |
| |
| public BigInteger processBlock(BigInteger input) |
| { |
| if (key instanceof RSAPrivateCrtKeyParameters) |
| { |
| // |
| // we have the extra factors, use the Chinese Remainder Theorem - the author |
| // wishes to express his thanks to Dirk Bonekaemper at rtsffm.com for |
| // advice regarding the expression of this. |
| // |
| RSAPrivateCrtKeyParameters crtKey = (RSAPrivateCrtKeyParameters)key; |
| |
| BigInteger p = crtKey.getP(); |
| BigInteger q = crtKey.getQ(); |
| BigInteger dP = crtKey.getDP(); |
| BigInteger dQ = crtKey.getDQ(); |
| BigInteger qInv = crtKey.getQInv(); |
| |
| BigInteger mP, mQ, h, m; |
| |
| // mP = ((input mod p) ^ dP)) mod p |
| mP = (input.remainder(p)).modPow(dP, p); |
| |
| // mQ = ((input mod q) ^ dQ)) mod q |
| mQ = (input.remainder(q)).modPow(dQ, q); |
| |
| // h = qInv * (mP - mQ) mod p |
| h = mP.subtract(mQ); |
| h = h.multiply(qInv); |
| h = h.mod(p); // mod (in Java) returns the positive residual |
| |
| // m = h * q + mQ |
| m = h.multiply(q); |
| m = m.add(mQ); |
| |
| return m; |
| } |
| else |
| { |
| return input.modPow( |
| key.getExponent(), key.getModulus()); |
| } |
| } |
| } |