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

OAEPEncoding

public class OAEPEncoding extends Object implements org.bouncycastle.crypto.AsymmetricBlockCipher
Optimal Asymmetric Encryption Padding (OAEP) - see PKCS 1 V 2.

Fields Summary
private byte[]
defHash
private org.bouncycastle.crypto.Digest
hash
private org.bouncycastle.crypto.AsymmetricBlockCipher
engine
private SecureRandom
random
private boolean
forEncryption
Constructors Summary
public OAEPEncoding(org.bouncycastle.crypto.AsymmetricBlockCipher cipher)

        this(cipher, new SHA1Digest(), null);
    
public OAEPEncoding(org.bouncycastle.crypto.AsymmetricBlockCipher cipher, org.bouncycastle.crypto.Digest hash)

		this(cipher, hash, null);
	
public OAEPEncoding(org.bouncycastle.crypto.AsymmetricBlockCipher cipher, org.bouncycastle.crypto.Digest hash, byte[] encodingParams)

		this.engine = cipher;
		this.hash = hash;
		this.defHash = new byte[hash.getDigestSize()];
        
        if (encodingParams != null)
        {
        	hash.update(encodingParams, 0, encodingParams.length);
        }
        
		hash.doFinal(defHash, 0);
	
Methods Summary
private voidItoOSP(int i, byte[] sp)
int to octet string.

        sp[0] = (byte)(i >>> 24);
        sp[1] = (byte)(i >>> 16);
        sp[2] = (byte)(i >>> 8);
        sp[3] = (byte)(i >>> 0);
    
public byte[]decodeBlock(byte[] in, int inOff, int inLen)

exception
InvalidCipherTextException if the decryypted block turns out to be badly formatted.

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

        //
        // as we may have zeros in our leading bytes for the block we produced
        // on encryption, we need to make sure our decrypted block comes back
        // the same size.
        //
        if (data.length < engine.getOutputBlockSize())
        {
            block = new byte[engine.getOutputBlockSize()];

            System.arraycopy(data, 0, block, block.length - data.length, data.length);
        }
        else
        {
            block = data;
        }

        if (block.length < (2 * defHash.length) + 1)
        {
            throw new InvalidCipherTextException("data too short");
        }

        //
        // unmask the seed.
        //
        byte[] mask = maskGeneratorFunction1(
                    block, defHash.length, block.length - defHash.length, defHash.length);

        for (int i = 0; i != defHash.length; i++)
        {
            block[i] ^= mask[i];
        }

        //
        // unmask the message block.
        //
        mask = maskGeneratorFunction1(block, 0, defHash.length, block.length - defHash.length);

        for (int i = defHash.length; i != block.length; i++)
        {
            block[i] ^= mask[i - defHash.length];
        }

        //
        // check the hash of the encoding params.
        //
        for (int i = 0; i != defHash.length; i++)
        {
            if (defHash[i] != block[defHash.length + i])
            {
                throw new InvalidCipherTextException("data hash wrong");
            }
        }

        //
        // find the data block
        //
        int start;

        for (start = 2 * defHash.length; start != block.length; start++)
        {
            if (block[start] == 1 || block[start] != 0)
            {
                break;
            }
        }

        if (start >= (block.length - 1) || block[start] != 1)
        {
            throw new InvalidCipherTextException("data start wrong " + start);
        }

        start++;

        //
        // extract the data block
        //
        byte[]  output = new byte[block.length - start];

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

        return output;
    
public byte[]encodeBlock(byte[] in, int inOff, int inLen)

        byte[]  block = new byte[getInputBlockSize() + 1 + 2 * defHash.length];

        //
        // copy in the message
        //
        System.arraycopy(in, inOff, block, block.length - inLen, inLen);

        //
        // add sentinel
        //
        block[block.length - inLen - 1] = 0x01;

        //
        // as the block is already zeroed - there's no need to add PS (the >= 0 pad of 0)
        //

        //
        // add the hash of the encoding params.
        //
        System.arraycopy(defHash, 0, block, defHash.length, defHash.length);

        //
        // generate the seed.
        //
        byte[]  seed = new byte[defHash.length];

        random.nextBytes(seed);

        //
        // mask the message block.
        //
        byte[]  mask = maskGeneratorFunction1(seed, 0, seed.length, block.length - defHash.length);

        for (int i = defHash.length; i != block.length; i++)
        {
            block[i] ^= mask[i - defHash.length];
        }

        //
        // add in the seed
        //
        System.arraycopy(seed, 0, block, 0, defHash.length);

        //
        // mask the seed.
        //
        mask = maskGeneratorFunction1(
                        block, defHash.length, block.length - defHash.length, defHash.length);

        for (int i = 0; i != defHash.length; i++)
        {
            block[i] ^= mask[i];
        }

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

        int     baseBlockSize = engine.getInputBlockSize();

        if (forEncryption)
        {
            return baseBlockSize - 1 - 2 * defHash.length;
        }
        else
        {
            return baseBlockSize;
        }
    
public intgetOutputBlockSize()

        int     baseBlockSize = engine.getOutputBlockSize();

        if (forEncryption)
        {
            return baseBlockSize;
        }
        else
        {
            return baseBlockSize - 1 - 2 * defHash.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.forEncryption = forEncryption;
    
private byte[]maskGeneratorFunction1(byte[] Z, int zOff, int zLen, int length)
mask generator function, as described in PKCS1v2.

        byte[]  mask = new byte[length];
        byte[]  hashBuf = new byte[defHash.length];
        byte[]  C = new byte[4];
        int     counter = 0;

        hash.reset();

        do
        {
            ItoOSP(counter, C);

            hash.update(Z, zOff, zLen);
            hash.update(C, 0, C.length);
            hash.doFinal(hashBuf, 0);

            System.arraycopy(hashBuf, 0, mask, counter * defHash.length, defHash.length);
        }
        while (++counter < (length / defHash.length));

        if ((counter * defHash.length) < length)
        {
            ItoOSP(counter, C);

            hash.update(Z, zOff, zLen);
            hash.update(C, 0, C.length);
            hash.doFinal(hashBuf, 0);

            System.arraycopy(hashBuf, 0, mask, counter * defHash.length, mask.length - (counter * defHash.length));
        }

        return mask;
    
public byte[]processBlock(byte[] in, int inOff, int inLen)

        if (forEncryption)
        {
            return encodeBlock(in, inOff, inLen);
        }
        else
        {
            return decodeBlock(in, inOff, inLen);
        }