1 package org.bouncycastle.crypto.engines;
2 
3 import java.math.BigInteger;
4 import java.security.SecureRandom;
5 
6 import org.bouncycastle.crypto.AsymmetricBlockCipher;
7 import org.bouncycastle.crypto.CipherParameters;
8 import org.bouncycastle.crypto.DataLengthException;
9 import org.bouncycastle.crypto.params.ParametersWithRandom;
10 import org.bouncycastle.crypto.params.RSAKeyParameters;
11 import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
12 import org.bouncycastle.util.BigIntegers;
13 
14 /**
15  * this does your basic RSA algorithm with blinding
16  */
17 public class RSABlindedEngine
18     implements AsymmetricBlockCipher
19 {
20     private static final 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      */
init( boolean forEncryption, CipherParameters param)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      */
getInputBlockSize()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      */
getOutputBlockSize()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      */
processBlock( byte[] in, int inOff, int inLen)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