FileDocCategorySizeDatePackage
ISO9796d1Encoding.javaAPI DocAzureus 3.0.3.47010Tue Jun 08 05:12:58 BST 2004org.bouncycastle.crypto.encodings

ISO9796d1Encoding

public class ISO9796d1Encoding extends Object implements org.bouncycastle.crypto.AsymmetricBlockCipher
ISO 9796-1 padding. Note in the light of recent results you should only use this with RSA (rather than the "simpler" Rabin keys) and you should never use it with anything other than a hash (ie. even if the message is small don't sign the message, sign it's hash) or some "random" value. See your favorite search engine for details.

Fields Summary
private static byte[]
shadows
private static byte[]
inverse
private org.bouncycastle.crypto.AsymmetricBlockCipher
engine
private boolean
forEncryption
private int
bitSize
private int
padBits
Constructors Summary
public ISO9796d1Encoding(org.bouncycastle.crypto.AsymmetricBlockCipher cipher)


     
           
    
        this.engine = cipher;
    
Methods Summary
private byte[]decodeBlock(byte[] in, int inOff, int inLen)

exception
InvalidCipherTextException if the decrypted block is not a valid ISO 9796 bit string

        byte[]  block = engine.processBlock(in, inOff, inLen);
        int     r = 1;
        int     t = (bitSize + 13) / 16;

        if ((block[block.length - 1] & 0x0f) != 0x6)
        {
            throw new InvalidCipherTextException("invalid forcing byte in block");
        }

        block[block.length - 1] = (byte)(((block[block.length - 1] & 0xff) >>> 4) | ((inverse[(block[block.length - 2] & 0xff) >> 4]) << 4));
        block[0] = (byte)((shadows[(block[1] & 0xff) >>> 4] << 4)
                                                | shadows[block[1] & 0x0f]);

        boolean boundaryFound = false;
        int     boundary = 0;
        
        for (int i = block.length - 1; i >= block.length - 2 * t; i -= 2)
        {
            int val = ((shadows[(block[i] & 0xff) >>> 4] << 4)
                                        | shadows[block[i] & 0x0f]);
            
            if (((block[i - 1] ^ val) & 0xff) != 0)
            {
                if (!boundaryFound)
                {
                    boundaryFound = true;
                    r = (block[i - 1] ^ val) & 0xff;
                    boundary = i - 1;
                }
                else
                {
                    throw new InvalidCipherTextException("invalid tsums in block");
                }
            }
        }

        block[boundary] = 0;

        byte[]  nblock = new byte[(block.length - boundary) / 2];

        for (int i = 0; i < nblock.length; i++)
        {
            nblock[i] = block[2 * i + boundary + 1];
        }

        padBits = r - 1;

        return nblock;
    
private byte[]encodeBlock(byte[] in, int inOff, int inLen)

        byte[]  block = new byte[(bitSize + 7) / 8];
        int     r = padBits + 1;
        int     z = inLen;
        int     t = (bitSize + 13) / 16;

        for (int i = 0; i < t; i += z)
        {
            if (i > t - z)
            {
                System.arraycopy(in, inOff + inLen - (t - i),
                                    block, block.length - t, t - i);
            }
            else
            {
                System.arraycopy(in, inOff, block, block.length - (i + z), z);
            }
        }

        for (int i = block.length - 2 * t; i != block.length; i += 2)
        {
            byte    val = block[block.length - t + i / 2];
            
            block[i] = (byte)((shadows[(val & 0xff) >>> 4] << 4)
                                                | shadows[val & 0x0f]);
            block[i + 1] = val;
        }

        block[block.length - 2 * z] ^= r;
        block[block.length - 1] = (byte)((block[block.length - 1] << 4) | 0x06);

        int maxBit = (8 - (bitSize - 1) % 8);
        int offSet = 0;

        if (maxBit != 8)
        {
            block[0] &= 0xff >>> maxBit;
            block[0] |= 0x80 >>> maxBit;
        }
        else
        {
            block[0] = 0x00;
            block[1] |= 0x80;
            offSet = 1;
        }

        return engine.processBlock(block, offSet, block.length - offSet);
    
public intgetInputBlockSize()
return the input block size. The largest message we can process is (key_size_in_bits + 3)/16, which in our world comes to key_size_in_bytes / 2.

        int     baseBlockSize = engine.getInputBlockSize();

        if (forEncryption)
        {
            return (baseBlockSize + 1) / 2;
        }
        else
        {
            return baseBlockSize;
        }
    
public intgetOutputBlockSize()
return the maximum possible size for the output.

        int     baseBlockSize = engine.getOutputBlockSize();

        if (forEncryption)
        {
            return baseBlockSize;
        }
        else
        {
            return (baseBlockSize + 1) / 2;
        }
    
public intgetPadBits()
retrieve the number of pad bits in the last decoded message.

        return padBits;
    
public org.bouncycastle.crypto.AsymmetricBlockCiphergetUnderlyingCipher()

        return engine;
    
public voidinit(boolean forEncryption, org.bouncycastle.crypto.CipherParameters param)

        RSAKeyParameters  kParam = null;

        if (param instanceof ParametersWithRandom)
        {
            ParametersWithRandom    rParam = (ParametersWithRandom)param;

            kParam = (RSAKeyParameters)rParam.getParameters();
        }
        else
        {
            kParam = (RSAKeyParameters)param;
        }

        engine.init(forEncryption, kParam);

        bitSize = kParam.getModulus().bitLength();

        this.forEncryption = forEncryption;
    
public byte[]processBlock(byte[] in, int inOff, int inLen)

        if (forEncryption)
        {
            return encodeBlock(in, inOff, inLen);
        }
        else
        {
            return decodeBlock(in, inOff, inLen);
        }
    
public voidsetPadBits(int padBits)
set the number of bits in the next message to be treated as pad bits.

        if (padBits > 7)
        {
            throw new IllegalArgumentException("padBits > 7");
        }

        this.padBits = padBits;