/*
 * 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.symmetric.key.factory;

import static org.junit.Assert.assertEquals;

import java.security.Security;

import javax.crypto.SecretKey;

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

import com.scytl.cryptolib.api.exceptions.CryptoLibException;
import com.scytl.cryptolib.commons.utils.system.OperatingSystem;
import com.scytl.cryptolib.primitives.securerandom.configuration.ConfigSecureRandomAlgorithmAndProvider;
import com.scytl.cryptolib.symmetric.key.configuration.ConfigHmacSecretKeyAlgorithmAndSpec;
import com.scytl.cryptolib.symmetric.key.configuration.ConfigSecretKeyAlgorithmAndSpec;
import com.scytl.cryptolib.symmetric.key.configuration.SymmetricKeyPolicy;

public class SecretKeyGeneratorFactoryTest {

    public static SymmetricKeyPolicy _policy;

    public static SecretKeyGeneratorFactory _secretKeyGeneratorFactory;

    @BeforeClass
    public static void setUp() {

        Security.addProvider(new BouncyCastleProvider());

        _policy = getPolicy();

        _secretKeyGeneratorFactory =
            new SecretKeyGeneratorFactory(_policy);
    }

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

    @Test
    public void givenFactoryWhenCreateGeneratorAndSecretKeyThenExpectedKeyAttributes() {

        SecretKey secretKey =
            _secretKeyGeneratorFactory.createGeneratorForEncryption()
                .genSecretKey();

        String errorMsg =
            "The created secret key does not have the expected algorithm";
        assertEquals(errorMsg, "AES", secretKey.getAlgorithm());

        int expectedNumBytes = 128 / Byte.SIZE;
        errorMsg =
            "The created secret key does not have the expected length";
        assertEquals(errorMsg, expectedNumBytes,
            secretKey.getEncoded().length);
    }

    @Test
    public void givenFactoryWhenCreateGeneratorAndHmacSecretKeyThenExpectedKeyAttributes() {

        SecretKey secretKey =
            _secretKeyGeneratorFactory.createGeneratorForHmac()
                .genSecretKey();

        String errorMsg =
            "The created secret key does not have the expected algorithm";
        assertEquals(errorMsg, "HmacSHA256", secretKey.getAlgorithm());

        int expectedNumBytes = 256 / Byte.SIZE;
        errorMsg =
            "The created secret key does not have the expected length";
        assertEquals(errorMsg, expectedNumBytes,
            secretKey.getEncoded().length);
    }

    private static SymmetricKeyPolicy getPolicy() {

        return new SymmetricKeyPolicy() {

            @Override
            public ConfigSecretKeyAlgorithmAndSpec getSecretKeyAlgorithmAndSpec() {
                return ConfigSecretKeyAlgorithmAndSpec.AES_128_BC;
            }

            @Override
            public ConfigSecureRandomAlgorithmAndProvider getSecureRandomAlgorithmAndProvider() {
                return getSecureRandomConfig();
            }

            @Override
            public ConfigHmacSecretKeyAlgorithmAndSpec getHmacSecretKeyAlgorithmAndSpec() {
                return ConfigHmacSecretKeyAlgorithmAndSpec.HMACwithSHA256_256;
            }
        };
    }

    private static ConfigSecureRandomAlgorithmAndProvider getSecureRandomConfig() {

        switch (OperatingSystem.current()) {

        case WINDOWS:
            return ConfigSecureRandomAlgorithmAndProvider.PRNG_SUN_MSCAPI;
        case LINUX:
            return ConfigSecureRandomAlgorithmAndProvider.NATIVE_PRNG_SUN;
        default:
            throw new CryptoLibException("OS not supported");
        }
    }
}
