1:
37:
38:
39: package ;
40:
41: import ;
42: import ;
43: import ;
44:
45: import ;
46:
47: import ;
48: import ;
49: import ;
50: import ;
51: import ;
52: import ;
53:
54: import ;
55: import ;
56: import ;
57: import ;
58:
59: import ;
60:
61: import ;
62:
63: import ;
64: import ;
65: import ;
66: import ;
67: import ;
68: import ;
69:
70: public class RSACipherImpl extends CipherSpi
71: {
72: private static final Logger logger = SystemLogger.SYSTEM;
73:
74: private static final byte[] EMPTY = new byte[0];
75: private int opmode = -1;
76: private RSAPrivateKey decipherKey = null;
77: private RSAPublicKey blindingKey = null;
78: private RSAPublicKey encipherKey = null;
79: private SecureRandom random = null;
80: private byte[] dataBuffer = null;
81: private int pos = 0;
82:
83: protected void engineSetMode (String mode) throws NoSuchAlgorithmException
84: {
85: throw new NoSuchAlgorithmException ("only one mode available");
86: }
87:
88: protected void engineSetPadding (String pad) throws NoSuchPaddingException
89: {
90: throw new NoSuchPaddingException ("only one padding available");
91: }
92:
93: protected int engineGetBlockSize ()
94: {
95: return 1;
96: }
97:
98: protected int engineGetOutputSize (int inputLen)
99: {
100: int outputLen = 0;
101: if (decipherKey != null)
102: {
103: outputLen = (decipherKey.getModulus ().bitLength () + 7) / 8;
104: }
105: else if (encipherKey != null)
106: {
107: outputLen = (encipherKey.getModulus ().bitLength () + 7) / 8;
108: }
109: else
110: throw new IllegalStateException ("not initialized");
111: if (inputLen > outputLen)
112: throw new IllegalArgumentException ("not configured to encode " + inputLen
113: + "bytes; at most " + outputLen);
114: return outputLen;
115: }
116:
117: protected int engineGetKeySize (final Key key) throws InvalidKeyException
118: {
119: if (!(key instanceof RSAKey))
120: throw new InvalidKeyException ("not an RSA key");
121: return ((RSAKey) key).getModulus ().bitLength ();
122: }
123:
124: protected byte[] engineGetIV ()
125: {
126: return null;
127: }
128:
129: protected AlgorithmParameters engineGetParameters()
130: {
131: return null;
132: }
133:
134: protected void engineInit (int opmode, Key key, SecureRandom random)
135: throws InvalidKeyException
136: {
137: int outputLen = 0;
138: if (opmode == Cipher.ENCRYPT_MODE)
139: {
140: if (!(key instanceof RSAPublicKey))
141: throw new InvalidKeyException ("expecting a RSAPublicKey");
142: encipherKey = (RSAPublicKey) key;
143: decipherKey = null;
144: blindingKey = null;
145: outputLen = (encipherKey.getModulus ().bitLength () + 7) / 8;
146: }
147: else if (opmode == Cipher.DECRYPT_MODE)
148: {
149: if (key instanceof RSAPrivateKey)
150: {
151: decipherKey = (RSAPrivateKey) key;
152: encipherKey = null;
153: blindingKey = null;
154: outputLen = (decipherKey.getModulus ().bitLength () + 7) / 8;
155: }
156: else if (key instanceof RSAPublicKey)
157: {
158: if (decipherKey == null)
159: throw new IllegalStateException ("must configure decryption key first");
160: if (!decipherKey.getModulus ().equals (((RSAPublicKey) key).getModulus ()))
161: throw new InvalidKeyException ("blinding key is not compatible");
162: blindingKey = (RSAPublicKey) key;
163: return;
164: }
165: else
166: throw new InvalidKeyException ("expecting either an RSAPrivateKey or an RSAPublicKey (for blinding)");
167: }
168: else
169: throw new IllegalArgumentException ("only encryption and decryption supported");
170: this.random = random;
171: this.opmode = opmode;
172: pos = 0;
173: dataBuffer = new byte[outputLen];
174: }
175:
176: protected void engineInit (int opmode, Key key, AlgorithmParameterSpec spec, SecureRandom random)
177: throws InvalidKeyException
178: {
179: engineInit (opmode, key, random);
180: }
181:
182: protected void engineInit (int opmode, Key key, AlgorithmParameters params, SecureRandom random)
183: throws InvalidKeyException
184: {
185: engineInit (opmode, key, random);
186: }
187:
188: protected byte[] engineUpdate (byte[] in, int offset, int length)
189: {
190: if (opmode != Cipher.ENCRYPT_MODE && opmode != Cipher.DECRYPT_MODE)
191: throw new IllegalStateException ("not initialized");
192: System.arraycopy (in, offset, dataBuffer, pos, length);
193: pos += length;
194: return EMPTY;
195: }
196:
197: protected int engineUpdate (byte[] in, int offset, int length, byte[] out, int outOffset)
198: {
199: engineUpdate (in, offset, length);
200: return 0;
201: }
202:
203: protected byte[] engineDoFinal (byte[] in, int offset, int length)
204: throws IllegalBlockSizeException, BadPaddingException
205: {
206: engineUpdate (in, offset, length);
207: if (opmode == Cipher.DECRYPT_MODE)
208: {
209: if (pos < dataBuffer.length)
210: throw new IllegalBlockSizeException ("expecting exactly " + dataBuffer.length + " bytes");
211: BigInteger enc = new BigInteger (1, dataBuffer);
212: byte[] dec = rsaDecrypt (enc);
213: logger.log (Component.CRYPTO, "RSA: decryption produced\n{0}",
214: new ByteArray (dec));
215: if (dec[0] != 0x02)
216: throw new BadPaddingException ("expected padding type 2");
217: int i;
218: for (i = 1; i < dec.length && dec[i] != 0x00; i++);
219: int len = dec.length - i;
220: byte[] result = new byte[len];
221: System.arraycopy (dec, i, result, 0, len);
222: pos = 0;
223: return result;
224: }
225: else
226: {
227: offset = dataBuffer.length - pos;
228: if (offset < 3)
229: throw new IllegalBlockSizeException ("input is too large to encrypt");
230: byte[] dec = new byte[dataBuffer.length];
231: dec[0] = 0x02;
232: if (random == null)
233: random = new SecureRandom ();
234: byte[] pad = new byte[offset - 2];
235: random.nextBytes (pad);
236: for (int i = 0; i < pad.length; i++)
237: if (pad[i] == 0)
238: pad[i] = 1;
239: System.arraycopy (pad, 0, dec, 1, pad.length);
240: dec[dec.length - pos] = 0x00;
241: System.arraycopy (dataBuffer, 0, dec, offset, pos);
242: logger.log (Component.CRYPTO, "RSA: produced padded plaintext\n{0}",
243: new ByteArray (dec));
244: BigInteger x = new BigInteger (1, dec);
245: BigInteger y = x.modPow (encipherKey.getPublicExponent (),
246: encipherKey.getModulus ());
247: byte[] enc = y.toByteArray ();
248: if (enc[0] == 0x00)
249: {
250: byte[] tmp = new byte[enc.length - 1];
251: System.arraycopy (enc, 1, tmp, 0, tmp.length);
252: enc = tmp;
253: }
254: pos = 0;
255: return enc;
256: }
257: }
258:
259: protected int engineDoFinal (byte[] out, int offset)
260: throws ShortBufferException, IllegalBlockSizeException, BadPaddingException
261: {
262: byte[] result = engineDoFinal (EMPTY, 0, 0);
263: if (out.length - offset < result.length)
264: throw new ShortBufferException ("need " + result.length + ", have "
265: + (out.length - offset));
266: System.arraycopy (result, 0, out, offset, result.length);
267: return result.length;
268: }
269:
270: protected int engineDoFinal (final byte[] input, final int offset, final int length,
271: final byte[] output, final int outputOffset)
272: throws ShortBufferException, IllegalBlockSizeException, BadPaddingException
273: {
274: byte[] result = engineDoFinal (input, offset, length);
275: if (output.length - outputOffset < result.length)
276: throw new ShortBufferException ("need " + result.length + ", have "
277: + (output.length - outputOffset));
278: System.arraycopy (result, 0, output, outputOffset, result.length);
279: return result.length;
280: }
281:
282:
285: private byte[] rsaDecrypt (BigInteger enc)
286: {
287: if (random == null)
288: random = new SecureRandom ();
289: BigInteger n = decipherKey.getModulus ();
290: BigInteger r = null;
291: BigInteger pubExp = null;
292: if (blindingKey != null)
293: pubExp = blindingKey.getPublicExponent ();
294: if (pubExp != null && (decipherKey instanceof RSAPrivateCrtKey))
295: pubExp = ((RSAPrivateCrtKey) decipherKey).getPublicExponent ();
296: if (pubExp != null)
297: {
298: r = new BigInteger (n.bitLength () - 1, random);
299: enc = r.modPow (pubExp, n).multiply (enc).mod (n);
300: }
301:
302: BigInteger dec = enc.modPow (decipherKey.getPrivateExponent (), n);
303:
304: if (pubExp != null)
305: {
306: dec = dec.multiply (r.modInverse (n)).mod (n);
307: }
308:
309: return dec.toByteArray ();
310: }
311: }