⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rsa.java

📁 面向应用的智能安全代理平台和工具包是一个综合网络应用的安全共性需求而设计和实现的一个通用性的网络信息安全应用支撑平台
💻 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 + -