?? blockcipher.java
字號:
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 + -