/* * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * 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. */ package com.sun.crypto.provider; import java.util.Locale; import java.security.*;import java.security.interfaces.*;import java.security.spec.AlgorithmParameterSpec;import java.security.spec.InvalidParameterSpecException;import java.security.spec.MGF1ParameterSpec; import javax.crypto.*;import javax.crypto.spec.PSource;import javax.crypto.spec.OAEPParameterSpec; import sun.security.rsa.*;import sun.security.jca.Providers; /** * 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 * . "RSA/ECB/NoPadding" for rsa RSA. * * 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 */public final class RSACipher extends CipherSpi { // constant for an empty byte array private final static byte[] B0 = new byte[0]; // mode constant for public key encryption private final static int MODE_ENCRYPT = 1; // mode constant for private key decryption private final static int MODE_DECRYPT = 2; // mode constant for private key encryption (signing) private final static int MODE_SIGN = 3; // mode constant for public key decryption (verifying) private final static int MODE_VERIFY = 4; // constant for raw RSA private final static String PAD_NONE = "NoPadding"; // constant for PKCS#1 v1.5 RSA private final static String PAD_PKCS1 = "PKCS1Padding"; // constant for PKCS#2 v2.0 OAEP with MGF1 private final static String PAD_OAEP_MGF1 = "OAEP"; // current mode, one of MODE_* above. Set when init() is called private int mode; // active padding type, one of PAD_* above. Set by setPadding() private String paddingType; // padding object private RSAPadding padding; // cipher parameter for OAEP padding private OAEPParameterSpec spec = null; // 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 private RSAPublicKey publicKey; // the private key, if we were initialized using a private key private RSAPrivateKey privateKey; // hash algorithm for OAEP private String oaepHashAlgorithm = "SHA-1"; public RSACipher() { paddingType = PAD_PKCS1; } // modes do not make sense for RSA, but allow ECB // see JCE spec protected void engineSetMode(String mode) throws NoSuchAlgorithmException { if (mode.equalsIgnoreCase("ECB") == false) { throw new NoSuchAlgorithmException("Unsupported mode " + mode); } } // set the padding type // see JCE spec protected void engineSetPadding(String paddingName) throws NoSuchPaddingException { if (paddingName.equalsIgnoreCase(PAD_NONE)) { paddingType = PAD_NONE; } else if (paddingName.equalsIgnoreCase(PAD_PKCS1)) { paddingType = PAD_PKCS1; } else { String lowerPadding = paddingName.toLowerCase(Locale.ENGLISH); if (lowerPadding.equals("oaeppadding")) { paddingType = PAD_OAEP_MGF1; } else if (lowerPadding.startsWith("oaepwith") && lowerPadding.endsWith("andmgf1padding")) { paddingType = PAD_OAEP_MGF1; // "oaepwith".length() == 8 // "andmgf1padding".length() == 14 oaepHashAlgorithm = paddingName.substring(8, paddingName.length() - 14); // check if MessageDigest appears to be available // avoid getInstance() call here if (Providers.getProviderList().getService ("MessageDigest", oaepHashAlgorithm) == null) { throw new NoSuchPaddingException ("MessageDigest not available for " + paddingName); } } else { throw new NoSuchPaddingException ("Padding " + paddingName + " not supported"); } } } // 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 protected int engineGetOutputSize(int inputLen) { return outputSize; } // no iv, return null // see JCE spec protected byte[] engineGetIV() { return null; } // see JCE spec protected AlgorithmParameters engineGetParameters() { if (spec != null) { try { AlgorithmParameters params = AlgorithmParameters.getInstance("OAEP", "SunJCE"); params.init(spec); 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 protected void engineInit(int opmode, Key key, SecureRandom random) throws InvalidKeyException { try { init(opmode, key, random, null); } catch (InvalidAlgorithmParameterException iape) { // never thrown when null parameters are used; // but re-throw it just in case InvalidKeyException ike = new InvalidKeyException("Wrong parameters"); ike.initCause(iape); throw ike; } } // see JCE spec protected void engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { init(opmode, key, random, params); } // see JCE spec protected void engineInit(int opmode, Key key, AlgorithmParameters params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException { if (params == null) { init(opmode, key, random, null); } else { try { OAEPParameterSpec spec = (OAEPParameterSpec) params.getParameterSpec(OAEPParameterSpec.class); init(opmode, key, random, spec); } catch (InvalidParameterSpecException ipse) { InvalidAlgorithmParameterException iape = new InvalidAlgorithmParameterException("Wrong parameter"); iape.initCause(ipse); throw iape; } } } // initialize this cipher private void init(int opmode, Key key, SecureRandom random, AlgorithmParameterSpec params) throws InvalidKeyException, InvalidAlgorithmParameterException { boolean encrypt; switch (opmode) { case Cipher.ENCRYPT_MODE: case Cipher.WRAP_MODE: encrypt = true; break; case Cipher.DECRYPT_MODE: case Cipher.UNWRAP_MODE: encrypt = false; break; default: throw new InvalidKeyException("Unknown mode: " + opmode); } RSAKey rsaKey = RSAKeyFactory.toRSAKey(key); if (key instanceof RSAPublicKey) { mode = encrypt ? MODE_ENCRYPT : MODE_VERIFY; publicKey = (RSAPublicKey)key; privateKey = null; } else { // must be RSAPrivateKey per check in toRSAKey mode = encrypt ? MODE_SIGN : MODE_DECRYPT; privateKey = (RSAPrivateKey)key; publicKey = null; } int n = RSACore.getByteLength(rsaKey.getModulus()); outputSize = n; bufOfs = 0; if (paddingType == PAD_NONE) { if (params != null) { throw new InvalidAlgorithmParameterException ("Parameters not supported"); } padding = RSAPadding.getInstance(RSAPadding.PAD_NONE, n, random); buffer = new byte[n]; } else if (paddingType == PAD_PKCS1) { if (params != null) { throw new InvalidAlgorithmParameterException ("Parameters not supported"); } int blockType = (mode <= MODE_DECRYPT) ? RSAPadding.PAD_BLOCKTYPE_2 : RSAPadding.PAD_BLOCKTYPE_1; padding = RSAPadding.getInstance(blockType, n, random); if (encrypt) { int k = padding.getMaxDataSize(); buffer = new byte[k]; } else { buffer = new byte[n]; } } else { // PAD_OAEP_MGF1 if ((mode == MODE_SIGN) || (mode == MODE_VERIFY)) { throw new InvalidKeyException ("OAEP cannot be used to sign or verify signatures"); } OAEPParameterSpec myParams; if (params != null) { if (!(params instanceof OAEPParameterSpec)) { throw new InvalidAlgorithmParameterException ("Wrong Parameters for OAEP Padding"); } myParams = (OAEPParameterSpec) params; } else { myParams = new OAEPParameterSpec(oaepHashAlgorithm, "MGF1", MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT); } padding = RSAPadding.getInstance(RSAPadding.PAD_OAEP_MGF1, n, random, myParams); if (encrypt) { int k = padding.getMaxDataSize(); buffer = new byte[k]; } else { buffer = new byte[n]; } } } // internal update method private void update(byte[] in, int inOfs, int inLen) { if ((inLen == 0) || (in == null)) { return; } if (bufOfs + inLen > buffer.length) { bufOfs = buffer.length + 1; return; } System.arraycopy(in, inOfs, buffer, bufOfs, inLen); bufOfs += inLen; } // internal doFinal() method. Here we perform the actual RSA operation private byte[] doFinal() throws BadPaddingException, IllegalBlockSizeException { if (bufOfs > buffer.length) { throw new IllegalBlockSizeException("Data must not be longer " + "than " + buffer.length + " bytes"); } try { byte[] data; switch (mode) { case MODE_SIGN: data = padding.pad(buffer, 0, bufOfs); return RSACore.rsa(data, privateKey); case MODE_VERIFY: byte[] verifyBuffer = RSACore.convert(buffer, 0, bufOfs); data = RSACore.rsa(verifyBuffer, publicKey); return padding.unpad(data); case MODE_ENCRYPT: data = padding.pad(buffer, 0, bufOfs); return RSACore.rsa(data, publicKey); case MODE_DECRYPT: byte[] decryptBuffer = RSACore.convert(buffer, 0, bufOfs); data = RSACore.rsa(decryptBuffer, privateKey); return padding.unpad(data); default: throw new AssertionError("Internal error"); } } finally { bufOfs = 0; } } // see JCE spec protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) { update(in, inOfs, inLen); return B0; } // see JCE spec protected int engineUpdate(byte[] in, int inOfs, int inLen, byte[] out, int outOfs) { update(in, inOfs, inLen); return 0; } // see JCE spec protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen) throws BadPaddingException, IllegalBlockSizeException { update(in, inOfs, inLen); return doFinal(); } // see JCE spec protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out, int outOfs) throws ShortBufferException, BadPaddingException, IllegalBlockSizeException { if (outputSize > out.length - outOfs) { throw new ShortBufferException ("Need " + outputSize + " bytes for output"); } update(in, inOfs, inLen); byte[] result = doFinal(); int n = result.length; System.arraycopy(result, 0, out, outOfs, n); return n; } // see JCE spec protected byte[] engineWrap(Key key) throws InvalidKeyException, IllegalBlockSizeException { byte[] encoded = key.getEncoded(); if ((encoded == null) || (encoded.length == 0)) { throw new InvalidKeyException("Could not obtain encoded key"); } if (encoded.length > buffer.length) { throw new InvalidKeyException("Key is too long for wrapping"); } update(encoded, 0, encoded.length); try { return doFinal(); } catch (BadPaddingException e) { // should not occur throw new InvalidKeyException("Wrapping failed", e); } } // see JCE spec protected Key engineUnwrap(byte[] wrappedKey, String algorithm, int type) throws InvalidKeyException, NoSuchAlgorithmException { if (wrappedKey.length > buffer.length) { throw new InvalidKeyException("Key is too long for unwrapping"); } update(wrappedKey, 0, wrappedKey.length); try { byte[] encoded = doFinal(); return ConstructKeys.constructKey(encoded, algorithm, type); } 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 protected int engineGetKeySize(Key key) throws InvalidKeyException { RSAKey rsaKey = RSAKeyFactory.toRSAKey(key); return rsaKey.getModulus().bitLength(); } }
/*
* Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* 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.
*/
package com.sun.crypto.provider;
import java.util.Locale;
import java.security.*;
import java.security.interfaces.*;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.InvalidParameterSpecException;
import java.security.spec.MGF1ParameterSpec;
import javax.crypto.*;
import javax.crypto.spec.PSource;
import javax.crypto.spec.OAEPParameterSpec;
import sun.security.rsa.*;
import sun.security.jca.Providers;
/**
* 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
* . "RSA/ECB/NoPadding" for rsa RSA.
*
* 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
*/
public final class RSACipher extends CipherSpi {
// constant for an empty byte array
private final static byte[] B0 = new byte[0];
// mode constant for public key encryption
private final static int MODE_ENCRYPT = 1;
// mode constant for private key decryption
private final static int MODE_DECRYPT = 2;
// mode constant for private key encryption (signing)
private final static int MODE_SIGN = 3;
// mode constant for public key decryption (verifying)
private final static int MODE_VERIFY = 4;
// constant for raw RSA
private final static String PAD_NONE = "NoPadding";
// constant for PKCS#1 v1.5 RSA
private final static String PAD_PKCS1 = "PKCS1Padding";
// constant for PKCS#2 v2.0 OAEP with MGF1
private final static String PAD_OAEP_MGF1 = "OAEP";
// current mode, one of MODE_* above. Set when init() is called
private int mode;
// active padding type, one of PAD_* above. Set by setPadding()
private String paddingType;
// padding object
private RSAPadding padding;
// cipher parameter for OAEP padding
private OAEPParameterSpec spec = null;
// 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
private RSAPublicKey publicKey;
// the private key, if we were initialized using a private key
private RSAPrivateKey privateKey;
// hash algorithm for OAEP
private String oaepHashAlgorithm = "SHA-1";
public RSACipher() {
paddingType = PAD_PKCS1;
}
// modes do not make sense for RSA, but allow ECB
// see JCE spec
protected void engineSetMode(String mode) throws NoSuchAlgorithmException {
if (mode.equalsIgnoreCase("ECB") == false) {
throw new NoSuchAlgorithmException("Unsupported mode " + mode);
}
}
// set the padding type
// see JCE spec
protected void engineSetPadding(String paddingName)
throws NoSuchPaddingException {
if (paddingName.equalsIgnoreCase(PAD_NONE)) {
paddingType = PAD_NONE;
} else if (paddingName.equalsIgnoreCase(PAD_PKCS1)) {
paddingType = PAD_PKCS1;
} else {
String lowerPadding = paddingName.toLowerCase(Locale.ENGLISH);
if (lowerPadding.equals("oaeppadding")) {
paddingType = PAD_OAEP_MGF1;
} else if (lowerPadding.startsWith("oaepwith") &&
lowerPadding.endsWith("andmgf1padding")) {
paddingType = PAD_OAEP_MGF1;
// "oaepwith".length() == 8
// "andmgf1padding".length() == 14
oaepHashAlgorithm =
paddingName.substring(8, paddingName.length() - 14);
// check if MessageDigest appears to be available
// avoid getInstance() call here
if (Providers.getProviderList().getService
("MessageDigest", oaepHashAlgorithm) == null) {
throw new NoSuchPaddingException
("MessageDigest not available for " + paddingName);
}
} else {
throw new NoSuchPaddingException
("Padding " + paddingName + " not supported");
}
}
}
// 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
protected int engineGetOutputSize(int inputLen) {
return outputSize;
}
// no iv, return null
// see JCE spec
protected byte[] engineGetIV() {
return null;
}
// see JCE spec
protected AlgorithmParameters engineGetParameters() {
if (spec != null) {
try {
AlgorithmParameters params =
AlgorithmParameters.getInstance("OAEP", "SunJCE");
params.init(spec);
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
protected void engineInit(int opmode, Key key, SecureRandom random)
throws InvalidKeyException {
try {
init(opmode, key, random, null);
} catch (InvalidAlgorithmParameterException iape) {
// never thrown when null parameters are used;
// but re-throw it just in case
InvalidKeyException ike =
new InvalidKeyException("Wrong parameters");
ike.initCause(iape);
throw ike;
}
}
// see JCE spec
protected void engineInit(int opmode, Key key,
AlgorithmParameterSpec params, SecureRandom random)
throws InvalidKeyException, InvalidAlgorithmParameterException {
init(opmode, key, random, params);
}
// see JCE spec
protected void engineInit(int opmode, Key key,
AlgorithmParameters params, SecureRandom random)
throws InvalidKeyException, InvalidAlgorithmParameterException {
if (params == null) {
init(opmode, key, random, null);
} else {
try {
OAEPParameterSpec spec = (OAEPParameterSpec)
params.getParameterSpec(OAEPParameterSpec.class);
init(opmode, key, random, spec);
} catch (InvalidParameterSpecException ipse) {
InvalidAlgorithmParameterException iape =
new InvalidAlgorithmParameterException("Wrong parameter");
iape.initCause(ipse);
throw iape;
}
}
}
// initialize this cipher
private void init(int opmode, Key key, SecureRandom random,
AlgorithmParameterSpec params)
throws InvalidKeyException, InvalidAlgorithmParameterException {
boolean encrypt;
switch (opmode) {
case Cipher.ENCRYPT_MODE:
case Cipher.WRAP_MODE:
encrypt = true;
break;
case Cipher.DECRYPT_MODE:
case Cipher.UNWRAP_MODE:
encrypt = false;
break;
default:
throw new InvalidKeyException("Unknown mode: " + opmode);
}
RSAKey rsaKey = RSAKeyFactory.toRSAKey(key);
if (key instanceof RSAPublicKey) {
mode = encrypt ? MODE_ENCRYPT : MODE_VERIFY;
publicKey = (RSAPublicKey)key;
privateKey = null;
} else { // must be RSAPrivateKey per check in toRSAKey
mode = encrypt ? MODE_SIGN : MODE_DECRYPT;
privateKey = (RSAPrivateKey)key;
publicKey = null;
}
int n = RSACore.getByteLength(rsaKey.getModulus());
outputSize = n;
bufOfs = 0;
if (paddingType == PAD_NONE) {
if (params != null) {
throw new InvalidAlgorithmParameterException
("Parameters not supported");
}
padding = RSAPadding.getInstance(RSAPadding.PAD_NONE, n, random);
buffer = new byte[n];
} else if (paddingType == PAD_PKCS1) {
if (params != null) {
throw new InvalidAlgorithmParameterException
("Parameters not supported");
}
int blockType = (mode <= MODE_DECRYPT) ? RSAPadding.PAD_BLOCKTYPE_2
: RSAPadding.PAD_BLOCKTYPE_1;
padding = RSAPadding.getInstance(blockType, n, random);
if (encrypt) {
int k = padding.getMaxDataSize();
buffer = new byte[k];
} else {
buffer = new byte[n];
}
} else { // PAD_OAEP_MGF1
if ((mode == MODE_SIGN) || (mode == MODE_VERIFY)) {
throw new InvalidKeyException
("OAEP cannot be used to sign or verify signatures");
}
OAEPParameterSpec myParams;
if (params != null) {
if (!(params instanceof OAEPParameterSpec)) {
throw new InvalidAlgorithmParameterException
("Wrong Parameters for OAEP Padding");
}
myParams = (OAEPParameterSpec) params;
} else {
myParams = new OAEPParameterSpec(oaepHashAlgorithm, "MGF1",
MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT);
}
padding = RSAPadding.getInstance(RSAPadding.PAD_OAEP_MGF1, n,
random, myParams);
if (encrypt) {
int k = padding.getMaxDataSize();
buffer = new byte[k];
} else {
buffer = new byte[n];
}
}
}
// internal update method
private void update(byte[] in, int inOfs, int inLen) {
if ((inLen == 0) || (in == null)) {
return;
}
if (bufOfs + inLen > buffer.length) {
bufOfs = buffer.length + 1;
return;
}
System.arraycopy(in, inOfs, buffer, bufOfs, inLen);
bufOfs += inLen;
}
// internal doFinal() method. Here we perform the actual RSA operation
private byte[] doFinal() throws BadPaddingException,
IllegalBlockSizeException {
if (bufOfs > buffer.length) {
throw new IllegalBlockSizeException("Data must not be longer "
+ "than " + buffer.length + " bytes");
}
try {
byte[] data;
switch (mode) {
case MODE_SIGN:
data = padding.pad(buffer, 0, bufOfs);
return RSACore.rsa(data, privateKey);
case MODE_VERIFY:
byte[] verifyBuffer = RSACore.convert(buffer, 0, bufOfs);
data = RSACore.rsa(verifyBuffer, publicKey);
return padding.unpad(data);
case MODE_ENCRYPT:
data = padding.pad(buffer, 0, bufOfs);
return RSACore.rsa(data, publicKey);
case MODE_DECRYPT:
byte[] decryptBuffer = RSACore.convert(buffer, 0, bufOfs);
data = RSACore.rsa(decryptBuffer, privateKey);
return padding.unpad(data);
default:
throw new AssertionError("Internal error");
}
} finally {
bufOfs = 0;
}
}
// see JCE spec
protected byte[] engineUpdate(byte[] in, int inOfs, int inLen) {
update(in, inOfs, inLen);
return B0;
}
// see JCE spec
protected int engineUpdate(byte[] in, int inOfs, int inLen, byte[] out,
int outOfs) {
update(in, inOfs, inLen);
return 0;
}
// see JCE spec
protected byte[] engineDoFinal(byte[] in, int inOfs, int inLen)
throws BadPaddingException, IllegalBlockSizeException {
update(in, inOfs, inLen);
return doFinal();
}
// see JCE spec
protected int engineDoFinal(byte[] in, int inOfs, int inLen, byte[] out,
int outOfs) throws ShortBufferException, BadPaddingException,
IllegalBlockSizeException {
if (outputSize > out.length - outOfs) {
throw new ShortBufferException
("Need " + outputSize + " bytes for output");
}
update(in, inOfs, inLen);
byte[] result = doFinal();
int n = result.length;
System.arraycopy(result, 0, out, outOfs, n);
return n;
}
// see JCE spec
protected byte[] engineWrap(Key key) throws InvalidKeyException,
IllegalBlockSizeException {
byte[] encoded = key.getEncoded();
if ((encoded == null) || (encoded.length == 0)) {
throw new InvalidKeyException("Could not obtain encoded key");
}
if (encoded.length > buffer.length) {
throw new InvalidKeyException("Key is too long for wrapping");
}
update(encoded, 0, encoded.length);
try {
return doFinal();
} catch (BadPaddingException e) {
// should not occur
throw new InvalidKeyException("Wrapping failed", e);
}
}
// see JCE spec
protected Key engineUnwrap(byte[] wrappedKey, String algorithm,
int type) throws InvalidKeyException, NoSuchAlgorithmException {
if (wrappedKey.length > buffer.length) {
throw new InvalidKeyException("Key is too long for unwrapping");
}
update(wrappedKey, 0, wrappedKey.length);
try {
byte[] encoded = doFinal();
return ConstructKeys.constructKey(encoded, algorithm, type);
} 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
protected int engineGetKeySize(Key key) throws InvalidKeyException {
RSAKey rsaKey = RSAKeyFactory.toRSAKey(key);
return rsaKey.getModulus().bitLength();
}
}