1 /*
   2  * Copyright (c) 2005, 2014, 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 sun.security.mscapi;
  27 
  28 import java.math.BigInteger;
  29 import java.security.*;
  30 import java.security.Key;
  31 import java.security.interfaces.*;
  32 import java.security.spec.*;
  33 
  34 import javax.crypto.*;
  35 import javax.crypto.spec.*;
  36 
  37 import sun.security.rsa.RSAKeyFactory;
  38 import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec;
  39 import sun.security.util.KeyUtil;
  40 
  41 /**
  42  * RSA cipher implementation using the Microsoft Crypto API.
  43  * Supports RSA en/decryption and signing/verifying using PKCS#1 v1.5 padding.
  44  *
  45  * Objects should be instantiated by calling Cipher.getInstance() using the
  46  * following algorithm name:
  47  *
  48  *  . "RSA/ECB/PKCS1Padding" (or "RSA") for PKCS#1 padding. The mode (blocktype)
  49  *    is selected based on the en/decryption mode and public/private key used.
  50  *
  51  * We only do one RSA operation per doFinal() call. If the application passes
  52  * more data via calls to update() or doFinal(), we throw an
  53  * IllegalBlockSizeException when doFinal() is called (see JCE API spec).
  54  * Bulk encryption using RSA does not make sense and is not standardized.
  55  *
  56  * Note: RSA keys should be at least 512 bits long
  57  *
  58  * @since   1.6
  59  * @author  Andreas Sterbenz
  60  * @author  Vincent Ryan
  61  */
  62 public final class RSACipher extends CipherSpi {
  63 
  64     // constant for an empty byte array
  65     private final static byte[] B0 = new byte[0];
  66 
  67     // mode constant for public key encryption
  68     private final static int MODE_ENCRYPT = 1;
  69     // mode constant for private key decryption
  70     private final static int MODE_DECRYPT = 2;
  71     // mode constant for private key encryption (signing)
  72     private final static int MODE_SIGN    = 3;
  73     // mode constant for public key decryption (verifying)
  74     private final static int MODE_VERIFY  = 4;
  75 
  76     // constant for PKCS#1 v1.5 RSA
  77     private final static String PAD_PKCS1 = "PKCS1Padding";
  78     private final static int PAD_PKCS1_LENGTH = 11;
  79 
  80     // current mode, one of MODE_* above. Set when init() is called
  81     private int mode;
  82 
  83     // active padding type, one of PAD_* above. Set by setPadding()
  84     private String paddingType;
  85     private int paddingLength = 0;
  86 
  87     // buffer for the data
  88     private byte[] buffer;
  89     // offset into the buffer (number of bytes buffered)
  90     private int bufOfs;
  91 
  92     // size of the output (the length of the key).
  93     private int outputSize;
  94 
  95     // the public key, if we were initialized using a public key
  96     private sun.security.mscapi.Key publicKey;
  97 
  98     // the private key, if we were initialized using a private key
  99     private sun.security.mscapi.Key privateKey;
 100 
 101     // cipher parameter for TLS RSA premaster secret
 102     private AlgorithmParameterSpec spec = null;
 103 
 104     // the source of randomness
 105     private SecureRandom random;
 106 
 107     public RSACipher() {
 108         paddingType = PAD_PKCS1;
 109     }
 110 
 111     // modes do not make sense for RSA, but allow ECB
 112     // see JCE spec
 113     protected void engineSetMode(String mode) throws NoSuchAlgorithmException {
 114         if (mode.equalsIgnoreCase("ECB") == false) {
 115             throw new NoSuchAlgorithmException("Unsupported mode " + mode);
 116         }
 117     }
 118 
 119     // set the padding type
 120     // see JCE spec
 121     protected void engineSetPadding(String paddingName)
 122             throws NoSuchPaddingException {
 123         if (paddingName.equalsIgnoreCase(PAD_PKCS1)) {
 124             paddingType = PAD_PKCS1;
 125         } else {
 126             throw new NoSuchPaddingException
 127                 ("Padding " + paddingName + " not supported");
 128         }
 129     }
 130 
 131     // return 0 as block size, we are not a block cipher
 132     // see JCE spec
 133     protected int engineGetBlockSize() {
 134         return 0;
 135     }
 136 
 137     // return the output size
 138     // see JCE spec
 139     protected int engineGetOutputSize(int inputLen) {
 140         return outputSize;
 141     }
 142 
 143     // no iv, return null
 144     // see JCE spec
 145     protected byte[] engineGetIV() {
 146         return null;
 147     }
 148 
 149     // no parameters, return null
 150     // see JCE spec
 151     protected AlgorithmParameters engineGetParameters() {
 152         return null;
 153     }
 154 
 155     // see JCE spec
 156     protected void engineInit(int opmode, Key key, SecureRandom random)
 157             throws InvalidKeyException {
 158         init(opmode, key);
 159     }
 160 
 161     // see JCE spec
 162     @SuppressWarnings("deprecation")
 163     protected void engineInit(int opmode, Key key,
 164             AlgorithmParameterSpec params, SecureRandom random)
 165             throws InvalidKeyException, InvalidAlgorithmParameterException {
 166 
 167         if (params != null) {
 168             if (!(params instanceof TlsRsaPremasterSecretParameterSpec)) {
 169                 throw new InvalidAlgorithmParameterException(
 170                         "Parameters not supported");
 171             }
 172             spec = params;
 173             this.random = random;   // for TLS RSA premaster secret
 174         }
 175         init(opmode, key);
 176     }
 177 
 178     // see JCE spec
 179     protected void engineInit(int opmode, Key key,
 180             AlgorithmParameters params, SecureRandom random)
 181             throws InvalidKeyException, InvalidAlgorithmParameterException {
 182 
 183         if (params != null) {
 184             throw new InvalidAlgorithmParameterException
 185                 ("Parameters not supported");
 186         }
 187         init(opmode, key);
 188     }
 189 
 190     // initialize this cipher
 191     private void init(int opmode, Key key) throws InvalidKeyException {
 192 
 193         boolean encrypt;
 194 
 195         switch (opmode) {
 196         case Cipher.ENCRYPT_MODE:
 197         case Cipher.WRAP_MODE:
 198             paddingLength = PAD_PKCS1_LENGTH;
 199             encrypt = true;
 200             break;
 201         case Cipher.DECRYPT_MODE:
 202         case Cipher.UNWRAP_MODE:
 203             paddingLength = 0; // reset
 204             encrypt = false;
 205             break;
 206         default:
 207             throw new InvalidKeyException("Unknown mode: " + opmode);
 208         }
 209 
 210         if (!(key instanceof sun.security.mscapi.Key)) {
 211             if (key instanceof java.security.interfaces.RSAPublicKey) {
 212                 java.security.interfaces.RSAPublicKey rsaKey =
 213                     (java.security.interfaces.RSAPublicKey) key;
 214 
 215                 // Convert key to MSCAPI format
 216 
 217                 BigInteger modulus = rsaKey.getModulus();
 218                 BigInteger exponent =  rsaKey.getPublicExponent();
 219 
 220                 // Check against the local and global values to make sure
 221                 // the sizes are ok.  Round up to the nearest byte.
 222                 RSAKeyFactory.checkKeyLengths(((modulus.bitLength() + 7) & ~7),
 223                     exponent, -1, RSAKeyPairGenerator.KEY_SIZE_MAX);
 224 
 225                 byte[] modulusBytes = modulus.toByteArray();
 226                 byte[] exponentBytes = exponent.toByteArray();
 227 
 228                 // Adjust key length due to sign bit
 229                 int keyBitLength = (modulusBytes[0] == 0)
 230                     ? (modulusBytes.length - 1) * 8
 231                     : modulusBytes.length * 8;
 232 
 233                 byte[] keyBlob = RSASignature.generatePublicKeyBlob(
 234                     keyBitLength, modulusBytes, exponentBytes);
 235 
 236                 try {
 237                     key = RSASignature.importPublicKey(keyBlob, keyBitLength);
 238 
 239                 } catch (KeyStoreException e) {
 240                     throw new InvalidKeyException(e);
 241                 }
 242 
 243             } else {
 244                 throw new InvalidKeyException("Unsupported key type: " + key);
 245             }
 246         }
 247 
 248         if (key instanceof PublicKey) {
 249             mode = encrypt ? MODE_ENCRYPT : MODE_VERIFY;
 250             publicKey = (sun.security.mscapi.Key)key;
 251             privateKey = null;
 252             outputSize = publicKey.length() / 8;
 253         } else if (key instanceof PrivateKey) {
 254             mode = encrypt ? MODE_SIGN : MODE_DECRYPT;
 255             privateKey = (sun.security.mscapi.Key)key;
 256             publicKey = null;
 257             outputSize = privateKey.length() / 8;
 258         } else {
 259             throw new InvalidKeyException("Unknown key type: " + key);
 260         }
 261 
 262         bufOfs = 0;
 263         buffer = new byte[outputSize];
 264     }
 265 
 266     // internal update method
 267     private void update(byte[] in, int inOfs, int inLen) {
 268         if ((inLen == 0) || (in == null)) {
 269             return;
 270         }
 271         if (bufOfs + inLen > (buffer.length - paddingLength)) {
 272             bufOfs = buffer.length + 1;
 273             return;
 274         }
 275         System.arraycopy(in, inOfs, buffer, bufOfs, inLen);
 276         bufOfs += inLen;
 277     }
 278 
 279     // internal doFinal() method. Here we perform the actual RSA operation
 280     private byte[] doFinal() throws BadPaddingException,
 281             IllegalBlockSizeException {
 282         if (bufOfs > buffer.length) {
 283             throw new IllegalBlockSizeException("Data must not be longer "
 284                 + "than " + (buffer.length - paddingLength)  + " bytes");
 285         }
 286 
 287         try {
 288             byte[] data = buffer;
 289             switch (mode) {
 290             case MODE_SIGN:
 291                 return encryptDecrypt(data, bufOfs,
 292                     privateKey.getHCryptKey(), true);
 293 
 294             case MODE_VERIFY:
 295                 return encryptDecrypt(data, bufOfs,
 296                     publicKey.getHCryptKey(), false);
 297 
 298             case MODE_ENCRYPT:
 299                 return encryptDecrypt(data, bufOfs,
 300                     publicKey.getHCryptKey(), true);
 301 
 302             case MODE_DECRYPT:
 303                 return encryptDecrypt(data, bufOfs,
 304                     privateKey.getHCryptKey(), false);
 305 
 306             default:
 307                 throw new AssertionError("Internal error");
 308             }
 309 
 310         } catch (KeyException e) {
 311             throw new ProviderException(e);
 312 
 313         } finally {
 314             bufOfs = 0;
 315         }
 316     }
 317 
 318     // see JCE spec
 319     protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) {
 320         update(in, inOfs, inLen);
 321         return B0;
 322     }
 323 
 324     // see JCE spec
 325     protected int engineUpdate(byte[] in, int inOfs, int inLen, byte[] out,
 326             int outOfs) {
 327         update(in, inOfs, inLen);
 328         return 0;
 329     }
 330 
 331     // see JCE spec
 332     protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen)
 333             throws BadPaddingException, IllegalBlockSizeException {
 334         update(in, inOfs, inLen);
 335         return doFinal();
 336     }
 337 
 338     // see JCE spec
 339     protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out,
 340             int outOfs) throws ShortBufferException, BadPaddingException,
 341             IllegalBlockSizeException {
 342         if (outputSize > out.length - outOfs) {
 343             throw new ShortBufferException
 344                 ("Need " + outputSize + " bytes for output");
 345         }
 346         update(in, inOfs, inLen);
 347         byte[] result = doFinal();
 348         int n = result.length;
 349         System.arraycopy(result, 0, out, outOfs, n);
 350         return n;
 351     }
 352 
 353     // see JCE spec
 354     protected byte[] engineWrap(Key key) throws InvalidKeyException,
 355             IllegalBlockSizeException {
 356         byte[] encoded = key.getEncoded(); // TODO - unextractable key
 357         if ((encoded == null) || (encoded.length == 0)) {
 358             throw new InvalidKeyException("Could not obtain encoded key");
 359         }
 360         if (encoded.length > buffer.length) {
 361             throw new InvalidKeyException("Key is too long for wrapping");
 362         }
 363         update(encoded, 0, encoded.length);
 364         try {
 365             return doFinal();
 366         } catch (BadPaddingException e) {
 367             // should not occur
 368             throw new InvalidKeyException("Wrapping failed", e);
 369         }
 370     }
 371 
 372     // see JCE spec
 373     @SuppressWarnings("deprecation")
 374     protected java.security.Key engineUnwrap(byte[] wrappedKey,
 375             String algorithm,
 376             int type) throws InvalidKeyException, NoSuchAlgorithmException {
 377 
 378         if (wrappedKey.length > buffer.length) {
 379             throw new InvalidKeyException("Key is too long for unwrapping");
 380         }
 381 
 382         boolean isTlsRsaPremasterSecret =
 383                 algorithm.equals("TlsRsaPremasterSecret");
 384         Exception failover = null;
 385         byte[] encoded = null;
 386 
 387         update(wrappedKey, 0, wrappedKey.length);
 388         try {
 389             encoded = doFinal();
 390         } catch (BadPaddingException e) {
 391             if (isTlsRsaPremasterSecret) {
 392                 failover = e;
 393             } else {
 394                 throw new InvalidKeyException("Unwrapping failed", e);
 395             }
 396         } catch (IllegalBlockSizeException e) {
 397             // should not occur, handled with length check above
 398             throw new InvalidKeyException("Unwrapping failed", e);
 399         }
 400 
 401         if (isTlsRsaPremasterSecret) {
 402             if (!(spec instanceof TlsRsaPremasterSecretParameterSpec)) {
 403                 throw new IllegalStateException(
 404                         "No TlsRsaPremasterSecretParameterSpec specified");
 405             }
 406 
 407             // polish the TLS premaster secret
 408             encoded = KeyUtil.checkTlsPreMasterSecretKey(
 409                 ((TlsRsaPremasterSecretParameterSpec)spec).getClientVersion(),
 410                 ((TlsRsaPremasterSecretParameterSpec)spec).getServerVersion(),
 411                 random, encoded, (failover != null));
 412         }
 413 
 414         return constructKey(encoded, algorithm, type);
 415     }
 416 
 417     // see JCE spec
 418     protected int engineGetKeySize(Key key) throws InvalidKeyException {
 419 
 420         if (key instanceof sun.security.mscapi.Key) {
 421             return ((sun.security.mscapi.Key) key).length();
 422 
 423         } else if (key instanceof RSAKey) {
 424             return ((RSAKey) key).getModulus().bitLength();
 425 
 426         } else {
 427             throw new InvalidKeyException("Unsupported key type: " + key);
 428         }
 429     }
 430 
 431     // Construct an X.509 encoded public key.
 432     private static PublicKey constructPublicKey(byte[] encodedKey,
 433         String encodedKeyAlgorithm)
 434             throws InvalidKeyException, NoSuchAlgorithmException {
 435 
 436         try {
 437             KeyFactory keyFactory = KeyFactory.getInstance(encodedKeyAlgorithm);
 438             X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedKey);
 439 
 440             return keyFactory.generatePublic(keySpec);
 441 
 442         } catch (NoSuchAlgorithmException nsae) {
 443             throw new NoSuchAlgorithmException("No installed provider " +
 444                 "supports the " + encodedKeyAlgorithm + " algorithm", nsae);
 445 
 446         } catch (InvalidKeySpecException ike) {
 447             throw new InvalidKeyException("Cannot construct public key", ike);
 448         }
 449     }
 450 
 451     // Construct a PKCS #8 encoded private key.
 452     private static PrivateKey constructPrivateKey(byte[] encodedKey,
 453         String encodedKeyAlgorithm)
 454             throws InvalidKeyException, NoSuchAlgorithmException {
 455 
 456         try {
 457             KeyFactory keyFactory = KeyFactory.getInstance(encodedKeyAlgorithm);
 458             PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedKey);
 459 
 460             return keyFactory.generatePrivate(keySpec);
 461 
 462         } catch (NoSuchAlgorithmException nsae) {
 463             throw new NoSuchAlgorithmException("No installed provider " +
 464                 "supports the " + encodedKeyAlgorithm + " algorithm", nsae);
 465 
 466         } catch (InvalidKeySpecException ike) {
 467             throw new InvalidKeyException("Cannot construct private key", ike);
 468         }
 469     }
 470 
 471     // Construct an encoded secret key.
 472     private static SecretKey constructSecretKey(byte[] encodedKey,
 473         String encodedKeyAlgorithm) {
 474 
 475         return new SecretKeySpec(encodedKey, encodedKeyAlgorithm);
 476     }
 477 
 478     private static Key constructKey(byte[] encodedKey,
 479             String encodedKeyAlgorithm,
 480             int keyType) throws InvalidKeyException, NoSuchAlgorithmException {
 481 
 482         switch (keyType) {
 483             case Cipher.PUBLIC_KEY:
 484                 return constructPublicKey(encodedKey, encodedKeyAlgorithm);
 485             case Cipher.PRIVATE_KEY:
 486                 return constructPrivateKey(encodedKey, encodedKeyAlgorithm);
 487             case Cipher.SECRET_KEY:
 488                 return constructSecretKey(encodedKey, encodedKeyAlgorithm);
 489             default:
 490                 throw new InvalidKeyException("Unknown key type " + keyType);
 491         }
 492     }
 493 
 494     /*
 495      * Encrypt/decrypt a data buffer using Microsoft Crypto API with HCRYPTKEY.
 496      * It expects and returns ciphertext data in big-endian form.
 497      */
 498     private native static byte[] encryptDecrypt(byte[] data, int dataSize,
 499         long hCryptKey, boolean doEncrypt) throws KeyException;
 500 
 501 }