1    package org.bouncycastle.crypto.engines;
2    
3    import java.math.BigInteger;
4    
5    import org.bouncycastle.crypto.CipherParameters;
6    import org.bouncycastle.crypto.DataLengthException;
7    import org.bouncycastle.crypto.AsymmetricBlockCipher;
8    import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
9    import org.bouncycastle.crypto.params.RSAKeyParameters;
10   import org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters;
11   
12   
15   public class RSAEngine
16       implements AsymmetricBlockCipher
17   {
18       private RSAKeyParameters        key;
19       private boolean                 forEncryption;
20   
21       
27       public void init(
28           boolean             forEncryption,
29           CipherParameters    param)
30       {
31           this.key = (RSAKeyParameters)param;
32           this.forEncryption = forEncryption;
33       }
34   
35       
42       public int getInputBlockSize()
43       {
44           int     bitSize = key.getModulus().bitLength();
45   
46           if (forEncryption)
47           {
48               return (bitSize + 7) / 8 - 1;
49           }
50           else
51           {
52               return (bitSize + 7) / 8;
53           }
54       }
55   
56       
63       public int getOutputBlockSize()
64       {
65           int     bitSize = key.getModulus().bitLength();
66   
67           if (forEncryption)
68           {
69               return (bitSize + 7) / 8;
70           }
71           else
72           {
73               return (bitSize + 7) / 8 - 1;
74           }
75       }
76   
77       
86       public byte[] processBlock(
87           byte[]  in,
88           int     inOff,
89           int     inLen)
90       {
91           if (inLen > (getInputBlockSize() + 1))
92           {
93               throw new DataLengthException("input too large for RSA cipher.\n");
94           }
95           else if (inLen == (getInputBlockSize() + 1) && (in[inOff] & 0x80) != 0)
96           {
97               throw new DataLengthException("input too large for RSA cipher.\n");
98           }
99   
100          byte[]  block;
101  
102          if (inOff != 0 || inLen != in.length)
103          {
104              block = new byte[inLen];
105  
106              System.arraycopy(in, inOff, block, 0, inLen);
107          }
108          else
109          {
110              block = in;
111          }
112  
113          BigInteger  input = new BigInteger(1, block);
114          byte[]      output;
115  
116          if (key instanceof RSAPrivateCrtKeyParameters)
117          {
118              
119              
120              
121              
122              
123              RSAPrivateCrtKeyParameters crtKey = (RSAPrivateCrtKeyParameters)key;
124  
125              BigInteger d = crtKey.getExponent();
126              BigInteger p = crtKey.getP();
127              BigInteger q = crtKey.getQ();
128              BigInteger dP = crtKey.getDP();
129              BigInteger dQ = crtKey.getDQ();
130              BigInteger qInv = crtKey.getQInv();
131      
132              BigIntegerBigIntegerBigInteger            // mP = ((input mod p) ^ dP)) mod p
133              mP = (input.remainder(p)).modPow(dP, p);
134      
135              // mQ = ((input mod q) ^ dQ)) mod q
136              mQ = (input.remainder(q)).modPow(dQ, q);
137      
138              // h = qInv * (mP - mQ) mod p
139              h = mP.subtract(mQ);
140              h = h.multiply(qInv);
141              h = h.mod(p);               // mod (in Java) returns the positive residual
142      
143              // m = h * q + mQ
144              m = h.multiply(q);
145              m = m.add(mQ);
146      
147              output = m.toByteArray();
148          }
149          else
150          {
151              output = input.modPow(
152                          key.getExponent(), key.getModulus()).toByteArray();
153          }
154  
155          if (forEncryption)
156          {
157              if (output[0] == 0 && output.length > getOutputBlockSize())        // have ended up with an extra zero byte, copy down.
158              {
159                  byte[]  tmp = new byte[output.length - 1];
160  
161                  System.arraycopy(output, 1, tmp, 0, tmp.length);
162  
163                  return tmp;
164              }
165  
166              if (output.length < getOutputBlockSize())     // have ended up with less bytes than normal, lengthen
167              {
168                  byte[]  tmp = new byte[getOutputBlockSize()];
169  
170                  System.arraycopy(output, 0, tmp, tmp.length - output.length, output.length);
171  
172                  return tmp;
173              }
174          }
175          else
176          {
177              if (output[0] == 0)        // have ended up with an extra zero byte, copy down.
178              {
179                  byte[]  tmp = new byte[output.length - 1];
180  
181                  System.arraycopy(output, 1, tmp, 0, tmp.length);
182  
183                  return tmp;
184              }
185          }
186          return output;
187      }
188  }
189  ?????????????BigInteger??????????????????????????mP???????????????????input???????????????????????????????????p??????????????????????????????????????????????dP??????????????????????????????????????????????????p??????????????????????????mQ???????????????????input???????????????????????????????????q??????????????????????????????????????????????dQ??????????????????????????????????????????????????q??????????????????????????h?????????????????mP?????????????????????????????mQ?????????????h?????????????????h????????????????????????????qInv?????????????h?????????????????h???????????????????????p???????????????????????????????????????????????????????????????????m?????????????????h????????????????????????????q?????????????m?????????????????m???????????????????????mQ?????????????output??????????????????????m?????????????output??????????????????????input?????????????????????????key?????????????????????????????getExponent????????????????????????????????????????????key????????????????????????????????????????????????getModulus?????????????forEncryption?????????????????output???????????????????????????????????output???????????????????????????????????????????????????getOutputBlockSize?????????????????????????????????????????????????????????????????????????????????????????????????byte???????????????????????????????????byte????????????????????????????????????????output??????????????????????????????????output?????????????????????????????????????????????tmp?????????????????????????????????????????????????????tmp????????????????????????tmp?????????????????output?????????????????????????????????getOutputBlockSize????????????????????????????????????????????????????????????????????????????byte???????????????????????????????????byte????????????????????????????????????????getOutputBlockSize??????????????????????????????????output?????????????????????????????????????????????tmp??????????????????????????????????????????????????tmp???????????????????????????????????????????????????????????????output??????????????????????????????????????????????????????????????????????????????output????????????????????????tmp?????????????????output?????????????????????????????????????????????????????????byte???????????????????????????????????byte????????????????????????????????????????output??????????????????????????????????output?????????????????????????????????????????????tmp?????????????????????????????????????????????????????tmp????????????????????????tmp????????????????output