Dead
[official-gcc.git] / gomp-20050608-branch / libjava / classpath / gnu / javax / crypto / RSACipherImpl.java
blob0a4c29db6f13b5589d35b5c0a5896162dc9b6bbe
1 /* DiffieHellmanImpl.java -- implementation of the Diffie-Hellman key agreement.
2 Copyright (C) 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package gnu.javax.crypto;
41 import gnu.classpath.ByteArray;
42 import gnu.classpath.debug.Component;
43 import gnu.classpath.debug.SystemLogger;
45 import java.math.BigInteger;
47 import java.security.AlgorithmParameters;
48 import java.security.InvalidAlgorithmParameterException;
49 import java.security.InvalidKeyException;
50 import java.security.Key;
51 import java.security.NoSuchAlgorithmException;
52 import java.security.SecureRandom;
54 import java.security.interfaces.RSAKey;
55 import java.security.interfaces.RSAPrivateKey;
56 import java.security.interfaces.RSAPrivateCrtKey;
57 import java.security.interfaces.RSAPublicKey;
59 import java.security.spec.AlgorithmParameterSpec;
61 import java.util.logging.Logger;
63 import javax.crypto.BadPaddingException;
64 import javax.crypto.Cipher;
65 import javax.crypto.CipherSpi;
66 import javax.crypto.IllegalBlockSizeException;
67 import javax.crypto.NoSuchPaddingException;
68 import javax.crypto.ShortBufferException;
70 public class RSACipherImpl extends CipherSpi
72 private static final Logger logger = SystemLogger.SYSTEM;
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;
83 protected void engineSetMode (String mode) throws NoSuchAlgorithmException
85 throw new NoSuchAlgorithmException ("only one mode available");
88 protected void engineSetPadding (String pad) throws NoSuchPaddingException
90 throw new NoSuchPaddingException ("only one padding available");
93 protected int engineGetBlockSize ()
95 return 1;
98 protected int engineGetOutputSize (int inputLen)
100 int outputLen = 0;
101 if (decipherKey != null)
103 outputLen = (decipherKey.getModulus ().bitLength () + 7) / 8;
105 else if (encipherKey != null)
107 outputLen = (encipherKey.getModulus ().bitLength () + 7) / 8;
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;
117 protected int engineGetKeySize (final Key key) throws InvalidKeyException
119 if (!(key instanceof RSAKey))
120 throw new InvalidKeyException ("not an RSA key");
121 return ((RSAKey) key).getModulus ().bitLength ();
124 protected byte[] engineGetIV ()
126 return null;
129 protected AlgorithmParameters engineGetParameters()
131 return null;
134 protected void engineInit (int opmode, Key key, SecureRandom random)
135 throws InvalidKeyException
137 int outputLen = 0;
138 if (opmode == Cipher.ENCRYPT_MODE)
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;
147 else if (opmode == Cipher.DECRYPT_MODE)
149 if (key instanceof RSAPrivateKey)
151 decipherKey = (RSAPrivateKey) key;
152 encipherKey = null;
153 blindingKey = null;
154 outputLen = (decipherKey.getModulus ().bitLength () + 7) / 8;
156 else if (key instanceof RSAPublicKey)
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;
165 else
166 throw new InvalidKeyException ("expecting either an RSAPrivateKey or an RSAPublicKey (for blinding)");
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];
176 protected void engineInit (int opmode, Key key, AlgorithmParameterSpec spec, SecureRandom random)
177 throws InvalidKeyException
179 engineInit (opmode, key, random);
182 protected void engineInit (int opmode, Key key, AlgorithmParameters params, SecureRandom random)
183 throws InvalidKeyException
185 engineInit (opmode, key, random);
188 protected byte[] engineUpdate (byte[] in, int offset, int length)
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;
197 protected int engineUpdate (byte[] in, int offset, int length, byte[] out, int outOffset)
199 engineUpdate (in, offset, length);
200 return 0;
203 protected byte[] engineDoFinal (byte[] in, int offset, int length)
204 throws IllegalBlockSizeException, BadPaddingException
206 engineUpdate (in, offset, length);
207 if (opmode == Cipher.DECRYPT_MODE)
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;
225 else
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)
250 byte[] tmp = new byte[enc.length - 1];
251 System.arraycopy (enc, 1, tmp, 0, tmp.length);
252 enc = tmp;
254 pos = 0;
255 return enc;
259 protected int engineDoFinal (byte[] out, int offset)
260 throws ShortBufferException, IllegalBlockSizeException, BadPaddingException
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;
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
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;
283 * Decrypts the ciphertext, employing RSA blinding if possible.
285 private byte[] rsaDecrypt (BigInteger enc)
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)
298 r = new BigInteger (n.bitLength () - 1, random);
299 enc = r.modPow (pubExp, n).multiply (enc).mod (n);
302 BigInteger dec = enc.modPow (decipherKey.getPrivateExponent (), n);
304 if (pubExp != null)
306 dec = dec.multiply (r.modInverse (n)).mod (n);
309 return dec.toByteArray ();