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 }