package org.bouncycastle.crypto.prng.test;

import java.security.SecureRandom;

import org.bouncycastle.crypto.engines.AESEngine;
import org.bouncycastle.crypto.engines.DESedeEngine;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.crypto.prng.X931SecureRandomBuilder;
import org.bouncycastle.util.Arrays;
import org.bouncycastle.util.Strings;
import org.bouncycastle.util.encoders.Hex;
import org.bouncycastle.util.test.SimpleTest;

/**
 * HMAC SP800-90 DRBG
 */
public class X931Test
    extends SimpleTest
{
    public String getName()
    {
        return "X931";
    }

    public static void main(String[] args)
    {
        runTest(new X931Test());
    }

    private X931TestVector[] createTestVectorData()
    {
        return new X931TestVector[]
            {
                new X931TestVector(
                    AESEngine.newInstance(),
                    new AES128EntropyProvider(),
                    "f7d36762b9915f1ed585eb8e91700eb2",
                    "259e67249288597a4d61e7c0e690afae",
                    false,
                    new String[] {
                        "15f013af5a8e9df9a8e37500edaeac43",
                        "a9d74bb1c90a222adc398546d64879cf",
                        "0379e404042d58180764fb9e6c5d94bb",
                        "3c74603e036d28c79947ffb56fee4e51",
                        "e872101a4df81ebbe1e632fc87195d52",
                        "26a6b3d33b8e7e68b75d9630ec036314" }),
                new X931TestVector(
                    new DESedeEngine(),
                    new TDESEntropyProvider(),
                    "ef16ec643e5db5892cbc6eabba310b3410e6f8759e3e382c",
                    "55df103deaf68dc4",
                    false,
                    new String[] {
                        "9c960bb9662ce6de",
                        "d9d0e527fd0931da",
                        "3e2db9994e9e6995",
                        "0e3868aef8218cf7",
                        "7b0b0ca137f8fd81",
                        "f657df270ad12265" })
            };
    }

    public void performTest()
        throws Exception
    {
        X931TestVector[] vectors = createTestVectorData();

        for (int i = 0; i != vectors.length; i++)
        {
            X931TestVector tv = vectors[i];
            X931SecureRandomBuilder bld = new X931SecureRandomBuilder(tv.getEntropyProvider());

            bld.setDateTimeVector(Hex.decode(tv.getDateTimeVector()));

            SecureRandom rand = bld.build(tv.getEngine(), new KeyParameter(Hex.decode(tv.getKey())), tv.isPredictionResistant());

            for (int j = 0; j != tv.getExpected().length - 1; j++)
            {
                byte[] expected = Hex.decode(tv.getExpected()[j]);
                byte[] res = new byte[expected.length];

                rand.nextBytes(res);

                if (!Arrays.areEqual(expected, res))
                {
                    fail("expected output wrong [" + j + "] got : " + Strings.fromByteArray(Hex.encode(res)));
                }
            }

            byte[] expected = Hex.decode(tv.getExpected()[tv.getExpected().length - 1]);
            byte[] res = new byte[expected.length];

            for (int j = tv.getExpected().length - 1; j != 10000; j++)
            {
                rand.nextBytes(res);
            }

            if (!Arrays.areEqual(expected, res))
            {
                fail("expected output wrong [" + 10000 + "] got : " + Strings.fromByteArray(Hex.encode(res)));
            }
        }
    }

    private static class AES128EntropyProvider
        extends TestEntropySourceProvider
    {
        AES128EntropyProvider()
        {
            super(Hex.decode(
                "35cc0ea481fc8a4f5f05c7d4667233b2"), true);
        }
    }

    private static class TDESEntropyProvider
        extends TestEntropySourceProvider
    {
        TDESEntropyProvider()
        {
            super(Hex.decode(
                "96d872b9122c5e74"), true);
        }
    }
}
