FileDocCategorySizeDatePackage
PKCS1Encoding.javaAPI DocAndroid 1.5 API6114Wed May 06 22:41:06 BST 2009org.bouncycastle.crypto.encodings

PKCS1Encoding

public class PKCS1Encoding extends Object implements org.bouncycastle.crypto.AsymmetricBlockCipher
this does your basic PKCS 1 v1.5 padding - whether or not you should be using this depends on your application - see PKCS1 Version 2 for details.

Fields Summary
public static String
STRICT_LENGTH_ENABLED_PROPERTY
some providers fail to include the leading zero in PKCS1 encoded blocks. If you need to work with one of these set the system property org.bouncycastle.pkcs1.strict to false.

The system property is checked during construction of the encoding object, it is set to true by default.

private static int
HEADER_LENGTH
private SecureRandom
random
private org.bouncycastle.crypto.AsymmetricBlockCipher
engine
private boolean
forEncryption
private boolean
forPrivateKey
private boolean
useStrictLength
Constructors Summary
public PKCS1Encoding(org.bouncycastle.crypto.AsymmetricBlockCipher cipher)
Basic constructor.

param
cipher


             
     
           
    
        this.engine = cipher;
        this.useStrictLength = System.getProperty(STRICT_LENGTH_ENABLED_PROPERTY, "true").equals("true");
    
Methods Summary
private byte[]decodeBlock(byte[] in, int inOff, int inLen)

exception
InvalidCipherTextException if the decrypted block is not in PKCS1 format.

        byte[]  block = engine.processBlock(in, inOff, inLen);

        if (block.length < getOutputBlockSize())
        {
            throw new InvalidCipherTextException("block truncated");
        }

        byte type = block[0];
        
        if (type != 1 && type != 2)
        {
            throw new InvalidCipherTextException("unknown block type");
        }

        if (useStrictLength && block.length != engine.getOutputBlockSize())
        {
            throw new InvalidCipherTextException("block incorrect size");
        }
        
        //
        // find and extract the message block.
        //
        int start;
        
        for (start = 1; start != block.length; start++)
        {
            byte pad = block[start];
            
            if (pad == 0)
            {
                break;
            }
            if (type == 1 && pad != (byte)0xff)
            {
                throw new InvalidCipherTextException("block padding incorrect");
            }
        }

        start++;           // data should start at the next byte

        if (start >= block.length || start < HEADER_LENGTH)
        {
            throw new InvalidCipherTextException("no data in block");
        }

        byte[]  result = new byte[block.length - start];

        System.arraycopy(block, start, result, 0, result.length);

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

        byte[]  block = new byte[engine.getInputBlockSize()];

        if (forPrivateKey)
        {
            block[0] = 0x01;                        // type code 1

            for (int i = 1; i != block.length - inLen - 1; i++)
            {
                block[i] = (byte)0xFF;
            }
        }
        else
        {
            random.nextBytes(block);                // random fill

            block[0] = 0x02;                        // type code 2

            //
            // a zero byte marks the end of the padding, so all
            // the pad bytes must be non-zero.
            //
            for (int i = 1; i != block.length - inLen - 1; i++)
            {
                while (block[i] == 0)
                {
                    block[i] = (byte)random.nextInt();
                }
            }
        }

        block[block.length - inLen - 1] = 0x00;       // mark the end of the padding
        System.arraycopy(in, inOff, block, block.length - inLen, inLen);

        return engine.processBlock(block, 0, block.length);
    
public intgetInputBlockSize()

        int     baseBlockSize = engine.getInputBlockSize();

        if (forEncryption)
        {
            return baseBlockSize - HEADER_LENGTH;
        }
        else
        {
            return baseBlockSize;
        }
    
public intgetOutputBlockSize()

        int     baseBlockSize = engine.getOutputBlockSize();

        if (forEncryption)
        {
            return baseBlockSize;
        }
        else
        {
            return baseBlockSize - HEADER_LENGTH;
        }
    
public org.bouncycastle.crypto.AsymmetricBlockCiphergetUnderlyingCipher()

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

        AsymmetricKeyParameter  kParam;

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

            this.random = rParam.getRandom();
            kParam = (AsymmetricKeyParameter)rParam.getParameters();
        }
        else
        {
            this.random = new SecureRandom();
            kParam = (AsymmetricKeyParameter)param;
        }

        engine.init(forEncryption, kParam);

        this.forPrivateKey = kParam.isPrivate();
        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);
        }