Source for gnu.javax.crypto.RSACipherImpl

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