123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300 |
- /* RSACipherImpl.java --
- Copyright (C) 2005, 2006 Free Software Foundation, Inc.
- This file is part of GNU Classpath.
- GNU Classpath is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
- GNU Classpath is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with GNU Classpath; see the file COPYING. If not, write to the
- Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- 02110-1301 USA.
- Linking this library statically or dynamically with other modules is
- making a combined work based on this library. Thus, the terms and
- conditions of the GNU General Public License cover the whole
- combination.
- As a special exception, the copyright holders of this library give you
- permission to link this library with independent modules to produce an
- executable, regardless of the license terms of these independent
- modules, and to copy and distribute the resulting executable under
- terms of your choice, provided that you also meet, for each linked
- independent module, the terms and conditions of the license of that
- module. An independent module is a module which is not derived from
- or based on this library. If you modify this library, you may extend
- this exception to your version of the library, but you are not
- obligated to do so. If you do not wish to do so, delete this
- exception statement from your version. */
- package gnu.javax.crypto;
- import gnu.classpath.debug.Component;
- import gnu.classpath.debug.SystemLogger;
- import gnu.java.security.sig.rsa.EME_PKCS1_V1_5;
- import gnu.java.security.util.ByteArray;
- import java.math.BigInteger;
- import java.security.AlgorithmParameters;
- import java.security.InvalidKeyException;
- import java.security.Key;
- import java.security.NoSuchAlgorithmException;
- import java.security.SecureRandom;
- import java.security.interfaces.RSAKey;
- import java.security.interfaces.RSAPrivateCrtKey;
- import java.security.interfaces.RSAPrivateKey;
- import java.security.interfaces.RSAPublicKey;
- import java.security.spec.AlgorithmParameterSpec;
- import javax.crypto.BadPaddingException;
- import javax.crypto.Cipher;
- import javax.crypto.CipherSpi;
- import javax.crypto.IllegalBlockSizeException;
- import javax.crypto.NoSuchPaddingException;
- import javax.crypto.ShortBufferException;
- public class RSACipherImpl
- extends CipherSpi
- {
- private static final SystemLogger logger = SystemLogger.SYSTEM;
- private static final byte[] EMPTY = new byte[0];
- private int opmode = -1;
- private RSAPrivateKey decipherKey = null;
- private RSAPublicKey blindingKey = null;
- private RSAPublicKey encipherKey = null;
- private SecureRandom random = null;
- private byte[] dataBuffer = null;
- private int pos = 0;
- protected void engineSetMode(String mode) throws NoSuchAlgorithmException
- {
- throw new NoSuchAlgorithmException("only one mode available");
- }
- protected void engineSetPadding(String pad) throws NoSuchPaddingException
- {
- throw new NoSuchPaddingException("only one padding available");
- }
- protected int engineGetBlockSize()
- {
- return 1;
- }
- protected int engineGetOutputSize(int inputLen)
- {
- int outputLen = 0;
- if (decipherKey != null)
- outputLen = (decipherKey.getModulus().bitLength() + 7) / 8;
- else if (encipherKey != null)
- outputLen = (encipherKey.getModulus().bitLength() + 7) / 8;
- else
- throw new IllegalStateException("not initialized");
- if (inputLen > outputLen)
- throw new IllegalArgumentException("not configured to encode " + inputLen
- + "bytes; at most " + outputLen);
- return outputLen;
- }
- protected int engineGetKeySize(final Key key) throws InvalidKeyException
- {
- if (! (key instanceof RSAKey))
- throw new InvalidKeyException("not an RSA key");
- return ((RSAKey) key).getModulus().bitLength();
- }
- protected byte[] engineGetIV()
- {
- return null;
- }
- protected AlgorithmParameters engineGetParameters()
- {
- return null;
- }
- protected void engineInit(int opmode, Key key, SecureRandom random)
- throws InvalidKeyException
- {
- int outputLen = 0;
- if (opmode == Cipher.ENCRYPT_MODE)
- {
- if (! (key instanceof RSAPublicKey))
- throw new InvalidKeyException("expecting a RSAPublicKey");
- encipherKey = (RSAPublicKey) key;
- decipherKey = null;
- blindingKey = null;
- outputLen = (encipherKey.getModulus().bitLength() + 7) / 8;
- }
- else if (opmode == Cipher.DECRYPT_MODE)
- {
- if (key instanceof RSAPrivateKey)
- {
- decipherKey = (RSAPrivateKey) key;
- encipherKey = null;
- blindingKey = null;
- outputLen = (decipherKey.getModulus().bitLength() + 7) / 8;
- }
- else if (key instanceof RSAPublicKey)
- {
- if (decipherKey == null)
- throw new IllegalStateException("must configure decryption key first");
- if (! decipherKey.getModulus().equals(((RSAPublicKey) key).getModulus()))
- throw new InvalidKeyException("blinding key is not compatible");
- blindingKey = (RSAPublicKey) key;
- return;
- }
- else
- throw new InvalidKeyException(
- "expecting either an RSAPrivateKey or an RSAPublicKey (for blinding)");
- }
- else
- throw new IllegalArgumentException("only encryption and decryption supported");
- this.random = random;
- this.opmode = opmode;
- pos = 0;
- dataBuffer = new byte[outputLen];
- }
- protected void engineInit(int opmode, Key key, AlgorithmParameterSpec spec,
- SecureRandom random) throws InvalidKeyException
- {
- engineInit(opmode, key, random);
- }
- protected void engineInit(int opmode, Key key, AlgorithmParameters params,
- SecureRandom random) throws InvalidKeyException
- {
- engineInit(opmode, key, random);
- }
- protected byte[] engineUpdate(byte[] in, int offset, int length)
- {
- if (opmode != Cipher.ENCRYPT_MODE && opmode != Cipher.DECRYPT_MODE)
- throw new IllegalStateException("not initialized");
- System.arraycopy(in, offset, dataBuffer, pos, length);
- pos += length;
- return EMPTY;
- }
- protected int engineUpdate(byte[] in, int offset, int length, byte[] out,
- int outOffset)
- {
- engineUpdate(in, offset, length);
- return 0;
- }
- protected byte[] engineDoFinal(byte[] in, int offset, int length)
- throws IllegalBlockSizeException, BadPaddingException
- {
- engineUpdate(in, offset, length);
- if (opmode == Cipher.DECRYPT_MODE)
- {
- BigInteger enc = new BigInteger (1, dataBuffer);
- byte[] dec = rsaDecrypt (enc);
- logger.log (Component.CRYPTO, "RSA: decryption produced\n{0}",
- new ByteArray (dec));
- EME_PKCS1_V1_5 pkcs = EME_PKCS1_V1_5.getInstance(decipherKey);
- byte[] result = pkcs.decode(dec);
- return result;
- }
- else
- {
- offset = dataBuffer.length - pos;
- if (offset < 3)
- throw new IllegalBlockSizeException("input is too large to encrypt");
- EME_PKCS1_V1_5 pkcs = EME_PKCS1_V1_5.getInstance(encipherKey);
- if (random == null)
- random = new SecureRandom();
- byte[] em = new byte[pos];
- System.arraycopy(dataBuffer, 0, em, 0, pos);
- byte[] dec = pkcs.encode(em, random);
- logger.log (Component.CRYPTO, "RSA: produced padded plaintext\n{0}",
- new ByteArray (dec));
- BigInteger x = new BigInteger (1, dec);
- BigInteger y = x.modPow (encipherKey.getPublicExponent (),
- encipherKey.getModulus ());
- byte[] enc = y.toByteArray ();
- if (enc[0] == 0x00)
- {
- byte[] tmp = new byte[enc.length - 1];
- System.arraycopy(enc, 1, tmp, 0, tmp.length);
- enc = tmp;
- }
- pos = 0;
- return enc;
- }
- }
- protected int engineDoFinal(byte[] out, int offset)
- throws ShortBufferException, IllegalBlockSizeException,
- BadPaddingException
- {
- byte[] result = engineDoFinal(EMPTY, 0, 0);
- if (out.length - offset < result.length)
- throw new ShortBufferException("need " + result.length + ", have "
- + (out.length - offset));
- System.arraycopy(result, 0, out, offset, result.length);
- return result.length;
- }
- protected int engineDoFinal(final byte[] input, final int offset,
- final int length, final byte[] output,
- final int outputOffset)
- throws ShortBufferException, IllegalBlockSizeException,
- BadPaddingException
- {
- byte[] result = engineDoFinal(input, offset, length);
- if (output.length - outputOffset < result.length)
- throw new ShortBufferException("need " + result.length + ", have "
- + (output.length - outputOffset));
- System.arraycopy(result, 0, output, outputOffset, result.length);
- return result.length;
- }
- /**
- * Decrypts the ciphertext, employing RSA blinding if possible.
- */
- private byte[] rsaDecrypt(BigInteger enc)
- {
- if (random == null)
- random = new SecureRandom();
- BigInteger n = decipherKey.getModulus();
- BigInteger r = null;
- BigInteger pubExp = null;
- if (blindingKey != null)
- pubExp = blindingKey.getPublicExponent();
- if (pubExp != null && (decipherKey instanceof RSAPrivateCrtKey))
- pubExp = ((RSAPrivateCrtKey) decipherKey).getPublicExponent();
- if (pubExp != null)
- {
- r = new BigInteger(n.bitLength() - 1, random);
- enc = r.modPow(pubExp, n).multiply(enc).mod(n);
- }
- BigInteger dec = enc.modPow(decipherKey.getPrivateExponent(), n);
- if (pubExp != null)
- {
- dec = dec.multiply (r.modInverse (n)).mod (n);
- }
- byte[] decb = dec.toByteArray();
- if (decb[0] != 0x00)
- {
- byte[] b = new byte[decb.length + 1];
- System.arraycopy(decb, 0, b, 1, decb.length);
- decb = b;
- }
- return decb;
- }
- }
|