/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* RSA cipher implementation. Supports RSA en/decryption and signing/verifying
* using PKCS#1 v1.5 padding and without padding (raw RSA). Note that raw RSA
* is supported mostly for completeness and should only be used in rare cases.
*
* Objects should be instantiated by calling Cipher.getInstance() using the
* following algorithm names:
* . "RSA/ECB/PKCS1Padding" (or "RSA") for PKCS#1 padding. The mode (blocktype)
* is selected based on the en/decryption mode and public/private key used
*
* We only do one RSA operation per doFinal() call. If the application passes
* more data via calls to update() or doFinal(), we throw an
* IllegalBlockSizeException when doFinal() is called (see JCE API spec).
* Bulk encryption using RSA does not make sense and is not standardized.
*
* Note: RSA keys should be at least 512 bits long
*
* @since 1.5
* @author Andreas Sterbenz
*/
// constant for an empty byte array
// mode constant for public key encryption
// mode constant for private key decryption
// mode constant for private key encryption (signing)
// mode constant for public key decryption (verifying)
// constant for raw RSA
// constant for PKCS#1 v1.5 RSA
// constant for PKCS#2 v2.0 OAEP with MGF1
// current mode, one of MODE_* above. Set when init() is called
private int mode;
// active padding type, one of PAD_* above. Set by setPadding()
// padding object
// cipher parameter for OAEP padding
// buffer for the data
private byte[] buffer;
// offset into the buffer (number of bytes buffered)
private int bufOfs;
// size of the output
private int outputSize;
// the public key, if we were initialized using a public key
// the private key, if we were initialized using a private key
// hash algorithm for OAEP
public RSACipher() {
}
// modes do not make sense for RSA, but allow ECB
// see JCE spec
}
}
// set the padding type
// see JCE spec
throws NoSuchPaddingException {
} else {
// "oaepwith".length() == 8
// "andmgf1padding".length() == 14
// check if MessageDigest appears to be available
// avoid getInstance() call here
throw new NoSuchPaddingException
("MessageDigest not available for " + paddingName);
}
} else {
throw new NoSuchPaddingException
}
}
}
// return 0 as block size, we are not a block cipher
// see JCE spec
protected int engineGetBlockSize() {
return 0;
}
// return the output size
// see JCE spec
return outputSize;
}
// no iv, return null
// see JCE spec
protected byte[] engineGetIV() {
return null;
}
// see JCE spec
try {
return params;
} catch (NoSuchAlgorithmException nsae) {
// should never happen
throw new RuntimeException("Cannot find OAEP " +
" AlgorithmParameters implementation in SunJCE provider");
} catch (NoSuchProviderException nspe) {
// should never happen
throw new RuntimeException("Cannot find SunJCE provider");
} catch (InvalidParameterSpecException ipse) {
// should never happen
throw new RuntimeException("OAEPParameterSpec not supported");
}
} else {
return null;
}
}
// see JCE spec
throws InvalidKeyException {
try {
} catch (InvalidAlgorithmParameterException iape) {
// never thrown when null parameters are used;
// but re-throw it just in case
new InvalidKeyException("Wrong parameters");
throw ike;
}
}
// see JCE spec
}
// see JCE spec
} else {
try {
} catch (InvalidParameterSpecException ipse) {
new InvalidAlgorithmParameterException("Wrong parameter");
throw iape;
}
}
}
// initialize this cipher
boolean encrypt;
switch (opmode) {
case Cipher.ENCRYPT_MODE:
encrypt = true;
break;
case Cipher.DECRYPT_MODE:
case Cipher.UNWRAP_MODE:
encrypt = false;
break;
default:
}
if (key instanceof RSAPublicKey) {
privateKey = null;
} else { // must be RSAPrivateKey per check in toRSAKey
}
outputSize = n;
bufOfs = 0;
if (paddingType == PAD_NONE) {
throw new InvalidAlgorithmParameterException
("Parameters not supported");
}
buffer = new byte[n];
} else if (paddingType == PAD_PKCS1) {
throw new InvalidAlgorithmParameterException
("Parameters not supported");
}
if (encrypt) {
int k = padding.getMaxDataSize();
buffer = new byte[k];
} else {
buffer = new byte[n];
}
} else { // PAD_OAEP_MGF1
throw new InvalidKeyException
("OAEP cannot be used to sign or verify signatures");
}
if (!(params instanceof OAEPParameterSpec)) {
throw new InvalidAlgorithmParameterException
("Wrong Parameters for OAEP Padding");
}
} else {
}
if (encrypt) {
int k = padding.getMaxDataSize();
buffer = new byte[k];
} else {
buffer = new byte[n];
}
}
}
// internal update method
return;
}
return;
}
}
// internal doFinal() method. Here we perform the actual RSA operation
throw new IllegalBlockSizeException("Data must not be longer "
}
try {
byte[] data;
switch (mode) {
case MODE_SIGN:
case MODE_VERIFY:
case MODE_ENCRYPT:
case MODE_DECRYPT:
default:
throw new AssertionError("Internal error");
}
} finally {
bufOfs = 0;
}
}
// see JCE spec
return B0;
}
// see JCE spec
int outOfs) {
return 0;
}
// see JCE spec
throws BadPaddingException, IllegalBlockSizeException {
return doFinal();
}
// see JCE spec
throw new ShortBufferException
}
return n;
}
// see JCE spec
throw new InvalidKeyException("Could not obtain encoded key");
}
throw new InvalidKeyException("Key is too long for wrapping");
}
try {
return doFinal();
} catch (BadPaddingException e) {
// should not occur
throw new InvalidKeyException("Wrapping failed", e);
}
}
// see JCE spec
throw new InvalidKeyException("Key is too long for unwrapping");
}
try {
} catch (BadPaddingException e) {
// should not occur
throw new InvalidKeyException("Unwrapping failed", e);
} catch (IllegalBlockSizeException e) {
// should not occur, handled with length check above
throw new InvalidKeyException("Unwrapping failed", e);
}
}
// see JCE spec
}
}