package org.bouncycastle.crypto.test;

import java.security.SecureRandom;

import org.bouncycastle.crypto.engines.DESEngine;
import org.bouncycastle.crypto.paddings.BlockCipherPadding;
import org.bouncycastle.crypto.paddings.ISO10126d2Padding;
import org.bouncycastle.crypto.paddings.PKCS7Padding;
import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
import org.bouncycastle.crypto.paddings.X923Padding;
import org.bouncycastle.crypto.paddings.ZeroBytePadding;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTestResult;
import org.bouncycastle.util.test.Test;
import org.bouncycastle.util.test.TestResult;

/**
 * General Padding tests.
 */
public class PaddingTest
    implements Test
{
    public PaddingTest()
    {
    }

    private boolean isEqualTo(
        byte[]  a,
        byte[]  b)
    {
        for (int i = 0; i != a.length; i++)
        {
            if (a[i] != b[i])
            {
                return false;
            }
        }

        return true;
    }

	public TestResult testPadding(
		BlockCipherPadding	padding,
		SecureRandom			rand)
	{
		PaddedBufferedBlockCipher	cipher = new PaddedBufferedBlockCipher(new DESEngine(), padding);
		KeyParameter    					key = new KeyParameter(Hex.decode("0011223344556677"));
		
		try
		{
			for (int i = 1; i != 20; i++)
			{
				byte[]	data = new byte[i];
				byte[]	out = new byte[data.length + 8];
				byte[]	dec = new byte[i];
				
				rand.nextBytes(data);
				
				cipher.init(true, key);
				
				int	len = cipher.processBytes(data, 0, data.length, out, 0);
				
				len += cipher.doFinal(out, len);
				
				cipher.init(false, key);
				
				int	decLen = cipher.processBytes(out, 0, len, dec, 0);
				
				decLen += cipher.doFinal(dec, decLen);
				
				if (!isEqualTo(data, dec))
				{
					return new SimpleTestResult(false, getName() + ": falied to decrypt - i = " + i + ", padding = " + padding.getPaddingName());
				}
			}
		}
		catch (Exception e)
		{
			return new SimpleTestResult(false, getName() + ": Exception - " + e.toString(), e);
		}
		
		return new SimpleTestResult(true, getName() + ": Okay");
	}
	
    public TestResult perform()
    {
    	SecureRandom	rand = new SecureRandom(new byte[20]);
    	
    	rand.setSeed(System.currentTimeMillis());
    	
		TestResult	res = testPadding(new PKCS7Padding(), rand);
        if (!res.isSuccessful())
        {
        	return res;
        }

		res = testPadding(new ISO10126d2Padding(), rand);
		if (!res.isSuccessful())
		{
			return res;
		}
		
		res = testPadding(new X923Padding(), rand);
		if (!res.isSuccessful())
		{
			return res;
		}
		
		res = testPadding(new ZeroBytePadding(), rand);
		if (!res.isSuccessful())
		{
			return res;
		}
		
        return new SimpleTestResult(true, getName() + ": Okay");
    }

    public String getName()
    {
        return "PaddingTest";
    }

    public static void main(
        String[]    args)
    {
        PaddingTest    test = new PaddingTest();
        TestResult result = test.perform();

        System.out.println(result);
    }
}
