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

📄 blockcipher.java

📁 面向应用的智能安全代理平台和工具包是一个综合网络应用的安全共性需求而设计和实现的一个通用性的网络信息安全应用支撑平台
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
package au.net.aba.crypto.provider;

/*
 * $Id: BlockCipher.java,v 1.25 1999/02/11 04:28:32 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/BlockCipher.java,v $
 * $Revision: 1.25 $
 * $Date: 1999/02/11 04:28:32 $
 * $State: Exp $
 */

import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import au.net.aba.crypto.spec.InlineIvParameterSpec;
import java.security.*;
import java.security.InvalidAlgorithmParameterException;
import java.security.spec.AlgorithmParameterSpec;

/**
 * This abstract class is the base class for all Block Ciphers.
 * It will perform the necessary block buffering and then
 * pass the data on through the protected interface.
 * <p>
 * This class supports PKCS#5 and NoPadding, as well
 * as supporting ECB and CBC modes.  The standard block size
 * is 8.
 * <p>
 * To implement a new block cipher it is necessary to implement
 * the three abstract methods that re-key the cipher, do encryption
 * and decryption using the current.  It may also be necessary
 * to override the <code>engineSetMode</code> method if CBC
 * or ECB are not supported.  If different padding mechanisms are
 * used <code>engineSetPadding</code> may be overridden (in
 * which case it may also be necessary to override
 * <code>engineGetOutputSize</code>).  For block sizes other than 8
 * <code>engineGetBlockSize</code> should be overridden.  Finally
 * if the algorithm supports AlgorithmParameterSpec just override
 * the <code>engineInit</code> method that accepts those parameters.
 */
public abstract class BlockCipher extends CipherSpi
{
	public final static String ident = "$Id: BlockCipher.java,v 1.25 1999/02/11 04:28:32 leachbj Exp $";

	protected final static int BLOCK_SIZE = 8;

	protected static final int ECB = 0;
	protected static final int CBC = 1;

	protected byte[] buffer;
	protected int bufferPos;

	protected int mode;
	protected boolean paddedStream;
	protected int streamMode;

	protected byte[] ivec;
	protected byte[] cbcV;

	protected boolean ivInline;
	protected boolean ivEncrypted;
	protected boolean firstBlock;

	protected Key key;

	protected SecureRandom random;

	public BlockCipher()
	{
		paddedStream = false;
		streamMode = ECB;
	}
	/**
	 * Decrypt the given block starting at the given offset and place
	 * the result in the provided buffer starting at the given offset.
	 * The input will be an exact multiple of our blocksize.
	 */
	protected abstract int decryptBlock(byte[] in, int inoff, int len,
		byte[] out, int outOff) throws BadPaddingException;
	/**
	 * Encrypt the given block starting at the given offset and place
	 * the result in the provided buffer starting at the given offset.
	 * The input will be an exact multiple of our blocksize.
	 */
	protected abstract int encryptBlock(byte[] in, int inoff, int len,
		byte[] out, int outOff) throws IllegalBlockSizeException;
	/**
	 * Encrypts or decrypts data in a single-part operation, or
	 * finishes a multiple-part operation. The data is encrypted or
	 * decrypted, depending on how this cipher was initialised. 
	 * <p>
	 * The first inputLen bytes in the input buffer, starting at
	 * inputOffset, and any input bytes that may have been buffered during
	 * a previous update operation, are processed, with padding (if
	 * requested) being applied. The result is stored in a new buffer. 
	 * <p>
	 * The cipher is reset to its initial state (uninitialised) after
	 * this call. 
	 *
	 * @param input the input buffer 
	 * @param inputOff the offset in input where the input starts 
	 * @param inputLen the input length 
	 *
	 * @exception IllegalBlockSizeException if this cipher is a block
	 * 	cipher, no padding has been requested (only in encryption
	 * 	mode), and the total input length of the data processed by
	 * 	this cipher is not a multiple of block size 
	 * @exception BadPaddingException if this cipher is in decryption mode,
	 * 	and (un)padding has been requested, but the decrypted data is
	 * 	not bounded by the appropriate padding bytes.
	 *
	 * @return the new buffer with the result 
	 */
	protected byte[] engineDoFinal(
		byte input[],
		int inputOff,
		int inputLen)
	throws IllegalBlockSizeException, BadPaddingException
	{
		/*
		 * create result array for the entire result
		 */
		byte[] output = new byte[engineGetOutputSize(inputLen)];

		try
		{
			int len = engineDoFinal(input, inputOff,
				inputLen, output, 0);
			if (len != output.length)
			{
				byte[] tmp = new byte[len];

/*
				System.out.println(
					"output " + output
					+ " output.length "
					+ (output != null ? output.length : -1)
					+ " tmp " + tmp
					+ " tmp.length "
					+ (tmp != null ? tmp.length : -1)
					+ " len " + len);
*/

				System.arraycopy(output, 0, tmp, 0, len);
				output = tmp;
			}
		}
		catch (ShortBufferException e)
		{
			// ouch this should never happen!
			throw new BadPaddingException("ShortBufferException: "
				+ e.getMessage());
		}

		return output;
	}
	/**
	 * Encrypts or decrypts data in a single-part operation, or finishes
	 * a multiple-part operation. The data is encrypted or decrypted,
	 * depending on how this cipher was initialised. 
	 * <p>
	 * The first inputLen bytes in the input buffer, starting at
	 * inputOffset, and any input bytes that may have been buffered during
	 * a previous update operation, are processed, with padding (if
	 * requested) being applied. The result is stored in the output buffer,
	 * starting at outputOffset. 
	 * <p>
	 * If the output buffer is too small to hold the result, a
	 * ShortBufferException is thrown.  In this case, repeat this call
	 * with a larger output buffer. Use getOutputSize to determine how
	 * big the output buffer should be. 
	 * 
	 * @param input the input buffer 
	 * @param inputOffset - the offset in input where the input starts 
	 * @param inputLen - the input length 
	 * @param output - the buffer for the result 
	 * @param outputOffset - the offset in output where the result is stored
	 * 
	 * @exception IllegalBlockSizeException if this cipher is a block
	 * 	cipher, no padding has been requested (only in encryption mode),
	 * 	and the total input length of the data processed by this cipher
	 * 	is not a multiple of block size 
	 * @exception ShortBufferException if the given output buffer is too
	 * 	small to hold the result 
	 * @exception BadPaddingException if this cipher is in decryption mode,
	 * 	and (un)padding has been requested, but the decrypted data is
	 * 	not bounded by the appropriate padding bytes 
	 * @returns the number of bytes stored in output 
	 */
	protected int engineDoFinal(
		byte[] input,
		int inputOff,
		int inputLen,
		byte[] output,
		int outputOff)
	throws ShortBufferException, IllegalBlockSizeException,
		BadPaddingException
	{
		int blockSize = engineGetBlockSize();
		int resultLen;

/*
		System.out.println("engineDoFinal: "
			+ " input " + input
			+ " inputOff " + inputOff
			+ " inputLen " + inputLen
			+ " output " + output
			+ " outputOff " + outputOff);
*/

		/*
		 * process any full blocks
		 */
		resultLen = processAllBlocks(input, inputOff, inputLen,
			output, outputOff);
		outputOff += resultLen;

/*
		System.out.println("engineDoFinal: bufferPos " + bufferPos);
*/

		/*
		 * process any final partial block
		 */
		if (mode == Cipher.ENCRYPT_MODE)
		{
			if (bufferPos == blockSize)
			{
				int n = processBlock(buffer, 0,
					blockSize, output, outputOff);
				outputOff += n;
				resultLen += n;
				bufferPos = 0;
			}

			if (paddedStream)
			{
				/*
				 * add PKCS7 padding
				 */
				int code = blockSize - bufferPos;
				for (; bufferPos < blockSize;
					bufferPos++)
				{
					buffer[bufferPos] = (byte)code;
				}

/*
				System.out.println("padding with code: " + code);
*/
			}

			if (bufferPos > 0)
			{
				resultLen += processBlock(buffer, 0, bufferPos,
					output, outputOff);
				bufferPos = 0;
			}
		}
		else if (mode == Cipher.DECRYPT_MODE)
		{
			if (bufferPos > 0)
			{
				if (bufferPos == blockSize)
				{
					resultLen += processBlock(buffer, 0,
						blockSize, output, outputOff);
					bufferPos = 0;
				}
				else
				{
					throw new IllegalBlockSizeException(
						"input truncated.");
				}
			}

			if (paddedStream)
			{
/*
System.out.println(outputOff + " " + test.ByteUtil.bytesToHexStr(output));
*/

				/*
				 * remove PKCS7 padding
				 */
				int count = output[outputOff
					+ blockSize - 1] & 0xff;

/*
				System.out.println("pad count = " + count);
*/
				resultLen -= count;
			}
		}

		reset();
		return resultLen;
	}
	/**
	 * Returns the block size (in bytes).  In this case 8.  This
	 * method should be overridden if the given algorithm has
	 * a different block size.
	 *
	 * @return the block size (in bytes), or 0 if the underlying
	 * 	algorithm is not a block cipher 
	 */
	protected int engineGetBlockSize()
	{
		return BLOCK_SIZE;
	}
	/**
	 * Returns the initialisation vector (IV) in a new buffer. 
	 * <p>
	 * This is useful in the context of password-based encryption or
	 * decryption, where the IV is derived from a user-provided passphrase. 
	 *
	 * @return the initialisation vector in a new buffer, or null if the
	 * 	underlying algorithm does not use an IV, or if the IV has
	 * 	not yet been set. 
	 */
	protected byte[] engineGetIV()
	{
		if (ivec != null)
		{
			int blockSize = engineGetBlockSize();
			byte[] result = new byte[blockSize];
			System.arraycopy(ivec, 0, result, 0, blockSize);

			return result;
		}

		return null;
	}
	/**
	 * 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). 
	 * <p>
	 * This call takes into account any unprocessed (buffered) data from a
	 * previous update call, and padding. 
	 * <p>
	 * The actual output length of the next update or doFinal call may be
	 * smaller than the length returned by this method. 
	 *
	 * @param inputLen the input length (in bytes) 
	 * @return the required output buffer size (in bytes)
	 */
	protected int engineGetOutputSize(int inputLen)
	{
		int blockSize = engineGetBlockSize();

		if (firstBlock && ivInline)
		{
			if (mode == Cipher.ENCRYPT_MODE)
			{
				inputLen += blockSize;
			}
			else if (mode == Cipher.DECRYPT_MODE)
			{
				inputLen -= blockSize;
			}
		}

		inputLen += bufferPos;

		if (paddedStream)
		{
			if ((inputLen % blockSize) == 0)
			{
				inputLen += blockSize;
			}

			return ((inputLen + blockSize - 1) / blockSize)
				* blockSize;
		}

		return (inputLen / blockSize) * blockSize;
	}
	/**
	 * Returns the parameters used with this cipher. 
	 * <p>
	 * The returned parameters may be the same that were used to initialise
	 * this cipher, or may contain the default set of parameters or a set of
	 * randomly generated parameters used by the underlying cipher
	 * implementation (provided that the underlying cipher implementation
	 * uses a default set of parameters or creates new parameters if it
	 * needs parameters but was not initialised with any).
	 *
	 * @return the parameters used with this cipher, or null if this cipher
	 *     does not use any parameters.
	 */
	protected AlgorithmParameters engineGetParameters()
	{
		return null;
	}
	/**
	 * Initialises this cipher with a key, a set of algorithm parameters,
	 * and a source of randomness.
	 * <p>
	 * The cipher is initialised for encryption or decryption, depending
	 * on the value of opmode.
	 * <p>
	 * If this cipher requires any algorithm parameters and params is
	 * null, the underlying cipher implementation is supposed to generate
	 * the required parameters itself (using provider-specific default or
	 * random values) if it is being initialised for encryption, and
	 * raise an InvalidAlgorithmParameterException if it is being
	 * initialised for decryption. The generated parameters can be
	 * retrieved using engineGetParameters or engineGetIV (if the
	 * parameter is an IV). 
	 * <p>
	 * If this cipher (including its underlying feedback or padding
	 * scheme) requires any random bytes (e.g., for parameter
	 * generation), it will get them from random. 
	 * <p>
	 * Note that when a Cipher object is initialised, it loses all
	 * previously-acquired state. In other words, initialising a Cipher
	 * is equivalent to creating a new instance of that Cipher and
	 * initialising it.
	 * <p>
	 * @param opmode the operation mode of this cipher (this is either
	 *    ENCRYPT_MODE or DECRYPT_MODE)
	 * @param key the encryption key
	 * @param params the algorithm parameters
	 * @param random the source of randomness
	 * @exception InvalidKeyException if the given key is
	 *    inappropriate for initialising this cipher
	 * @exception InvalidAlgorithmParameterException if the given algorithm
	 * 	parameters are inappropriate for this cipher, or if this
	 * 	cipher is being initialised fro decryption and requires
	 * 	algorithm parameters and params is null
	 */
	protected void engineInit(
		int opmode,
		Key key,
		AlgorithmParameters params,
		SecureRandom random)
	throws InvalidKeyException, InvalidAlgorithmParameterException
	{
		AlgorithmParameterSpec spec = null;
		if (params != null)
		{
			try
			{
				spec = params.getParameterSpec(IvParameterSpec.class);
			}
			catch (Exception e)
			{
				try
				{
					spec = params.getParameterSpec(InlineIvParameterSpec.class);
				}
				catch (Exception e2)
				{
					throw new InvalidAlgorithmParameterException(
						"Processing error: " + e2);
				
				}
			}
		}

		engineInit(opmode, key, spec, random);
	}
	/**
	 * Initialises this cipher with a key and a source of randomness.  
	 * <p>
	 * The cipher is initialised for encryption or decryption, depending
	 * on the value of opmode.
	 * <p>
	 * If this cipher requires any algorithm parameters that cannot be
	 * derived from the given key, the underlying cipher implementation
	 * is supposed to generate the required parameters itself (using
	 * provider-specific default or random values) if it is being
	 * initialised for encryption, and raise an InvalidKeyException if it
	 * is being initialised for decryption. The generated parameters can
	 * be retrieved using engineGetParameters or engineGetIV (if the
	 * parameter is an IV).
	 * <p>
	 * If this cipher (including its underlying feedback or padding
	 * scheme) requires any random bytes (e.g., for parameter
	 * generation), it will get them from random.
	 * <p>
	 * Note that when a Cipher object is initialised, it loses all
	 * previously-acquired state. In other words, initialising a Cipher
	 * is equivalent to creating a new instance of that Cipher and
	 * initialising it

	 * @param opmode the operation mode of this cipher (this is either
	 *			ENCRYPT_MODE or DECRYPT_MODE) 
	 * @param key the encryption key 
	 * @param random the source of randomness 
	 * @exception InvalidKeyException if the given key is inappropriate
	 *			for initialising this cipher 
	 */
	protected void engineInit(
		int opmode,
		Key key,
		SecureRandom random)
	throws InvalidKeyException
	{
		try
		{
			engineInit(opmode, key, (AlgorithmParameterSpec)null,
				random);
		}
		catch (InvalidAlgorithmParameterException e)
		{
			// ouch this should never happen!
			throw new InvalidKeyException(
				"InvalidAlgorithmParameterException: "
				+ e.getMessage());
		}
	}
	/**
	 * Initialises this cipher with a key, a set of algorithm parameters,
	 * and a source of randomness.
	 * <p>
	 * The cipher is initialised for encryption or decryption, depending
	 * on the value of opmode.
	 * <p>
	 * If this cipher requires any algorithm parameters and params is
	 * null, the underlying cipher implementation is supposed to generate
	 * the required parameters itself (using provider-specific default or
	 * random values) if it is being initialised for encryption, and
	 * raise an InvalidAlgorithmParameterException if it is being
	 * initialised for decryption. The generated parameters can be
	 * retrieved using engineGetParameters or engineGetIV (if the
	 * parameter is an IV).
	 * <p>
	 * If this cipher (including its underlying feedback or padding
	 * scheme) requires any random bytes (e.g., for parameter
	 * generation), it will get them from random.
	 * <p>
	 * Note that when a Cipher object is initialised, it loses all
	 * previously-acquired state. In other words, initialising a Cipher
	 * is equivalent to creating a new instance of that Cipher and
	 * initialising it.
	 * <p>
	 * @param opmode the operation mode of this cipher (this is either
	 *	ENCRYPT_MODE or DECRYPT_MODE) 
	 * @param key the encryption key 
	 * @param params the algorithm parameters
	 * @param random the source of randomness 
	 *
	 * @exception InvalidKeyException if the given key is inappropriate

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -