FileDocCategorySizeDatePackage
BlockCipherBase.javaAPI DocphoneME MR2 API (J2ME)11783Wed May 02 18:00:00 BST 2007com.sun.midp.crypto

BlockCipherBase

public abstract class BlockCipherBase extends Cipher
Class providing common functionality for DES ciphers.

Fields Summary
private int
blockSize
Block size.
protected int
mode
ENCRYPT or DECRYPT.
protected Padder
padder
The padder.
protected byte[]
holdData
Contains the data that is not encrypted or decrypted yet.
protected int
holdCount
The holding buffer counter.
protected boolean
isUpdated
Indicates if this cipher object has been updated or not.
private byte[]
savedHoldData
Saved state variable.
private int
savedHoldCount
Saved state variable.
private boolean
savedIsUpdated
Saved state variable.
protected byte[]
IV
Initial vector.
private boolean
keepLastBlock
True in decryption with padder mode.
Constructors Summary
protected BlockCipherBase(int blockSize)
Constructor.

param
blockSize block size

        this.blockSize = blockSize;

        holdData = new byte[blockSize];
        mode = MODE_UNINITIALIZED;
    
Methods Summary
public intdoFinal(byte[] in, int offset, int len, byte[] out, int outOffset)
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 initialized.

param
in the input buffer
param
offset the offset in input where the input starts
param
len the input length
param
out the buffer for the result
param
outOffset the offset in output where the result is stored
return
the number of bytes stored in output
exception
IllegalStateException if this cipher is in a wrong state (e.g., has not been initialized)
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


        Util.checkBounds(in, offset, len, out, outOffset);

        if (mode == MODE_UNINITIALIZED)  {
            throw new IllegalStateException();
        }

        if (len == 0 && ! isUpdated) {
            return 0;
        }

        boolean encrypt = mode == Cipher.ENCRYPT_MODE;

        // calculate the size of the possible out buffer
        int expectedSize = len + holdCount;
        int delta = expectedSize % blockSize;
        if (delta != 0) {
            if (! encrypt || (encrypt && padder == null)) {
                throw new IllegalBlockSizeException();
            }
            expectedSize += blockSize - delta;
        } else
        if (encrypt && padder != null) {
            expectedSize += blockSize;
        }

        int excess = outOffset + expectedSize - out.length;

        // padder may remove up to blockSize bytes after decryption
        if (excess > (keepLastBlock ? blockSize : 0)) {
            throw new ShortBufferException();
        }

        if (keepLastBlock && excess > 0) {
            // after unpadding data may not fit into output buffer
            saveState();
        }

        int counter = update(in, offset, len, out, outOffset);

        if (padder != null) {
            if (encrypt) {
                if (padder.pad(holdData, holdCount) != 0) {
                    processBlock(out, outOffset + counter);
                    counter += blockSize;
                }
            } else {
                byte[] lastBlock = new byte[blockSize];
                processBlock(lastBlock, 0);
                int tail = blockSize - padder.unPad(lastBlock, blockSize);
                if (outOffset + counter + tail > out.length) {
                    restoreState();
                    throw new ShortBufferException();
                }
                System.arraycopy(lastBlock, 0,
                                 out, outOffset + counter, tail);
                counter += tail;
            }
        }

        holdCount = 0;
        return counter;
    
protected voiddoInit(int mode, java.lang.String keyAlgorithm, Key key, boolean needIV, CryptoParameter params)
Initializes a cipher object with the key and sets encryption or decryption mode.

param
mode either encryption or decription mode
param
keyAlgorithm algorithm the key should have
param
key key to be used
param
needIV true if this algorithm accepts IV parameter
param
params the algorithm parameters
exception
InvalidKeyException if the given key is inappropriate for initializing this cipher
exception
InvalidAlgorithmParameterException if the given algorithm parameters are inappropriate for this cipher


        byte[] IV;

        if (needIV) {
            if (params == null) {
                if (mode == Cipher.DECRYPT_MODE) {
                    throw new InvalidAlgorithmParameterException();
                }
                IV = new byte[blockSize];
            } else {
                if (! (params instanceof IvParameter)) {
                    throw new InvalidAlgorithmParameterException();
                }
                IV = Util.cloneArray(((IvParameter)params).getIV());
                if (IV.length != blockSize)  {
                    throw new InvalidAlgorithmParameterException();
                }
            }
        } else {
            if (params != null) {
                throw new InvalidAlgorithmParameterException();
            }
            IV = null;
        }

        if (!(key instanceof SecretKey &&
              keyAlgorithm.equals(key.getAlgorithm()))) {
            throw new InvalidKeyException();
        }

        initKey(key.getEncoded(), mode);

        holdCount = 0;
        isUpdated = false;
        this.mode = mode;
        this.IV = IV;
        keepLastBlock = mode == Cipher.DECRYPT_MODE && padder != null;
    
public byte[]getIV()
Returns the initialization vector (IV) in a new buffer. This is useful in the case where a random IV was created.

return
the initialization vector in a new buffer, or null if the underlying algorithm does not use an IV.

        return IV == null ? null : Util.cloneArray(IV);
    
abstract voidinitKey(byte[] data, int mode)
Initializes key.

param
data key data
param
mode cipher mode
exception
InvalidKeyException if the given key is inappropriate for this cipher

abstract voidprocessBlock(byte[] out, int offset)
Depending on the mode, either encrypts or decrypts data block.

param
out will contain the result of encryption or decryption operation
param
offset is the offset in out

protected voidrestoreState()
Restores cipher state.

        holdCount = savedHoldCount;
        holdData = savedHoldData;
        isUpdated = savedIsUpdated;
    
protected voidsaveState()
Saves cipher state.

        savedHoldCount = holdCount;
        savedHoldData = holdCount == 0 ?
                        holdData :
                        Util.cloneArray(holdData);
        savedIsUpdated = isUpdated;
    
protected voidsetPadding(java.lang.String padding)
Sets the padder.

param
padding Upper case padding arg from the transformation given to Cipher.getInstance
exception
NoSuchPaddingException if padding contains a padding scheme that is not available.

        
        if (padding.equals("") || padding.equals("PKCS5PADDING")) {
            padder = new PKCS5Padding(blockSize);
        } else if (!padding.equals("NOPADDING")) {
            throw new NoSuchPaddingException(padding);
        }
    
public intupdate(byte[] in, int offset, int len, byte[] out, int outOffset)
Continues a multiple-part encryption or decryption operation (depending on how this cipher was initialized), processing another data part.

param
in the input buffer
param
offset the offset in input where the input starts
param
len the input length
param
out the buffer for the result
param
outOffset the offset in output where the result is stored
return
the number of bytes stored in output
exception
IllegalStateException if this cipher is in a wrong state (e.g., has not been initialized)
exception
ShortBufferException if the given output buffer is too small to hold the result


        Util.checkBounds(in, offset, len, out, outOffset);

        if (mode == MODE_UNINITIALIZED)  {
            throw new IllegalStateException();
        }

        if (len == 0)  {
            return 0;
        }

        if (((holdCount + len) / blockSize -
             (keepLastBlock ? 1 : 0)) * blockSize >
            out.length - outOffset) {
            throw new ShortBufferException();
        }

        isUpdated = true;

        if (in == out) {
            in = new byte[len];
            System.arraycopy(out, offset, in, 0, len);
            offset = 0;
        }

        int counter = 0;
        while (true)  {

            int got;
            System.arraycopy(in, offset, holdData, holdCount,
                             got = Math.min(blockSize - holdCount, len));
            offset += got;
            len -= got;
            holdCount += got;

            if (holdCount < blockSize || (len == 0 && keepLastBlock)) {
                return counter;
            }

            processBlock(out, outOffset);

            counter   += blockSize;
            outOffset += blockSize;
        }