/*
 * Copyright 2018 Scytl Secure Electronic Voting SA
 *
 * All rights reserved
 *
 * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
 */
package com.scytl.cryptolib.primitives.derivation.factory;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

import java.security.Security;

import javax.xml.bind.DatatypeConverter;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.derivation.cryptoapi.CryptoAPIDerivedKey;
import com.scytl.cryptolib.primitives.derivation.configuration.ConfigKDFDerivationParameters;
import com.scytl.cryptolib.primitives.derivation.configuration.ConfigPBKDFDerivationParameters;
import com.scytl.cryptolib.primitives.derivation.configuration.DerivationPolicy;
import com.scytl.cryptolib.primitives.securerandom.configuration.ConfigSecureRandomAlgorithmAndProvider;

public class CryptoKDFDeriverTest {

    private static final String SEED_AS_HEX = "deadbeeffeebdaed";

    private static final int KEY_BYTE_LENGTH = 32;

    private static final String EXPECTED_DERIVED_KEY_AS_HEX =
        "2a598c866ba1914fbf19f9528c1a676936a1567dd27c51cd3bf4a561c60be610";

    private final CryptoKeyDeriverFactory _cryptoKeyDeriverFactory =
        new CryptoKeyDeriverFactory(getKeyDerivationPolicy());

    @BeforeClass
    public static void setUp() {
        Security.addProvider(new BouncyCastleProvider());
    }

    @AfterClass
    public static void removeBouncyCastleProvider() {
        Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
    }

    @Test
    public void testThatDerivesKeyForKDF2SHA256BCProviderKL128()
            throws GeneralCryptoLibException {

        CryptoKDFDeriver cryptoKDFDeriver =
            _cryptoKeyDeriverFactory.createKDFDeriver();

        CryptoAPIDerivedKey cryptoKDFDerivedKey;
        cryptoKDFDerivedKey = cryptoKDFDeriver.deriveKey(
            DatatypeConverter.parseHexBinary(SEED_AS_HEX), KEY_BYTE_LENGTH);

        String derivedKeyAsHex = DatatypeConverter
            .printHexBinary(cryptoKDFDerivedKey.getEncoded()).toLowerCase();

        assertNotNull(cryptoKDFDerivedKey);
        assertEquals(KEY_BYTE_LENGTH, cryptoKDFDerivedKey.getEncoded().length);
        assertEquals(EXPECTED_DERIVED_KEY_AS_HEX, derivedKeyAsHex);
    }

    @Test
    public void createCryptoKDFDeriverTest()
            throws GeneralCryptoLibException {
        CryptoKDFDeriver cryptoKDFDeriver = new CryptoKDFDeriver(ConfigKDFDerivationParameters.MGF1_SHA256_BC);
        assertNotNull(cryptoKDFDeriver);
    }

    private DerivationPolicy getKeyDerivationPolicy() {
        return new DerivationPolicy() {

            @Override
            public ConfigKDFDerivationParameters getKDFDerivationParameters() {
                return ConfigKDFDerivationParameters.MGF1_SHA256_BC;
            }

            @Override
            public ConfigPBKDFDerivationParameters getPBKDFDerivationParameters() {
                return ConfigPBKDFDerivationParameters.PBKDF2_32000_SHA256_256_BC_KL128;
            }

            @Override
            public ConfigSecureRandomAlgorithmAndProvider getSecureRandomAlgorithmAndProvider() {
                return ConfigSecureRandomAlgorithmAndProvider.NATIVE_PRNG_SUN;
            }
        };
    }
}
