RSApublic final class RSA extends Cipher This class implements RSA encryption/decryption |
Fields Summary |
---|
private RSAKey | ckeyLocal certificate key. | private int | modeCurrent cipher mode. | private static SecureRandom | rndLocal random number for seed. | private static final int | PAD_OFFSETSignature pad offset. | private byte[] | messageToSignMessage to sign. | private int | bytesInMessageNumber of bytes in the message to sign. |
Constructors Summary |
---|
public RSA()Constructor for RSA.
mode = Cipher.MODE_UNINITIALIZED;
try {
rnd = SecureRandom.getInstance(SecureRandom.ALG_SECURE_RANDOM);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("Random number generator missing");
}
|
Methods Summary |
---|
private void | addToMessage(byte[] inBuf, int inOff, int inLen)Fills the internal message buffer to be encrypted or decrypted
(depending on how this cipher was initialized).
For the RSA public key cipher there is no output until doFinal.
int bytesToCopy;
if (mode == Cipher.MODE_UNINITIALIZED) {
throw new IllegalStateException();
}
if (inLen == 0) {
return;
}
if (inBuf == null || inOff < 0 || inLen < 0 ||
inOff + inLen > inBuf.length) {
throw new IllegalArgumentException("input out of bounds");
}
bytesToCopy = messageToSign.length - bytesInMessage;
if (inLen < bytesToCopy) {
bytesToCopy = inLen;
}
System.arraycopy(inBuf, inOff, messageToSign, bytesInMessage,
bytesToCopy);
bytesInMessage += bytesToCopy;
| public int | doFinal(byte[] inBuf, int inOff, int inLen, byte[] outBuf, int outOff)Process the final data record.
addToMessage(inBuf, inOff, inLen);
if (outBuf == null || outOff < 0) {
throw new IllegalArgumentException("output out of bounds");
}
int val = performRsa(messageToSign, 0, bytesInMessage, outBuf, outOff);
try {
init(mode, ckey);
} catch (InvalidKeyException ike) {
// Ignore, nothing to do
}
return val;
| private byte[] | doIt(byte[] data)Performs an RSA operation on specified data. If the data length
is not the same as the modulus length (as may happen for an
encryption request), PKCS#1 block type 2 padding is added.
int modLen = ckey.getModulusLen();
byte[] buf = new byte[modLen];
byte[] mod = new byte[modLen];
int bufLen;
// Note: Both RSAPublicKey and RSAPrivateKey provide the same
// interface
short val = ckey.getModulus(mod, (short) 0);
byte[] tmp = new byte[modLen];
val = ckey.getExponent(tmp, (short) 0);
byte[] exp = new byte [val];
System.arraycopy(tmp, 0, exp, 0, val);
bufLen = modExp(data, exp, mod, buf);
if (bufLen == modLen) {
return buf;
} else if (bufLen < modLen) {
// Reuse tmp which already points to a byte array of modLen size
for (int i = 0; i < modLen; i++) tmp[i] = 0;
if (buf[0] == (byte) 0x01) {
tmp[0] = (byte) 0x00;
tmp[1] = (byte) 0x01;
for (int i = 2; i < modLen - bufLen + 1; i++) {
tmp[i] = (byte) 0xff;
}
System.arraycopy(buf, 1, tmp,
modLen - bufLen + 1, (bufLen - 1));
} else {
System.arraycopy(buf, 0, tmp, (modLen - bufLen), bufLen);
}
return tmp;
} else { // bufLen > modLen, key may be too long
throw new IllegalArgumentException("Key too long");
}
| public void | init(int opMode, Key key, CryptoParameter params)Initializes this cipher with a key and a set of algorithm
parameters.
if (!(key instanceof RSAKey)) {
throw new InvalidKeyException();
}
if (opMode != DECRYPT_MODE && opMode != ENCRYPT_MODE) {
throw new IllegalArgumentException("Wrong operation mode");
}
mode = opMode;
ckey = (RSAKey)key;
if (ckey.getModulusLen() == 0) {
throw new InvalidKeyException();
}
messageToSign = new byte[ckey.getModulusLen()];
bytesInMessage = 0;
| private static native int | modExp(byte[] data, byte[] exponent, byte[] modulus, byte[] result)A native method for performing modular exponentiation.
| private int | performRsa(byte[] inBuf, int inOff, int inLen, byte[] outBuf, int outOff)Performs the crypto process the buffer.
int modLen;
int outLen;
byte[] tmp;
byte[] res;
int padLen;
int endOfPad;
modLen = ckey.getModulusLen();
switch (mode) {
case Cipher.ENCRYPT_MODE:
if (inLen > modLen - 11) {
throw new IllegalArgumentException("Too much input");
}
/*
* Add PKCS#1 (ver 1.5) padding
* 0x00 | 0x02 | <random, non-zero pad bytes> | 0x00 | <data>
*/
tmp = new byte[modLen];
tmp[0] = (byte) 0x00;
padLen = modLen - inLen - 3;
endOfPad = padLen + PAD_OFFSET;
if (ckey instanceof RSAPublicKey) {
tmp[1] = (byte) 0x02; // for block type 02
// Use random padding (replacing 0x00s)
rnd.nextBytes(tmp, PAD_OFFSET, padLen);
for (int i = PAD_OFFSET; i < endOfPad; i++) {
if (tmp[i] == (byte) 0x00) {
// padding byte must be non-zero
tmp[i] = (byte) 0xff;
}
}
} else {
// NOTE: RFC2313 suggests 0x01 for private key signatures
tmp[1] = (byte) 0x01;
for (int i = PAD_OFFSET; i < endOfPad; i++) {
tmp[i] = (byte) 0xff;
}
}
if (inLen > modLen) {
throw new IllegalArgumentException("inlen > modlen");
}
tmp[modLen - inLen - 1] = (byte) 0x00;
System.arraycopy(inBuf, inOff, tmp, modLen - inLen, inLen);
res = doIt(tmp);
if (outOff + res.length > outBuf.length) {
throw new ShortBufferException();
}
System.arraycopy(res, 0, outBuf, outOff, res.length);
outLen = res.length;
break;
case Cipher.DECRYPT_MODE:
// This is specified in RFC2313
if (inLen != modLen) {
throw new IllegalArgumentException("inlen != modlen");
}
if (inOff != 0) {
tmp = new byte[modLen];
System.arraycopy(inBuf, inOff, tmp, 0, modLen);
res = doIt(tmp);
} else {
res = doIt(inBuf);
}
// Count number of padding bytes (these must be non-zero)
padLen = 0;
for (int i = 2; (i < res.length) && (res[i] != (byte) 0x00); i++) {
padLen++;
}
/*
* Note that whatever our decryption key type is,
* the other side used an opposite key type when encrypting
* so if our key type is TYPE_RSA_PUBLIC, the sender used
* TYPE_RSA_PRIVATE and the expected block type after
* decryption (before encryption) is 0x00 or 0x01
*/
if ((padLen < modLen - 3) && (res.length > 1) &&
(res[0] == (byte) 0x00) &&
(((ckey instanceof RSAPublicKey) &&
((res[1] == (byte) 0x01) || (res[1] == (byte) 0x00))) ||
((ckey instanceof RSAPrivateKey) &&
(res[1] == (byte) 0x02)))) {
outLen = modLen - padLen - 3;
if (outOff + outLen > outBuf.length) {
throw new ShortBufferException();
}
System.arraycopy(res, padLen + 3, outBuf, outOff, outLen);
} else {
throw new BadPaddingException();
}
break;
default:
throw new IllegalStateException();
}
return outLen;
| protected void | setChainingModeAndPadding(java.lang.String mode, java.lang.String padding)Called by the factory method to set the mode and padding parameters.
Need because Class.newInstance does not take args.
if (!(mode.equals("") || mode.equals("NONE"))) {
throw new IllegalArgumentException("illegal chaining mode");
}
// NOPADDING is not an option.
if (!(padding.equals("") || padding.equals("PKCS1PADDING"))) {
throw new NoSuchPaddingException();
}
| public int | update(byte[] inBuf, int inOff, int inLen, byte[] outBuf, int outOff)Fills the internal buffer to be encrypted or decrypted
(depending on how this cipher was initialized).
For the RSA public key cipher there is no output until doFinal.
addToMessage(inBuf, inOff, inLen);
return 0;
|
|