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 }