1 /*
   2  * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.crypto.provider;
  27 
  28 import java.util.Locale;
  29 
  30 import java.security.*;
  31 import java.security.interfaces.*;
  32 import java.security.spec.AlgorithmParameterSpec;
  33 import java.security.spec.InvalidParameterSpecException;
  34 import java.security.spec.MGF1ParameterSpec;
  35 
  36 import javax.crypto.*;
  37 import javax.crypto.spec.PSource;
  38 import javax.crypto.spec.OAEPParameterSpec;
  39 
  40 import sun.security.rsa.*;
  41 import sun.security.jca.Providers;
  42 import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec;
  43 import sun.security.util.KeyUtil;
  44 
  45 /**
  46  * RSA cipher implementation. Supports RSA en/decryption and signing/verifying
  47  * using PKCS#1 v1.5 padding and without padding (raw RSA). Note that raw RSA
  48  * is supported mostly for completeness and should only be used in rare cases.
  49  *
  50  * Objects should be instantiated by calling Cipher.getInstance() using the
  51  * following algorithm names:
  52  *  . "RSA/ECB/PKCS1Padding" (or "RSA") for PKCS#1 padding. The mode (blocktype)
  53  *    is selected based on the en/decryption mode and public/private key used
  54  *  . "RSA/ECB/NoPadding" for rsa RSA.
  55  *
  56  * We only do one RSA operation per doFinal() call. If the application passes
  57  * more data via calls to update() or doFinal(), we throw an
  58  * IllegalBlockSizeException when doFinal() is called (see JCE API spec).
  59  * Bulk encryption using RSA does not make sense and is not standardized.
  60  *
  61  * Note: RSA keys should be at least 512 bits long
  62  *
  63  * @since   1.5
  64  * @author  Andreas Sterbenz
  65  */
  66 public final class RSACipher extends CipherSpi {
  67 
  68     // constant for an empty byte array
  69     private final static byte[] B0 = new byte[0];
  70 
  71     // mode constant for public key encryption
  72     private final static int MODE_ENCRYPT = 1;
  73     // mode constant for private key decryption
  74     private final static int MODE_DECRYPT = 2;
  75     // mode constant for private key encryption (signing)
  76     private final static int MODE_SIGN    = 3;
  77     // mode constant for public key decryption (verifying)
  78     private final static int MODE_VERIFY  = 4;
  79 
  80     // constant for raw RSA
  81     private final static String PAD_NONE  = "NoPadding";
  82     // constant for PKCS#1 v1.5 RSA
  83     private final static String PAD_PKCS1 = "PKCS1Padding";
  84     // constant for PKCS#2 v2.0 OAEP with MGF1
  85     private final static String PAD_OAEP_MGF1  = "OAEP";
  86 
  87     // current mode, one of MODE_* above. Set when init() is called
  88     private int mode;
  89 
  90     // active padding type, one of PAD_* above. Set by setPadding()
  91     private String paddingType;
  92 
  93     // padding object
  94     private RSAPadding padding;
  95 
  96     // cipher parameter for OAEP padding and TLS RSA premaster secret
  97     private AlgorithmParameterSpec spec = null;
  98 
  99     // buffer for the data
 100     private byte[] buffer;
 101     // offset into the buffer (number of bytes buffered)
 102     private int bufOfs;
 103 
 104     // size of the output
 105     private int outputSize;
 106 
 107     // the public key, if we were initialized using a public key
 108     private RSAPublicKey publicKey;
 109     // the private key, if we were initialized using a private key
 110     private RSAPrivateKey privateKey;
 111 
 112     // hash algorithm for OAEP
 113     private String oaepHashAlgorithm = "SHA-1";
 114 
 115     // the source of randomness
 116     private SecureRandom random;
 117 
 118     public RSACipher() {
 119         paddingType = PAD_PKCS1;
 120     }
 121 
 122     // modes do not make sense for RSA, but allow ECB
 123     // see JCE spec
 124     protected void engineSetMode(String mode) throws NoSuchAlgorithmException {
 125         if (mode.equalsIgnoreCase("ECB") == false) {
 126             throw new NoSuchAlgorithmException("Unsupported mode " + mode);
 127         }
 128     }
 129 
 130     // set the padding type
 131     // see JCE spec
 132     protected void engineSetPadding(String paddingName)
 133             throws NoSuchPaddingException {
 134         if (paddingName.equalsIgnoreCase(PAD_NONE)) {
 135             paddingType = PAD_NONE;
 136         } else if (paddingName.equalsIgnoreCase(PAD_PKCS1)) {
 137             paddingType = PAD_PKCS1;
 138         } else {
 139             String lowerPadding = paddingName.toLowerCase(Locale.ENGLISH);
 140             if (lowerPadding.equals("oaeppadding")) {
 141                 paddingType = PAD_OAEP_MGF1;
 142             } else if (lowerPadding.startsWith("oaepwith") &&
 143                        lowerPadding.endsWith("andmgf1padding")) {
 144                 paddingType = PAD_OAEP_MGF1;
 145                 // "oaepwith".length() == 8
 146                 // "andmgf1padding".length() == 14
 147                 oaepHashAlgorithm =
 148                         paddingName.substring(8, paddingName.length() - 14);
 149                 // check if MessageDigest appears to be available
 150                 // avoid getInstance() call here
 151                 if (Providers.getProviderList().getService
 152                         ("MessageDigest", oaepHashAlgorithm) == null) {
 153                     throw new NoSuchPaddingException
 154                         ("MessageDigest not available for " + paddingName);
 155                 }
 156             } else {
 157                 throw new NoSuchPaddingException
 158                     ("Padding " + paddingName + " not supported");
 159             }
 160         }
 161     }
 162 
 163     // return 0 as block size, we are not a block cipher
 164     // see JCE spec
 165     protected int engineGetBlockSize() {
 166         return 0;
 167     }
 168 
 169     // return the output size
 170     // see JCE spec
 171     protected int engineGetOutputSize(int inputLen) {
 172         return outputSize;
 173     }
 174 
 175     // no iv, return null
 176     // see JCE spec
 177     protected byte[] engineGetIV() {
 178         return null;
 179     }
 180 
 181     // see JCE spec
 182     protected AlgorithmParameters engineGetParameters() {
 183         if (spec != null && spec instanceof OAEPParameterSpec) {
 184             try {
 185                 AlgorithmParameters params =
 186                     AlgorithmParameters.getInstance("OAEP", "SunJCE");
 187                 params.init(spec);
 188                 return params;
 189             } catch (NoSuchAlgorithmException nsae) {
 190                 // should never happen
 191                 throw new RuntimeException("Cannot find OAEP " +
 192                     " AlgorithmParameters implementation in SunJCE provider");
 193             } catch (NoSuchProviderException nspe) {
 194                 // should never happen
 195                 throw new RuntimeException("Cannot find SunJCE provider");
 196             } catch (InvalidParameterSpecException ipse) {
 197                 // should never happen
 198                 throw new RuntimeException("OAEPParameterSpec not supported");
 199             }
 200         } else {
 201             return null;
 202         }
 203     }
 204 
 205     // see JCE spec
 206     protected void engineInit(int opmode, Key key, SecureRandom random)
 207             throws InvalidKeyException {
 208         try {
 209             init(opmode, key, random, null);
 210         } catch (InvalidAlgorithmParameterException iape) {
 211             // never thrown when null parameters are used;
 212             // but re-throw it just in case
 213             InvalidKeyException ike =
 214                 new InvalidKeyException("Wrong parameters");
 215             ike.initCause(iape);
 216             throw ike;
 217         }
 218     }
 219 
 220     // see JCE spec
 221     protected void engineInit(int opmode, Key key,
 222             AlgorithmParameterSpec params, SecureRandom random)
 223             throws InvalidKeyException, InvalidAlgorithmParameterException {
 224         init(opmode, key, random, params);
 225     }
 226 
 227     // see JCE spec
 228     protected void engineInit(int opmode, Key key,
 229             AlgorithmParameters params, SecureRandom random)
 230             throws InvalidKeyException, InvalidAlgorithmParameterException {
 231         if (params == null) {
 232             init(opmode, key, random, null);
 233         } else {
 234             try {
 235                 OAEPParameterSpec spec =
 236                         params.getParameterSpec(OAEPParameterSpec.class);
 237                 init(opmode, key, random, spec);
 238             } catch (InvalidParameterSpecException ipse) {
 239                 InvalidAlgorithmParameterException iape =
 240                     new InvalidAlgorithmParameterException("Wrong parameter");
 241                 iape.initCause(ipse);
 242                 throw iape;
 243             }
 244         }
 245     }
 246 
 247     // initialize this cipher
 248     private void init(int opmode, Key key, SecureRandom random,
 249             AlgorithmParameterSpec params)
 250             throws InvalidKeyException, InvalidAlgorithmParameterException {
 251         boolean encrypt;
 252         switch (opmode) {
 253         case Cipher.ENCRYPT_MODE:
 254         case Cipher.WRAP_MODE:
 255             encrypt = true;
 256             break;
 257         case Cipher.DECRYPT_MODE:
 258         case Cipher.UNWRAP_MODE:
 259             encrypt = false;
 260             break;
 261         default:
 262             throw new InvalidKeyException("Unknown mode: " + opmode);
 263         }
 264         RSAKey rsaKey = RSAKeyFactory.toRSAKey(key);
 265         if (key instanceof RSAPublicKey) {
 266             mode = encrypt ? MODE_ENCRYPT : MODE_VERIFY;
 267             publicKey = (RSAPublicKey)key;
 268             privateKey = null;
 269         } else { // must be RSAPrivateKey per check in toRSAKey
 270             mode = encrypt ? MODE_SIGN : MODE_DECRYPT;
 271             privateKey = (RSAPrivateKey)key;
 272             publicKey = null;
 273         }
 274         int n = RSACore.getByteLength(rsaKey.getModulus());
 275         outputSize = n;
 276         bufOfs = 0;
 277         if (paddingType == PAD_NONE) {
 278             if (params != null) {
 279                 throw new InvalidAlgorithmParameterException
 280                 ("Parameters not supported");
 281             }
 282             padding = RSAPadding.getInstance(RSAPadding.PAD_NONE, n, random);
 283             buffer = new byte[n];
 284         } else if (paddingType == PAD_PKCS1) {
 285             if (params != null) {
 286                 if (!(params instanceof TlsRsaPremasterSecretParameterSpec)) {
 287                     throw new InvalidAlgorithmParameterException(
 288                             "Parameters not supported");
 289                 }
 290 
 291                 spec = params;
 292                 this.random = random;   // for TLS RSA premaster secret
 293             }
 294             int blockType = (mode <= MODE_DECRYPT) ? RSAPadding.PAD_BLOCKTYPE_2
 295                                                    : RSAPadding.PAD_BLOCKTYPE_1;
 296             padding = RSAPadding.getInstance(blockType, n, random);
 297             if (encrypt) {
 298                 int k = padding.getMaxDataSize();
 299                 buffer = new byte[k];
 300             } else {
 301                 buffer = new byte[n];
 302             }
 303         } else { // PAD_OAEP_MGF1
 304             if ((mode == MODE_SIGN) || (mode == MODE_VERIFY)) {
 305                 throw new InvalidKeyException
 306                         ("OAEP cannot be used to sign or verify signatures");
 307             }
 308             if (params != null) {
 309                 if (!(params instanceof OAEPParameterSpec)) {
 310                     throw new InvalidAlgorithmParameterException
 311                         ("Wrong Parameters for OAEP Padding");
 312                 }
 313                 spec = params;
 314             } else {
 315                 spec = new OAEPParameterSpec(oaepHashAlgorithm, "MGF1",
 316                     MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT);
 317             }
 318             padding = RSAPadding.getInstance(RSAPadding.PAD_OAEP_MGF1, n,
 319                 random, (OAEPParameterSpec)spec);
 320             if (encrypt) {
 321                 int k = padding.getMaxDataSize();
 322                 buffer = new byte[k];
 323             } else {
 324                 buffer = new byte[n];
 325             }
 326         }
 327     }
 328 
 329     // internal update method
 330     private void update(byte[] in, int inOfs, int inLen) {
 331         if ((inLen == 0) || (in == null)) {
 332             return;
 333         }
 334         if (bufOfs + inLen > buffer.length) {
 335             bufOfs = buffer.length + 1;
 336             return;
 337         }
 338         System.arraycopy(in, inOfs, buffer, bufOfs, inLen);
 339         bufOfs += inLen;
 340     }
 341 
 342     // internal doFinal() method. Here we perform the actual RSA operation
 343     private byte[] doFinal() throws BadPaddingException,
 344             IllegalBlockSizeException {
 345         if (bufOfs > buffer.length) {
 346             throw new IllegalBlockSizeException("Data must not be longer "
 347                 + "than " + buffer.length + " bytes");
 348         }
 349         try {
 350             byte[] data;
 351             switch (mode) {
 352             case MODE_SIGN:
 353                 data = padding.pad(buffer, 0, bufOfs);
 354                 return RSACore.rsa(data, privateKey, true);
 355             case MODE_VERIFY:
 356                 byte[] verifyBuffer = RSACore.convert(buffer, 0, bufOfs);
 357                 data = RSACore.rsa(verifyBuffer, publicKey);
 358                 return padding.unpad(data);
 359             case MODE_ENCRYPT:
 360                 data = padding.pad(buffer, 0, bufOfs);
 361                 return RSACore.rsa(data, publicKey);
 362             case MODE_DECRYPT:
 363                 byte[] decryptBuffer = RSACore.convert(buffer, 0, bufOfs);
 364                 data = RSACore.rsa(decryptBuffer, privateKey, false);
 365                 return padding.unpad(data);
 366             default:
 367                 throw new AssertionError("Internal error");
 368             }
 369         } finally {
 370             bufOfs = 0;
 371         }
 372     }
 373 
 374     // see JCE spec
 375     protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) {
 376         update(in, inOfs, inLen);
 377         return B0;
 378     }
 379 
 380     // see JCE spec
 381     protected int engineUpdate(byte[] in, int inOfs, int inLen, byte[] out,
 382             int outOfs) {
 383         update(in, inOfs, inLen);
 384         return 0;
 385     }
 386 
 387     // see JCE spec
 388     protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen)
 389             throws BadPaddingException, IllegalBlockSizeException {
 390         update(in, inOfs, inLen);
 391         return doFinal();
 392     }
 393 
 394     // see JCE spec
 395     protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out,
 396             int outOfs) throws ShortBufferException, BadPaddingException,
 397             IllegalBlockSizeException {
 398         if (outputSize > out.length - outOfs) {
 399             throw new ShortBufferException
 400                 ("Need " + outputSize + " bytes for output");
 401         }
 402         update(in, inOfs, inLen);
 403         byte[] result = doFinal();
 404         int n = result.length;
 405         System.arraycopy(result, 0, out, outOfs, n);
 406         return n;
 407     }
 408 
 409     // see JCE spec
 410     protected byte[] engineWrap(Key key) throws InvalidKeyException,
 411             IllegalBlockSizeException {
 412         byte[] encoded = key.getEncoded();
 413         if ((encoded == null) || (encoded.length == 0)) {
 414             throw new InvalidKeyException("Could not obtain encoded key");
 415         }
 416         if (encoded.length > buffer.length) {
 417             throw new InvalidKeyException("Key is too long for wrapping");
 418         }
 419         update(encoded, 0, encoded.length);
 420         try {
 421             return doFinal();
 422         } catch (BadPaddingException e) {
 423             // should not occur
 424             throw new InvalidKeyException("Wrapping failed", e);
 425         }
 426     }
 427 
 428     // see JCE spec
 429     protected Key engineUnwrap(byte[] wrappedKey, String algorithm,
 430             int type) throws InvalidKeyException, NoSuchAlgorithmException {
 431         if (wrappedKey.length > buffer.length) {
 432             throw new InvalidKeyException("Key is too long for unwrapping");
 433         }
 434 
 435         boolean isTlsRsaPremasterSecret =
 436                 algorithm.equals("TlsRsaPremasterSecret");
 437         Exception failover = null;
 438         byte[] encoded = null;
 439 
 440         update(wrappedKey, 0, wrappedKey.length);
 441         try {
 442             encoded = doFinal();
 443         } catch (BadPaddingException e) {
 444             if (isTlsRsaPremasterSecret) {
 445                 failover = e;
 446             } else {
 447                 throw new InvalidKeyException("Unwrapping failed", e);
 448             }
 449         } catch (IllegalBlockSizeException e) {
 450             // should not occur, handled with length check above
 451             throw new InvalidKeyException("Unwrapping failed", e);
 452         }
 453 
 454         if (isTlsRsaPremasterSecret) {
 455             if (!(spec instanceof TlsRsaPremasterSecretParameterSpec)) {
 456                 throw new IllegalStateException(
 457                         "No TlsRsaPremasterSecretParameterSpec specified");
 458             }
 459 
 460             // polish the TLS premaster secret
 461             encoded = KeyUtil.checkTlsPreMasterSecretKey(
 462                 ((TlsRsaPremasterSecretParameterSpec)spec).getClientVersion(),
 463                 ((TlsRsaPremasterSecretParameterSpec)spec).getServerVersion(),
 464                 random, encoded, (failover != null));
 465         }
 466 
 467         return ConstructKeys.constructKey(encoded, algorithm, type);
 468     }
 469 
 470     // see JCE spec
 471     protected int engineGetKeySize(Key key) throws InvalidKeyException {
 472         RSAKey rsaKey = RSAKeyFactory.toRSAKey(key);
 473         return rsaKey.getModulus().bitLength();
 474     }
 475 }