1 /*
   2  * Copyright (c) 2005, 2012, 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     protected void engineInit(int opmode, Key key,
 163             AlgorithmParameterSpec params, SecureRandom random)
 164             throws InvalidKeyException, InvalidAlgorithmParameterException {
 165 
 166         if (params != null) {
 167             if (!(params instanceof TlsRsaPremasterSecretParameterSpec)) {
 168                 throw new InvalidAlgorithmParameterException(
 169                         "Parameters not supported");
 170             }
 171             spec = params;
 172             this.random = random;   // for TLS RSA premaster secret
 173         }
 174         init(opmode, key);
 175     }
 176 
 177     // see JCE spec
 178     protected void engineInit(int opmode, Key key,
 179             AlgorithmParameters params, SecureRandom random)
 180             throws InvalidKeyException, InvalidAlgorithmParameterException {
 181 
 182         if (params != null) {
 183             throw new InvalidAlgorithmParameterException
 184                 ("Parameters not supported");
 185         }
 186         init(opmode, key);
 187     }
 188 
 189     // initialize this cipher
 190     private void init(int opmode, Key key) throws InvalidKeyException {
 191 
 192         boolean encrypt;
 193 
 194         switch (opmode) {
 195         case Cipher.ENCRYPT_MODE:
 196         case Cipher.WRAP_MODE:
 197             paddingLength = PAD_PKCS1_LENGTH;
 198             encrypt = true;
 199             break;
 200         case Cipher.DECRYPT_MODE:
 201         case Cipher.UNWRAP_MODE:
 202             paddingLength = 0; // reset
 203             encrypt = false;
 204             break;
 205         default:
 206             throw new InvalidKeyException("Unknown mode: " + opmode);
 207         }
 208 
 209         if (!(key instanceof sun.security.mscapi.Key)) {
 210             if (key instanceof java.security.interfaces.RSAPublicKey) {
 211                 java.security.interfaces.RSAPublicKey rsaKey =
 212                     (java.security.interfaces.RSAPublicKey) key;
 213 
 214                 // Convert key to MSCAPI format
 215 
 216                 BigInteger modulus = rsaKey.getModulus();
 217                 BigInteger exponent =  rsaKey.getPublicExponent();
 218 
 219                 // Check against the local and global values to make sure
 220                 // the sizes are ok.  Round up to the nearest byte.
 221                 RSAKeyFactory.checkKeyLengths(((modulus.bitLength() + 7) & ~7),
 222                     exponent, -1, RSAKeyPairGenerator.KEY_SIZE_MAX);
 223 
 224                 byte[] modulusBytes = modulus.toByteArray();
 225                 byte[] exponentBytes = exponent.toByteArray();
 226 
 227                 // Adjust key length due to sign bit
 228                 int keyBitLength = (modulusBytes[0] == 0)
 229                     ? (modulusBytes.length - 1) * 8
 230                     : modulusBytes.length * 8;
 231 
 232                 byte[] keyBlob = RSASignature.generatePublicKeyBlob(
 233                     keyBitLength, modulusBytes, exponentBytes);
 234 
 235                 try {
 236                     key = RSASignature.importPublicKey(keyBlob, keyBitLength);
 237 
 238                 } catch (KeyStoreException e) {
 239                     throw new InvalidKeyException(e);
 240                 }
 241 
 242             } else {
 243                 throw new InvalidKeyException("Unsupported key type: " + key);
 244             }
 245         }
 246 
 247         if (key instanceof PublicKey) {
 248             mode = encrypt ? MODE_ENCRYPT : MODE_VERIFY;
 249             publicKey = (sun.security.mscapi.Key)key;
 250             privateKey = null;
 251             outputSize = publicKey.length() / 8;
 252         } else if (key instanceof PrivateKey) {
 253             mode = encrypt ? MODE_SIGN : MODE_DECRYPT;
 254             privateKey = (sun.security.mscapi.Key)key;
 255             publicKey = null;
 256             outputSize = privateKey.length() / 8;
 257         } else {
 258             throw new InvalidKeyException("Unknown key type: " + key);
 259         }
 260 
 261         bufOfs = 0;
 262         buffer = new byte[outputSize];
 263     }
 264 
 265     // internal update method
 266     private void update(byte[] in, int inOfs, int inLen) {
 267         if ((inLen == 0) || (in == null)) {
 268             return;
 269         }
 270         if (bufOfs + inLen > (buffer.length - paddingLength)) {
 271             bufOfs = buffer.length + 1;
 272             return;
 273         }
 274         System.arraycopy(in, inOfs, buffer, bufOfs, inLen);
 275         bufOfs += inLen;
 276     }
 277 
 278     // internal doFinal() method. Here we perform the actual RSA operation
 279     private byte[] doFinal() throws BadPaddingException,
 280             IllegalBlockSizeException {
 281         if (bufOfs > buffer.length) {
 282             throw new IllegalBlockSizeException("Data must not be longer "
 283                 + "than " + (buffer.length - paddingLength)  + " bytes");
 284         }
 285 
 286         try {
 287             byte[] data = buffer;
 288             switch (mode) {
 289             case MODE_SIGN:
 290                 return encryptDecrypt(data, bufOfs,
 291                     privateKey.getHCryptKey(), true);
 292 
 293             case MODE_VERIFY:
 294                 return encryptDecrypt(data, bufOfs,
 295                     publicKey.getHCryptKey(), false);
 296 
 297             case MODE_ENCRYPT:
 298                 return encryptDecrypt(data, bufOfs,
 299                     publicKey.getHCryptKey(), true);
 300 
 301             case MODE_DECRYPT:
 302                 return encryptDecrypt(data, bufOfs,
 303                     privateKey.getHCryptKey(), false);
 304 
 305             default:
 306                 throw new AssertionError("Internal error");
 307             }
 308 
 309         } catch (KeyException e) {
 310             throw new ProviderException(e);
 311 
 312         } finally {
 313             bufOfs = 0;
 314         }
 315     }
 316 
 317     // see JCE spec
 318     protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) {
 319         update(in, inOfs, inLen);
 320         return B0;
 321     }
 322 
 323     // see JCE spec
 324     protected int engineUpdate(byte[] in, int inOfs, int inLen, byte[] out,
 325             int outOfs) {
 326         update(in, inOfs, inLen);
 327         return 0;
 328     }
 329 
 330     // see JCE spec
 331     protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen)
 332             throws BadPaddingException, IllegalBlockSizeException {
 333         update(in, inOfs, inLen);
 334         return doFinal();
 335     }
 336 
 337     // see JCE spec
 338     protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out,
 339             int outOfs) throws ShortBufferException, BadPaddingException,
 340             IllegalBlockSizeException {
 341         if (outputSize > out.length - outOfs) {
 342             throw new ShortBufferException
 343                 ("Need " + outputSize + " bytes for output");
 344         }
 345         update(in, inOfs, inLen);
 346         byte[] result = doFinal();
 347         int n = result.length;
 348         System.arraycopy(result, 0, out, outOfs, n);
 349         return n;
 350     }
 351 
 352     // see JCE spec
 353     protected byte[] engineWrap(Key key) throws InvalidKeyException,
 354             IllegalBlockSizeException {
 355         byte[] encoded = key.getEncoded(); // TODO - unextractable key
 356         if ((encoded == null) || (encoded.length == 0)) {
 357             throw new InvalidKeyException("Could not obtain encoded key");
 358         }
 359         if (encoded.length > buffer.length) {
 360             throw new InvalidKeyException("Key is too long for wrapping");
 361         }
 362         update(encoded, 0, encoded.length);
 363         try {
 364             return doFinal();
 365         } catch (BadPaddingException e) {
 366             // should not occur
 367             throw new InvalidKeyException("Wrapping failed", e);
 368         }
 369     }
 370 
 371     // see JCE spec
 372     protected java.security.Key engineUnwrap(byte[] wrappedKey,
 373             String algorithm,
 374             int type) throws InvalidKeyException, NoSuchAlgorithmException {
 375 
 376         if (wrappedKey.length > buffer.length) {
 377             throw new InvalidKeyException("Key is too long for unwrapping");
 378         }
 379 
 380         boolean isTlsRsaPremasterSecret =
 381                 algorithm.equals("TlsRsaPremasterSecret");
 382         Exception failover = null;
 383         byte[] encoded = null;
 384 
 385         update(wrappedKey, 0, wrappedKey.length);
 386         try {
 387             encoded = doFinal();
 388         } catch (BadPaddingException e) {
 389             if (isTlsRsaPremasterSecret) {
 390                 failover = e;
 391             } else {
 392                 throw new InvalidKeyException("Unwrapping failed", e);
 393             }
 394         } catch (IllegalBlockSizeException e) {
 395             // should not occur, handled with length check above
 396             throw new InvalidKeyException("Unwrapping failed", e);
 397         }
 398 
 399         if (isTlsRsaPremasterSecret) {
 400             if (!(spec instanceof TlsRsaPremasterSecretParameterSpec)) {
 401                 throw new IllegalStateException(
 402                         "No TlsRsaPremasterSecretParameterSpec specified");
 403             }
 404 
 405             // polish the TLS premaster secret
 406             encoded = KeyUtil.checkTlsPreMasterSecretKey(
 407                 ((TlsRsaPremasterSecretParameterSpec)spec).getClientVersion(),
 408                 ((TlsRsaPremasterSecretParameterSpec)spec).getServerVersion(),
 409                 random, encoded, (failover != null));
 410         }
 411 
 412         return constructKey(encoded, algorithm, type);
 413     }
 414 
 415     // see JCE spec
 416     protected int engineGetKeySize(Key key) throws InvalidKeyException {
 417 
 418         if (key instanceof sun.security.mscapi.Key) {
 419             return ((sun.security.mscapi.Key) key).length();
 420 
 421         } else if (key instanceof RSAKey) {
 422             return ((RSAKey) key).getModulus().bitLength();
 423 
 424         } else {
 425             throw new InvalidKeyException("Unsupported key type: " + key);
 426         }
 427     }
 428 
 429     // Construct an X.509 encoded public key.
 430     private static PublicKey constructPublicKey(byte[] encodedKey,
 431         String encodedKeyAlgorithm)
 432             throws InvalidKeyException, NoSuchAlgorithmException {
 433 
 434         try {
 435             KeyFactory keyFactory = KeyFactory.getInstance(encodedKeyAlgorithm);
 436             X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedKey);
 437 
 438             return keyFactory.generatePublic(keySpec);
 439 
 440         } catch (NoSuchAlgorithmException nsae) {
 441             throw new NoSuchAlgorithmException("No installed provider " +
 442                 "supports the " + encodedKeyAlgorithm + " algorithm", nsae);
 443 
 444         } catch (InvalidKeySpecException ike) {
 445             throw new InvalidKeyException("Cannot construct public key", ike);
 446         }
 447     }
 448 
 449     // Construct a PKCS #8 encoded private key.
 450     private static PrivateKey constructPrivateKey(byte[] encodedKey,
 451         String encodedKeyAlgorithm)
 452             throws InvalidKeyException, NoSuchAlgorithmException {
 453 
 454         try {
 455             KeyFactory keyFactory = KeyFactory.getInstance(encodedKeyAlgorithm);
 456             PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedKey);
 457 
 458             return keyFactory.generatePrivate(keySpec);
 459 
 460         } catch (NoSuchAlgorithmException nsae) {
 461             throw new NoSuchAlgorithmException("No installed provider " +
 462                 "supports the " + encodedKeyAlgorithm + " algorithm", nsae);
 463 
 464         } catch (InvalidKeySpecException ike) {
 465             throw new InvalidKeyException("Cannot construct private key", ike);
 466         }
 467     }
 468 
 469     // Construct an encoded secret key.
 470     private static SecretKey constructSecretKey(byte[] encodedKey,
 471         String encodedKeyAlgorithm) {
 472 
 473         return new SecretKeySpec(encodedKey, encodedKeyAlgorithm);
 474     }
 475 
 476     private static Key constructKey(byte[] encodedKey,
 477             String encodedKeyAlgorithm,
 478             int keyType) throws InvalidKeyException, NoSuchAlgorithmException {
 479 
 480         switch (keyType) {
 481             case Cipher.PUBLIC_KEY:
 482                 return constructPublicKey(encodedKey, encodedKeyAlgorithm);
 483             case Cipher.PRIVATE_KEY:
 484                 return constructPrivateKey(encodedKey, encodedKeyAlgorithm);
 485             case Cipher.SECRET_KEY:
 486                 return constructSecretKey(encodedKey, encodedKeyAlgorithm);
 487             default:
 488                 throw new InvalidKeyException("Unknown key type " + keyType);
 489         }
 490     }
 491 
 492     /*
 493      * Encrypt/decrypt a data buffer using Microsoft Crypto API with HCRYPTKEY.
 494      * It expects and returns ciphertext data in big-endian form.
 495      */
 496     private native static byte[] encryptDecrypt(byte[] data, int dataSize,
 497         long hCryptKey, boolean doEncrypt) throws KeyException;
 498 
 499 }