RSABlindedEngine.java revision e6bf3e8dfa2804891a82075cb469b736321b4827
1package org.bouncycastle.crypto.engines;
2
3import org.bouncycastle.crypto.AsymmetricBlockCipher;
4import org.bouncycastle.crypto.CipherParameters;
5import org.bouncycastle.crypto.DataLengthException;
6import org.bouncycastle.crypto.params.ParametersWithRandom;
7import org.bouncycastle.crypto.params.RSAKeyParameters;
8import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
9import org.bouncycastle.util.BigIntegers;
10
11import java.math.BigInteger;
12import java.security.SecureRandom;
13
14/**
15 * this does your basic RSA algorithm with blinding
16 */
17public class RSABlindedEngine
18    implements AsymmetricBlockCipher
19{
20    private static BigInteger ONE = BigInteger.valueOf(1);
21
22    private RSACoreEngine    core = new RSACoreEngine();
23    private RSAKeyParameters key;
24    private SecureRandom     random;
25
26    /**
27     * initialise the RSA engine.
28     *
29     * @param forEncryption true if we are encrypting, false otherwise.
30     * @param param the necessary RSA key parameters.
31     */
32    public void init(
33        boolean             forEncryption,
34        CipherParameters    param)
35    {
36        core.init(forEncryption, param);
37
38        if (param instanceof ParametersWithRandom)
39        {
40            ParametersWithRandom    rParam = (ParametersWithRandom)param;
41
42            key = (RSAKeyParameters)rParam.getParameters();
43            random = rParam.getRandom();
44        }
45        else
46        {
47            key = (RSAKeyParameters)param;
48            random = new SecureRandom();
49        }
50    }
51
52    /**
53     * Return the maximum size for an input block to this engine.
54     * For RSA this is always one byte less than the key size on
55     * encryption, and the same length as the key size on decryption.
56     *
57     * @return maximum size for an input block.
58     */
59    public int getInputBlockSize()
60    {
61        return core.getInputBlockSize();
62    }
63
64    /**
65     * Return the maximum size for an output block to this engine.
66     * For RSA this is always one byte less than the key size on
67     * decryption, and the same length as the key size on encryption.
68     *
69     * @return maximum size for an output block.
70     */
71    public int getOutputBlockSize()
72    {
73        return core.getOutputBlockSize();
74    }
75
76    /**
77     * Process a single block using the basic RSA algorithm.
78     *
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.
84     */
85    public byte[] processBlock(
86        byte[]  in,
87        int     inOff,
88        int     inLen)
89    {
90        if (key == null)
91        {
92            throw new IllegalStateException("RSA engine not initialised");
93        }
94
95        BigInteger input = core.convertInput(in, inOff, inLen);
96
97        BigInteger result;
98        if (key instanceof RSAPrivateCrtKeyParameters)
99        {
100            RSAPrivateCrtKeyParameters k = (RSAPrivateCrtKeyParameters)key;
101
102            BigInteger e = k.getPublicExponent();
103            if (e != null)   // can't do blinding without a public exponent
104            {
105                BigInteger m = k.getModulus();
106                BigInteger r = BigIntegers.createRandomInRange(ONE, m.subtract(ONE), random);
107
108                BigInteger blindedInput = r.modPow(e, m).multiply(input).mod(m);
109                BigInteger blindedResult = core.processBlock(blindedInput);
110
111                BigInteger rInv = r.modInverse(m);
112                result = blindedResult.multiply(rInv).mod(m);
113            }
114            else
115            {
116                result = core.processBlock(input);
117            }
118        }
119        else
120        {
121            result = core.processBlock(input);
122        }
123
124        return core.convertOutput(result);
125    }
126}
127