📄 rsa.java
字号:
package au.net.aba.crypto.provider;
/*
* $Id: RSA.java,v 1.25 1999/01/22 06:28:03 leachbj Exp $
* $Author: leachbj $
*
* Copyright (C) 1996-1998 Australian Business Access Pty Ltd.
* All rights reserved.
*
* Use, modification, copying and distribution of this software is subject the
* terms and conditions of the ABA Public Licence. See the file
* "PUBLIC_LICENCE" for additional information.
*
* If you have not received a copy of the Public Licence, you must destroy all
* copies of this file immediately.
*
* $Source: /aba/CVSROOT/jdk1.1/src/au.net.aba/crypto/provider/RSA.java,v $
* $Revision: 1.25 $
* $Date: 1999/01/22 06:28:03 $
* $State: Exp $
*/
import java.math.*;
import java.security.*;
import java.security.interfaces.RSAPublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.spec.AlgorithmParameterSpec;
import java.security.AlgorithmParameters;
import javax.crypto.*;
/**
* A class that provides RSA public/private key encryption and
* decryption as specified in PKCS#1.
* <p>
* By default this cipher will use PKCS#1 padding however it
* also supports NoPadding.
*/
public class RSA extends BlockCipher
{
public final static String ident = "$Id: RSA.java,v 1.25 1999/01/22 06:28:03 leachbj Exp $";
private static final int HEADER_SIZE = 11; // PKCS1 - with padding
private RSAPublicKey rsaPublicKey;
private RSAPrivateKey rsaPrivateKey;
private int significantBytes = HEADER_SIZE;
private boolean padded;
/*
* Forge Research.
*
* This saves calling the key to get the byte length all the time.
* BITS_IN_BYTE is defined here as the ABA keys are not referenced now.
*/
private static final int BITS_IN_BYTE = 8;
public RSA()
{
padded = true;
paddedStream = false;
}
/**
* Perform RSA encryption utilising private key data and the
* Chinese remainder theorem. This method should be noticeably
* faster than the standard public key form.
*
* @param data The plain text or cipher text to cipher.
* @return The ciphered data.
*/
private BigInteger crtProcess(
BigInteger data)
{
RSAPrivateCrtKey rsaPrivateCrtKey = (RSAPrivateCrtKey)rsaPrivateKey;
/*
* grab the CRT values from the key
*/
BigInteger d = rsaPrivateCrtKey.getPrivateExponent();
BigInteger p = rsaPrivateCrtKey.getPrimeP();
BigInteger q = rsaPrivateCrtKey.getPrimeQ();
BigInteger dP = rsaPrivateCrtKey.getPrimeExponentP();
BigInteger dQ = rsaPrivateCrtKey.getPrimeExponentQ();
BigInteger qInv = rsaPrivateCrtKey.getCrtCoefficient();
BigInteger mP, mQ, tmp;
// mP = ((data mod p) ^ dP)) mod p
mP = (data.remainder(p)).modPow(dP, p);
// mQ = ((data mod q) ^ dQ)) mod q
mQ = (data.remainder(q)).modPow(dQ, q);
if (mP.compareTo(mQ) >= 0)
{
tmp = mP.subtract(mQ);
}
else
{
tmp = p.subtract(mQ.subtract(mP));
}
tmp = tmp.multiply(qInv);
tmp = tmp.remainder(p);
tmp = tmp.multiply(q);
tmp = tmp.add(mQ);
return tmp;
}
/**
* Decrypt a data block with this key.
*
* @param cipherText The cipher text block to decrypt. On return,
* this references a new array that contains
* the plain text.
*/
private byte[] decrypt(
byte[] cipherText)
{
BigInteger value = new BigInteger(1, cipherText);
// do the decipher
value = decrypt(value);
return value.toByteArray();
}
/**
* Decrypt a data block with the key.
*
* @param data The cipher text block to decrypt.
* @return The decrypted data.
*/
private BigInteger decrypt(
BigInteger cipherText)
{
if (rsaPrivateKey instanceof RSAPrivateCrtKey)
{
return crtProcess(cipherText);
}
else
{
BigInteger exponent = null;
BigInteger modulus = null;
if (rsaPrivateKey != null)
{
exponent = rsaPrivateKey.getPrivateExponent();
modulus = rsaPrivateKey.getModulus();
}
else
{
exponent = rsaPublicKey.getPublicExponent();
modulus = rsaPublicKey.getModulus();
}
return cipherText.modPow(exponent, modulus);
}
}
/**
* This method decrypts the specified array, placing the plain text
* data into the destination array.
*
* @param src The cipher text.
* @param srcIndex The index from which to read.
* @param len The lenght of the cipher text.
* @param dst The plain text.
* @param dstIndex The index at which to write.
* @return The number of bytes of plaintext.
*/
protected final int decryptBlock(
byte[] src,
int srcIndex,
int len,
byte[] dst,
int dstIndex)
throws BadPaddingException
{
/*
* copy the source data into an array of correct length
*/
byte[] enc = new byte[significantBytes];
System.arraycopy(src, srcIndex, enc, 0, enc.length);
/*
* decrypt the block
*/
byte[] block = decrypt(enc);
int offset = 0;
/*
* determine the start of the data portion of
* the packet according to the padding type
*/
if (padded)
{
if (block[0] != 0x01 && block[0] != 0x02)
{
throw new BadPaddingException("Bad block type");
}
for (offset = 1; offset != block.length; offset++)
{
if (block[offset] == 0)
{
break;
}
}
offset++; // data starts in the next byte
}
/*
* there can be at most (significantBytes - HEADER_SIZE)
* bytes of data in the packet
*/
int resultLen = block.length - offset;
if (resultLen <= 0
|| resultLen > significantBytes - HEADER_SIZE)
{
throw new BadPaddingException("Invalid PKCS1 block");
}
System.arraycopy(block, offset, dst, dstIndex, resultLen);
return resultLen;
}
/**
* Encrypt a data block with this key.
*
* @param plainText The plain text block to encrypt. On return,
* this references a new array that contains
* the encrypted data.
*/
private byte[] encrypt(
byte[] plainText)
{
BigInteger value = new BigInteger(1, plainText);
// do the cipher
value = encrypt(value);
return value.toByteArray();
}
/**
* Encrypt a data block.
*
* @param plainText The plain text block to encrypt.
* @return The encrypted data.
*/
protected BigInteger encrypt(
BigInteger plainText)
{
if (rsaPrivateKey instanceof RSAPrivateCrtKey)
{
return crtProcess(plainText);
}
else
{
BigInteger exponent = null;
BigInteger modulus = null;
if (rsaPrivateKey != null)
{
exponent = rsaPrivateKey.getPrivateExponent();
modulus = rsaPrivateKey.getModulus();
}
else
{
exponent = rsaPublicKey.getPublicExponent();
modulus = rsaPublicKey.getModulus();
}
return plainText.modPow(exponent, modulus);
}
}
/**
* This method encrypts the specified array, placing the
* ciphered data into the destination array.
*
* @param src The plain text.
* @param srcIndex The index from which to read.
* @param len The length of the plain text.
* @param dst The cipher text.
* @param dstIndex The index at which to write.
* @return The number of bytes processed.
*/
protected final int encryptBlock(
byte[] src,
int srcIndex,
int len,
byte[] dst,
int dstIndex)
throws IllegalBlockSizeException
{
/*
* create a PKCS1 block (from the PKCS-1 standard);
*
* EB = 00 || BT || PS || 00 || D
*
* BT is
* 00 for private key encryption with no padding
* 01 for private key padding (each byte is 0xFF)
* 02 for public key padding (each byte is rand none zero)
*
* PS is the padding string of length k-3-||D||. That
* is (significantBytes - 3 - data.length).
*
* D is the data, maximum length k - 11
*/
if (len > significantBytes - HEADER_SIZE)
{
throw new IllegalBlockSizeException(
"Datasize greater than allowable payload size.");
}
/*
* create the new block (all zeros)
*/
byte[] block = new byte[significantBytes];
/*
* add the correct padding
*/
if (padded)
{
if (rsaPrivateKey != null)
{
block[0] = 0x00; // so we are < the key!
block[1] = 0x01;
for (int i = 2; i != block.length; i++)
{
block[i] = (byte)0xFF;
}
}
else
{
random.nextBytes(block); // random fill
block[0] = 0x00; // so we are < the key!
block[1] = 0x02;
/*
* all our random bytes must be <> 0
*/
for (int i = 2; i != block.length; i++)
{
if (block[i] == 0)
{
block[i] = (byte)(0xFF & ~i);
}
}
}
/*
* mark the end of the padding
*/
block[block.length - len - 1] = 0x00;
}
/*
* copy in the data
*/
System.arraycopy(src, srcIndex, block,
block.length - len, len);
/*
* encrypt the block
*/
block = encrypt(block);
/*
* as the byte format returned is in twos complement we
* sometimes get a byte representation that is one byte longer
* than we want. We need to ignore this byte (it is always
* zero anyway).
*/
if (block.length >= significantBytes)
{
System.arraycopy(block, block.length - significantBytes,
dst, dstIndex, significantBytes);
}
else
{
int off = significantBytes - block.length;
/*
* if the number is smaller...
*/
for (int i = 0; i <= off; i++)
{
dst[dstIndex + i] = 0;
}
System.arraycopy(block, 0, dst, dstIndex + off,
block.length);
}
return significantBytes;
}
/**
* Returns the block size. In encryption mode this will be
* the size of the key less the header bytes, in decryption
* mode it will be the size of the key.
*/
protected int engineGetBlockSize()
{
if (mode == Cipher.DECRYPT_MODE)
{
return significantBytes;
}
return significantBytes - HEADER_SIZE;
}
/**
* Returns the length in bytes that an output buffer would need to be
* in order to hold the result of the next update or doFinal operation,
* given the input length inputLen (in bytes).
*/
protected int engineGetOutputSize(int inputLen)
{
int blockSize = engineGetBlockSize();
inputLen += bufferPos;
if (mode == Cipher.DECRYPT_MODE)
{
return inputLen / blockSize * (blockSize - HEADER_SIZE);
}
return (inputLen + blockSize - 1) / blockSize
* significantBytes;
}
/**
* Sets the mode of this cipher.
*
* @param mode the mode of the cipher (ECB, CBC). Currently only
* ECB is supported.
* @exception NoSuchAlgorithmException if the mode is not supported.
*/
public void engineSetMode(
String mode)
throws NoSuchAlgorithmException
{
if (!mode.equals("ECB"))
{
throw new NoSuchAlgorithmException(
"RSA only supports ECB.");
}
}
/**
* Sets the padding mechanism of this cipher.
*
* @param padding the name of the type of padding to be applied,
* currently "PKCS1Padding", and "NoPadding" will
* be accepted.
* @exception NoSuchPaddingException if the padding type is unknown.
*/
public void engineSetPadding(
String padding)
throws NoSuchPaddingException
{
if (padding.equals("PKCS1Padding"))
{
padded = true;
}
else if (padding.equals("NoPadding"))
{
padded = false;
}
else
{
throw new NoSuchPaddingException(
"RSA only supports PKCS1.");
}
}
/**
*/
protected void setKey(Key key)
throws InvalidKeyException
{
/*
* Check the key passed in against the standard java.security RSA
* interfaces.
*/
if (!(key instanceof RSAPrivateKey)
&& !(key instanceof RSAPublicKey))
{
throw new InvalidKeyException(
"expecting RSAPrivateKey/RSAPrivateCrtKey/RSAPublicKey");
}
/*
* Save the key for usage, and calculate the significant bytes
* in a generic way
*/
int keyBitLength = 0;
if (key instanceof RSAPublicKey)
{
rsaPublicKey = (RSAPublicKey)key;
rsaPrivateKey = null;
keyBitLength = rsaPublicKey.getModulus().bitLength();
}
else
{
rsaPrivateKey = (RSAPrivateKey)key;
rsaPublicKey = null;
keyBitLength = rsaPrivateKey.getModulus().bitLength();
}
significantBytes = (keyBitLength + BITS_IN_BYTE - 1) / BITS_IN_BYTE;
/*
* reset our buffer size, we need to do this because out
* block size just changed.
*/
buffer = new byte[engineGetBlockSize()];
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -