1/* 2 * Copyright (c) 2003, 2015, 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 26package com.sun.crypto.provider; 27 28import java.util.Locale; 29 30import java.security.*; 31import java.security.interfaces.*; 32import java.security.spec.AlgorithmParameterSpec; 33import java.security.spec.InvalidParameterSpecException; 34import java.security.spec.MGF1ParameterSpec; 35 36import javax.crypto.*; 37import javax.crypto.spec.PSource; 38import javax.crypto.spec.OAEPParameterSpec; 39 40import sun.security.rsa.*; 41import sun.security.jca.Providers; 42import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec; 43import sun.security.util.KeyUtil; 44 45/** 46 * RSA cipher implementation. Supports RSA en/decryption and signing/verifying 47 * using PKCS#1 v1.5 padding and without padding (raw RSA). Note that raw RSA 48 * is supported mostly for completeness and should only be used in rare cases. 49 * 50 * Objects should be instantiated by calling Cipher.getInstance() using the 51 * following algorithm names: 52 * . "RSA/ECB/PKCS1Padding" (or "RSA") for PKCS#1 padding. The mode (blocktype) 53 * is selected based on the en/decryption mode and public/private key used 54 * . "RSA/ECB/NoPadding" for rsa RSA. 55 * 56 * We only do one RSA operation per doFinal() call. If the application passes 57 * more data via calls to update() or doFinal(), we throw an 58 * IllegalBlockSizeException when doFinal() is called (see JCE API spec). 59 * Bulk encryption using RSA does not make sense and is not standardized. 60 * 61 * Note: RSA keys should be at least 512 bits long 62 * 63 * @since 1.5 64 * @author Andreas Sterbenz 65 */ 66public final class RSACipher extends CipherSpi { 67 68 // constant for an empty byte array 69 private static final byte[] B0 = new byte[0]; 70 71 // mode constant for public key encryption 72 private static final int MODE_ENCRYPT = 1; 73 // mode constant for private key decryption 74 private static final int MODE_DECRYPT = 2; 75 // mode constant for private key encryption (signing) 76 private static final int MODE_SIGN = 3; 77 // mode constant for public key decryption (verifying) 78 private static final int MODE_VERIFY = 4; 79 80 // constant for raw RSA 81 private static final String PAD_NONE = "NoPadding"; 82 // constant for PKCS#1 v1.5 RSA 83 private static final String PAD_PKCS1 = "PKCS1Padding"; 84 // constant for PKCS#2 v2.0 OAEP with MGF1 85 private static final String PAD_OAEP_MGF1 = "OAEP"; 86 87 // current mode, one of MODE_* above. Set when init() is called 88 private int mode; 89 90 // active padding type, one of PAD_* above. Set by setPadding() 91 private String paddingType; 92 93 // padding object 94 private RSAPadding padding; 95 96 // cipher parameter for OAEP padding and TLS RSA premaster secret 97 private AlgorithmParameterSpec spec = null; 98 99 // buffer for the data 100 private byte[] buffer; 101 // offset into the buffer (number of bytes buffered) 102 private int bufOfs; 103 104 // size of the output 105 private int outputSize; 106 107 // the public key, if we were initialized using a public key 108 private RSAPublicKey publicKey; 109 // the private key, if we were initialized using a private key 110 private RSAPrivateKey privateKey; 111 112 // hash algorithm for OAEP 113 private String oaepHashAlgorithm = "SHA-1"; 114 115 // the source of randomness 116 private SecureRandom random; 117 118 public RSACipher() { 119 paddingType = PAD_PKCS1; 120 } 121 122 // modes do not make sense for RSA, but allow ECB 123 // see JCE spec 124 protected void engineSetMode(String mode) throws NoSuchAlgorithmException { 125 if (mode.equalsIgnoreCase("ECB") == false) { 126 throw new NoSuchAlgorithmException("Unsupported mode " + mode); 127 } 128 } 129 130 // set the padding type 131 // see JCE spec 132 protected void engineSetPadding(String paddingName) 133 throws NoSuchPaddingException { 134 if (paddingName.equalsIgnoreCase(PAD_NONE)) { 135 paddingType = PAD_NONE; 136 } else if (paddingName.equalsIgnoreCase(PAD_PKCS1)) { 137 paddingType = PAD_PKCS1; 138 } else { 139 String lowerPadding = paddingName.toLowerCase(Locale.ENGLISH); 140 if (lowerPadding.equals("oaeppadding")) { 141 paddingType = PAD_OAEP_MGF1; 142 } else if (lowerPadding.startsWith("oaepwith") && 143 lowerPadding.endsWith("andmgf1padding")) { 144 paddingType = PAD_OAEP_MGF1; 145 // "oaepwith".length() == 8 146 // "andmgf1padding".length() == 14 147 oaepHashAlgorithm = 148 paddingName.substring(8, paddingName.length() - 14); 149 // check if MessageDigest appears to be available 150 // avoid getInstance() call here 151 if (Providers.getProviderList().getService 152 ("MessageDigest", oaepHashAlgorithm) == null) { 153 throw new NoSuchPaddingException 154 ("MessageDigest not available for " + paddingName); 155 } 156 } else { 157 throw new NoSuchPaddingException 158 ("Padding " + paddingName + " not supported"); 159 } 160 } 161 } 162 163 // return 0 as block size, we are not a block cipher 164 // see JCE spec 165 protected int engineGetBlockSize() { 166 return 0; 167 } 168 169 // return the output size 170 // see JCE spec 171 protected int engineGetOutputSize(int inputLen) { 172 return outputSize; 173 } 174 175 // no iv, return null 176 // see JCE spec 177 protected byte[] engineGetIV() { 178 return null; 179 } 180 181 // see JCE spec 182 protected AlgorithmParameters engineGetParameters() { 183 if (spec != null && spec instanceof OAEPParameterSpec) { 184 try { 185 AlgorithmParameters params = 186 AlgorithmParameters.getInstance("OAEP", 187 SunJCE.getInstance()); 188 params.init(spec); 189 return params; 190 } catch (NoSuchAlgorithmException nsae) { 191 // should never happen 192 throw new RuntimeException("Cannot find OAEP " + 193 " AlgorithmParameters implementation in SunJCE provider"); 194 } catch (InvalidParameterSpecException ipse) { 195 // should never happen 196 throw new RuntimeException("OAEPParameterSpec not supported"); 197 } 198 } else { 199 return null; 200 } 201 } 202 203 // see JCE spec 204 protected void engineInit(int opmode, Key key, SecureRandom random) 205 throws InvalidKeyException { 206 try { 207 init(opmode, key, random, null); 208 } catch (InvalidAlgorithmParameterException iape) { 209 // never thrown when null parameters are used; 210 // but re-throw it just in case 211 InvalidKeyException ike = 212 new InvalidKeyException("Wrong parameters"); 213 ike.initCause(iape); 214 throw ike; 215 } 216 } 217 218 // see JCE spec 219 protected void engineInit(int opmode, Key key, 220 AlgorithmParameterSpec params, SecureRandom random) 221 throws InvalidKeyException, InvalidAlgorithmParameterException { 222 init(opmode, key, random, params); 223 } 224 225 // see JCE spec 226 protected void engineInit(int opmode, Key key, 227 AlgorithmParameters params, SecureRandom random) 228 throws InvalidKeyException, InvalidAlgorithmParameterException { 229 if (params == null) { 230 init(opmode, key, random, null); 231 } else { 232 try { 233 OAEPParameterSpec spec = 234 params.getParameterSpec(OAEPParameterSpec.class); 235 init(opmode, key, random, spec); 236 } catch (InvalidParameterSpecException ipse) { 237 InvalidAlgorithmParameterException iape = 238 new InvalidAlgorithmParameterException("Wrong parameter"); 239 iape.initCause(ipse); 240 throw iape; 241 } 242 } 243 } 244 245 // initialize this cipher 246 @SuppressWarnings("deprecation") 247 private void init(int opmode, Key key, SecureRandom random, 248 AlgorithmParameterSpec params) 249 throws InvalidKeyException, InvalidAlgorithmParameterException { 250 boolean encrypt; 251 switch (opmode) { 252 case Cipher.ENCRYPT_MODE: 253 case Cipher.WRAP_MODE: 254 encrypt = true; 255 break; 256 case Cipher.DECRYPT_MODE: 257 case Cipher.UNWRAP_MODE: 258 encrypt = false; 259 break; 260 default: 261 throw new InvalidKeyException("Unknown mode: " + opmode); 262 } 263 RSAKey rsaKey = RSAKeyFactory.toRSAKey(key); 264 if (key instanceof RSAPublicKey) { 265 mode = encrypt ? MODE_ENCRYPT : MODE_VERIFY; 266 publicKey = (RSAPublicKey)key; 267 privateKey = null; 268 } else { // must be RSAPrivateKey per check in toRSAKey 269 mode = encrypt ? MODE_SIGN : MODE_DECRYPT; 270 privateKey = (RSAPrivateKey)key; 271 publicKey = null; 272 } 273 int n = RSACore.getByteLength(rsaKey.getModulus()); 274 outputSize = n; 275 bufOfs = 0; 276 if (paddingType == PAD_NONE) { 277 if (params != null) { 278 throw new InvalidAlgorithmParameterException 279 ("Parameters not supported"); 280 } 281 padding = RSAPadding.getInstance(RSAPadding.PAD_NONE, n, random); 282 buffer = new byte[n]; 283 } else if (paddingType == PAD_PKCS1) { 284 if (params != null) { 285 if (!(params instanceof TlsRsaPremasterSecretParameterSpec)) { 286 throw new InvalidAlgorithmParameterException( 287 "Parameters not supported"); 288 } 289 290 spec = params; 291 this.random = random; // for TLS RSA premaster secret 292 } 293 int blockType = (mode <= MODE_DECRYPT) ? RSAPadding.PAD_BLOCKTYPE_2 294 : RSAPadding.PAD_BLOCKTYPE_1; 295 padding = RSAPadding.getInstance(blockType, n, random); 296 if (encrypt) { 297 int k = padding.getMaxDataSize(); 298 buffer = new byte[k]; 299 } else { 300 buffer = new byte[n]; 301 } 302 } else { // PAD_OAEP_MGF1 303 if ((mode == MODE_SIGN) || (mode == MODE_VERIFY)) { 304 throw new InvalidKeyException 305 ("OAEP cannot be used to sign or verify signatures"); 306 } 307 if (params != null) { 308 if (!(params instanceof OAEPParameterSpec)) { 309 throw new InvalidAlgorithmParameterException 310 ("Wrong Parameters for OAEP Padding"); 311 } 312 spec = params; 313 } else { 314 spec = new OAEPParameterSpec(oaepHashAlgorithm, "MGF1", 315 MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT); 316 } 317 padding = RSAPadding.getInstance(RSAPadding.PAD_OAEP_MGF1, n, 318 random, (OAEPParameterSpec)spec); 319 if (encrypt) { 320 int k = padding.getMaxDataSize(); 321 buffer = new byte[k]; 322 } else { 323 buffer = new byte[n]; 324 } 325 } 326 } 327 328 // internal update method 329 private void update(byte[] in, int inOfs, int inLen) { 330 if ((inLen == 0) || (in == null)) { 331 return; 332 } 333 if (bufOfs + inLen > buffer.length) { 334 bufOfs = buffer.length + 1; 335 return; 336 } 337 System.arraycopy(in, inOfs, buffer, bufOfs, inLen); 338 bufOfs += inLen; 339 } 340 341 // internal doFinal() method. Here we perform the actual RSA operation 342 private byte[] doFinal() throws BadPaddingException, 343 IllegalBlockSizeException { 344 if (bufOfs > buffer.length) { 345 throw new IllegalBlockSizeException("Data must not be longer " 346 + "than " + buffer.length + " bytes"); 347 } 348 try { 349 byte[] data; 350 switch (mode) { 351 case MODE_SIGN: 352 data = padding.pad(buffer, 0, bufOfs); 353 return RSACore.rsa(data, privateKey, true); 354 case MODE_VERIFY: 355 byte[] verifyBuffer = RSACore.convert(buffer, 0, bufOfs); 356 data = RSACore.rsa(verifyBuffer, publicKey); 357 return padding.unpad(data); 358 case MODE_ENCRYPT: 359 data = padding.pad(buffer, 0, bufOfs); 360 return RSACore.rsa(data, publicKey); 361 case MODE_DECRYPT: 362 byte[] decryptBuffer = RSACore.convert(buffer, 0, bufOfs); 363 data = RSACore.rsa(decryptBuffer, privateKey, false); 364 return padding.unpad(data); 365 default: 366 throw new AssertionError("Internal error"); 367 } 368 } finally { 369 bufOfs = 0; 370 } 371 } 372 373 // see JCE spec 374 protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) { 375 update(in, inOfs, inLen); 376 return B0; 377 } 378 379 // see JCE spec 380 protected int engineUpdate(byte[] in, int inOfs, int inLen, byte[] out, 381 int outOfs) { 382 update(in, inOfs, inLen); 383 return 0; 384 } 385 386 // see JCE spec 387 protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen) 388 throws BadPaddingException, IllegalBlockSizeException { 389 update(in, inOfs, inLen); 390 return doFinal(); 391 } 392 393 // see JCE spec 394 protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out, 395 int outOfs) throws ShortBufferException, BadPaddingException, 396 IllegalBlockSizeException { 397 if (outputSize > out.length - outOfs) { 398 throw new ShortBufferException 399 ("Need " + outputSize + " bytes for output"); 400 } 401 update(in, inOfs, inLen); 402 byte[] result = doFinal(); 403 int n = result.length; 404 System.arraycopy(result, 0, out, outOfs, n); 405 return n; 406 } 407 408 // see JCE spec 409 protected byte[] engineWrap(Key key) throws InvalidKeyException, 410 IllegalBlockSizeException { 411 byte[] encoded = key.getEncoded(); 412 if ((encoded == null) || (encoded.length == 0)) { 413 throw new InvalidKeyException("Could not obtain encoded key"); 414 } 415 if (encoded.length > buffer.length) { 416 throw new InvalidKeyException("Key is too long for wrapping"); 417 } 418 update(encoded, 0, encoded.length); 419 try { 420 return doFinal(); 421 } catch (BadPaddingException e) { 422 // should not occur 423 throw new InvalidKeyException("Wrapping failed", e); 424 } 425 } 426 427 // see JCE spec 428 @SuppressWarnings("deprecation") 429 protected Key engineUnwrap(byte[] wrappedKey, String algorithm, 430 int type) throws InvalidKeyException, NoSuchAlgorithmException { 431 if (wrappedKey.length > buffer.length) { 432 throw new InvalidKeyException("Key is too long for unwrapping"); 433 } 434 435 boolean isTlsRsaPremasterSecret = 436 algorithm.equals("TlsRsaPremasterSecret"); 437 Exception failover = null; 438 byte[] encoded = null; 439 440 update(wrappedKey, 0, wrappedKey.length); 441 try { 442 encoded = doFinal(); 443 } catch (BadPaddingException e) { 444 if (isTlsRsaPremasterSecret) { 445 failover = e; 446 } else { 447 throw new InvalidKeyException("Unwrapping failed", e); 448 } 449 } catch (IllegalBlockSizeException e) { 450 // should not occur, handled with length check above 451 throw new InvalidKeyException("Unwrapping failed", e); 452 } 453 454 if (isTlsRsaPremasterSecret) { 455 if (!(spec instanceof TlsRsaPremasterSecretParameterSpec)) { 456 throw new IllegalStateException( 457 "No TlsRsaPremasterSecretParameterSpec specified"); 458 } 459 460 // polish the TLS premaster secret 461 encoded = KeyUtil.checkTlsPreMasterSecretKey( 462 ((TlsRsaPremasterSecretParameterSpec)spec).getClientVersion(), 463 ((TlsRsaPremasterSecretParameterSpec)spec).getServerVersion(), 464 random, encoded, (failover != null)); 465 } 466 467 return ConstructKeys.constructKey(encoded, algorithm, type); 468 } 469 470 // see JCE spec 471 protected int engineGetKeySize(Key key) throws InvalidKeyException { 472 RSAKey rsaKey = RSAKeyFactory.toRSAKey(key); 473 return rsaKey.getModulus().bitLength(); 474 } 475} 476