src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/RSACipher.java
changeset 53333 fd6de53a0d6e
parent 53332 ab474ef0a0ac
parent 53010 086dfcfc3731
child 53334 b94283cb226b
equal deleted inserted replaced
53332:ab474ef0a0ac 53333:fd6de53a0d6e
     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 }