001: package org.bouncycastle.crypto.engines;
002:
003: import org.bouncycastle.crypto.AsymmetricBlockCipher;
004: import org.bouncycastle.crypto.CipherParameters;
005: import org.bouncycastle.crypto.DataLengthException;
006: import org.bouncycastle.crypto.params.ParametersWithRandom;
007: import org.bouncycastle.crypto.params.RSAKeyParameters;
008: import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
009:
010: import java.math.BigInteger;
011: import java.security.SecureRandom;
012:
013: /**
014: * this does your basic RSA algorithm with blinding
015: */
016: public class RSABlindedEngine implements AsymmetricBlockCipher {
017: private static BigInteger ZERO = BigInteger.valueOf(0);
018:
019: private RSACoreEngine core = new RSACoreEngine();
020: private RSAKeyParameters key;
021: private SecureRandom random;
022:
023: /**
024: * initialise the RSA engine.
025: *
026: * @param forEncryption true if we are encrypting, false otherwise.
027: * @param param the necessary RSA key parameters.
028: */
029: public void init(boolean forEncryption, CipherParameters param) {
030: core.init(forEncryption, param);
031:
032: if (param instanceof ParametersWithRandom) {
033: ParametersWithRandom rParam = (ParametersWithRandom) param;
034:
035: key = (RSAKeyParameters) rParam.getParameters();
036: random = rParam.getRandom();
037: } else {
038: key = (RSAKeyParameters) param;
039: random = new SecureRandom();
040: }
041: }
042:
043: /**
044: * Return the maximum size for an input block to this engine.
045: * For RSA this is always one byte less than the key size on
046: * encryption, and the same length as the key size on decryption.
047: *
048: * @return maximum size for an input block.
049: */
050: public int getInputBlockSize() {
051: return core.getInputBlockSize();
052: }
053:
054: /**
055: * Return the maximum size for an output block to this engine.
056: * For RSA this is always one byte less than the key size on
057: * decryption, and the same length as the key size on encryption.
058: *
059: * @return maximum size for an output block.
060: */
061: public int getOutputBlockSize() {
062: return core.getOutputBlockSize();
063: }
064:
065: /**
066: * Process a single block using the basic RSA algorithm.
067: *
068: * @param in the input array.
069: * @param inOff the offset into the input buffer where the data starts.
070: * @param inLen the length of the data to be processed.
071: * @return the result of the RSA process.
072: * @exception DataLengthException the input block is too large.
073: */
074: public byte[] processBlock(byte[] in, int inOff, int inLen) {
075: if (key == null) {
076: throw new IllegalStateException(
077: "RSA engine not initialised");
078: }
079:
080: if (key instanceof RSAPrivateCrtKeyParameters) {
081: RSAPrivateCrtKeyParameters k = (RSAPrivateCrtKeyParameters) key;
082:
083: if (k.getPublicExponent() != null) // can't do blinding without a public exponent
084: {
085: BigInteger input = core.convertInput(in, inOff, inLen);
086: BigInteger m = k.getModulus();
087: BigInteger r = calculateR(m);
088: BigInteger result = core.processBlock(r.modPow(
089: k.getPublicExponent(), m).multiply(input)
090: .mod(m));
091:
092: return core.convertOutput(result.multiply(
093: r.modInverse(m)).mod(m));
094: }
095:
096: return core.convertOutput(core.processBlock(core
097: .convertInput(in, inOff, inLen)));
098: } else {
099: return core.convertOutput(core.processBlock(core
100: .convertInput(in, inOff, inLen)));
101: }
102: }
103:
104: /*
105: * calculate a random mess-with-their-heads value.
106: */
107: private BigInteger calculateR(BigInteger m) {
108: int max = m.bitLength() - 1; // must be less than m.bitLength()
109: int min = max / 2;
110: int length = ((random.nextInt() & 0xff) * ((max - min) / 0xff))
111: + min;
112: BigInteger factor = new BigInteger(length, random);
113:
114: while (factor.equals(ZERO)) {
115: factor = new BigInteger(length, random);
116: }
117:
118: return factor;
119: }
120: }
|