📄 blockcipher.java
字号:
* 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,
AlgorithmParameterSpec params,
SecureRandom random)
throws InvalidKeyException, InvalidAlgorithmParameterException
{
reset();
this.mode = opmode;
this.random = random;
this.key = key;
if (streamMode == CBC)
{
int blockSize = engineGetBlockSize();
/*
* create two buffers, one for the original
* iv, the other for the "current" iv
*/
ivec = new byte[blockSize];
cbcV = new byte[blockSize];
if (params instanceof IvParameterSpec)
{
/*
* copy the supplied iv
*/
System.arraycopy(
((IvParameterSpec)params).getIV(),
0, ivec, 0, blockSize);
}
else
{
/*
* create a random one, it will be
* added to the output stream
*/
if (params instanceof InlineIvParameterSpec)
{
ivInline = true;
firstBlock = true;
ivEncrypted = ((InlineIvParameterSpec)params).isEncryptedIv();
}
random.nextBytes(ivec);
}
/*
* copy the iv for use
*/
System.arraycopy(ivec, 0, cbcV, 0, blockSize);
}
setKey(key);
}
/**
* Sets the mode of this cipher. Valid modes for are;
* ECB or CBC.
*
* @param mode the cipher mode
* @exception NoSuchAlgorithmException if the requested cipher mode
* does not exist
*/
protected void engineSetMode(String mode)
throws NoSuchAlgorithmException
{
/*
System.out.println("engineSetMode("+mode+")");
*/
if (mode.equals("ECB"))
{
streamMode = ECB;
}
else if (mode.equals("CBC"))
{
streamMode = CBC;
}
else
{
throw new NoSuchAlgorithmException(
"Mode " + mode + " not supported.");
}
}
/**
* Sets the padding mechanism of this cipher. Valid padding mechanisms
* are; "PKCS5Padding" and "NoPadding".
*
* @param padding the padding mechanism
* @exception NoSuchPaddingException if the requested padding
* mechanism does not exist.
*/
protected void engineSetPadding(String padding)
throws NoSuchPaddingException
{
/*
System.out.println("engineSetPadding("+padding+")");
*/
if (padding.equals("PKCS5Padding"))
{
paddedStream = true;
}
else if (padding.equals("NoPadding"))
{
paddedStream = false;
}
else
{
throw new NoSuchPaddingException(
"Unsupported padding " + padding);
}
}
/**
* Continues a multiple-part encryption or decryption operation
* (depending on how this cipher was initialised), processing another
* data part.
* <p>
* The first inputLen bytes in the input buffer, starting at
* inputOffset, are processed, and the result is stored in a new buffer.
*
* @param input the input buffer
* @param inputOffset the offset in input where the input starts
* @param inputLen the input length
* @return the new buffer with the result, or null if the underlying
* cipher is a block cipher and the input data is too short to
* result in a new block.
*/
protected byte[] engineUpdate(
byte[] input,
int inputOff,
int inputLen)
{
byte[] output = null;
int len = engineGetOutputSize(inputLen);
if (len != 0)
{
output = new byte[len];
}
/*
System.out.println("len = " + len);
*/
try
{
len = engineUpdate(input, inputOff, inputLen,
output, 0);
}
catch (ShortBufferException e)
{
// this shouldnt happen
e.printStackTrace();
throw new RuntimeException("ShortBufferException: "
+ e.getMessage());
}
/*
System.out.println("len = " + len);
*/
/*
* our initial buffer was too big!
*/
if (output != null && len != output.length)
{
/*
System.out.println("len = " + len + " output.length = " + output.length);
*/
byte[] buf = new byte[len];
System.arraycopy(output, 0, buf, 0, len);
output = buf;
}
return output;
}
/**
* Continues a multiple-part encryption or decryption operation
* (depending on how this cipher was initialised), processing another
* data part.
* <p>
* The first inputLen bytes in the input buffer, starting at
* inputOffset, are processed, and 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 ShortBufferException if the given output buffer is too
* small to hold the result
*
* @return the number of bytes stored in output
*/
protected int engineUpdate(
byte[] input,
int inputOff,
int inputLen,
byte[] output,
int outputOff)
throws ShortBufferException
{
try
{
return processAllBlocks(input, inputOff, inputLen,
output, outputOff);
}
catch (BadPaddingException bpe)
{
// this shouldnt happen
bpe.printStackTrace();
}
catch (IllegalBlockSizeException ibse)
{
// this shouldnt happen
ibse.printStackTrace();
}
throw new ShortBufferException(
"Internal error, see stacktrace on console.");
}
/**
* This method is used to process in block sized chunks all the
* input data.
*/
private int processAllBlocks(
byte[] input,
int inputOff,
int inputLen,
byte[] output,
int outputOff)
throws BadPaddingException, IllegalBlockSizeException
{
int blockSize = engineGetBlockSize();
int resultBytes = 0;
/*
System.out.println (
"processAllBlocks: input " + input
+ " inputOff " + inputOff
+ " inputLen " + inputLen
+ " output " + output
+ " outputOff " + outputOff
+ " bufferPos " + bufferPos);
*/
if (inputLen < (blockSize - bufferPos))
{
if (inputLen > 0)
{
System.arraycopy(input, inputOff, buffer,
bufferPos, inputLen);
bufferPos += inputLen;
}
return 0;
}
else if (inputLen == (blockSize - bufferPos))
{
if (inputLen > 0)
{
System.arraycopy(input, inputOff, buffer,
bufferPos, inputLen);
}
if (paddedStream)
{
bufferPos += inputLen;
return 0;
}
else
{
resultBytes = processBlock(buffer, 0,
blockSize, output, outputOff);
bufferPos = 0;
return resultBytes;
}
}
else
{
int n = blockSize - bufferPos;
System.arraycopy(input, inputOff, buffer, bufferPos, n);
resultBytes = processBlock(buffer, 0, blockSize,
output, outputOff);
inputLen -= n;
inputOff += n;
outputOff += resultBytes;
bufferPos = 0;
}
int blockCount = (inputLen + blockSize - 1) / blockSize;
int lastBlockSize = inputLen % blockSize;
/*
* decode each element of the array, chopping the array
* into blocks to match the current key.
*/
for (int i = 0; i < blockCount - 1; i++)
{
int n = processBlock(input, inputOff, blockSize,
output, outputOff);
inputOff += blockSize;
outputOff += n;
resultBytes += n;
}
if (lastBlockSize == 0) /* exact multiple */
{
/*
* if we are padded we need to hold the last
* block unless we are an RSA cipher.
*/
if (paddedStream)
{
System.arraycopy(input, inputOff,
buffer, 0, blockSize);
bufferPos = blockSize;
}
else
{
int n = processBlock(input, inputOff,
blockSize, output, outputOff);
outputOff += n;
resultBytes += n;
bufferPos = 0;
}
}
else
{
System.arraycopy(input, inputOff,
buffer, 0, lastBlockSize);
bufferPos = lastBlockSize;
}
return resultBytes;
}
/**
* This method is used to process complete blocks. The cipher
* dependent encrypt or decrypt function will be called depending
* on how this cipher is currently initialised.
*/
private int processBlock(
byte[] input,
int inputOff,
int len,
byte[] output,
int outputOff)
throws BadPaddingException, IllegalBlockSizeException
{
int blockSize = engineGetBlockSize();
int resultLen = 0;
/*
System.out.println (
"processBlock: input " + input
+ " input.length " + input.length
+ " inputOff " + inputOff
+ " len " + len
+ " output " + output
+ " output.length " + output.length
+ " outputOff " + outputOff);
*/
/*
* if we are doing the first block and have an inline IV
* copy/encrypt the IV to the output or copy/decrypt the
* IV from the input
*/
if (firstBlock && ivInline)
{
firstBlock = false;
if (mode == Cipher.ENCRYPT_MODE)
{
int n;
if (ivEncrypted)
{
/*
* encrypt the ivec to the output
*/
n = encryptBlock(ivec, 0, blockSize,
output, outputOff);
}
else
{
/*
* copy the ivec to the output
*/
System.arraycopy(ivec, 0, output,
outputOff, blockSize);
n = blockSize;
}
/*
* just produced a block of output
*/
outputOff += n;
resultLen += n;
}
else // Cipher.DECRYPT_MODE
{
if (ivEncrypted)
{
/*
* decrypt input to the ivec
*/
decryptBlock(input, inputOff, len,
ivec, 0);
}
else
{
/*
* copy input to ivec
*/
System.arraycopy(input, inputOff,
ivec, 0, blockSize);
}
/*
* copy recovered ivec to cbcV
*/
System.arraycopy(ivec, 0, cbcV, 0, blockSize);
/*
* we have consumed a block of input so we return,
* however there is no output
*/
return 0;
}
}
/*
* process the next block
*/
if (mode == Cipher.ENCRYPT_MODE)
{
if (streamMode == CBC)
{
/*
* XOR the cbcV and the input,
* then encrypt the cbcV
*/
for (int i = 0; i < blockSize; i++)
{
cbcV[i] ^= input[inputOff + i];
}
input = cbcV;
inputOff = 0;
}
resultLen += encryptBlock(input, inputOff, len,
output, outputOff);
if (streamMode == CBC)
{
/*
* copy ciphertext to cbcV
*/
System.arraycopy(output, outputOff, cbcV, 0,
blockSize);
}
}
else
{
resultLen += decryptBlock(input, inputOff, len,
output, outputOff);
if (streamMode == CBC)
{
/*
* XOR the cbcV and the output
*/
for (int i = 0; i < blockSize; i++)
{
output[outputOff + i] ^= cbcV[i];
}
/*
* copy ciphertext to cbcV
*/
System.arraycopy(input, inputOff, cbcV, 0,
blockSize);
}
}
return resultLen;
}
/**
* Reset the Cipher to uninitialised.
*/
protected void reset()
{
/*
* zero out our internal buffer
*/
if (buffer != null)
{
for (int i = 0; i < buffer.length; i++)
{
buffer[0] = 0;
}
buffer = null;
}
/*
* reset the cbcV
*/
if (ivec != null)
{
System.arraycopy(ivec, 0, cbcV, 0, engineGetBlockSize());
}
/*
* rekey the cipher
*/
if (key != null)
{
try
{
setKey(key);
}
catch (InvalidKeyException e)
{
// ignore it
}
}
buffer = new byte[engineGetBlockSize()];
bufferPos = 0;
firstBlock = ivInline;
}
/**
* Re-key the cipher. If the provided Key is not compatible
* with this cipher the exception should throw an InvalidKeyException.
*/
protected abstract void setKey(Key key) throws InvalidKeyException;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -