/*
 * 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 javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import com.scytl.cryptolib.api.exceptions.CryptoLibException;
import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.primitives.securerandom.configuration.ConfigSecureRandomAlgorithmAndProvider;
import com.scytl.cryptolib.primitives.securerandom.configuration.SecureRandomPolicy;
import com.scytl.cryptolib.primitives.securerandom.factory.CryptoRandomBytes;
import com.scytl.cryptolib.primitives.securerandom.factory.SecureRandomFactory;
import com.scytl.cryptolib.symmetric.key.configuration.SymmetricKeyPolicy;

/**
 * A generator of secret keys to be used for HMAC.
 * <P>
 * Instances of this class are immutable.
 */
public final class CryptoSecretKeyGeneratorForHmac implements
        CryptoSecretKeyGenerator {

    private final String _hmacSecretKeyAlgorithm;

    private final int _hmacSecretKeyLength;

    private final CryptoRandomBytes _cryptoRandomBytes;

    CryptoSecretKeyGeneratorForHmac(final SymmetricKeyPolicy policy) {

        _cryptoRandomBytes =
            new SecureRandomFactory(
                buildSecureRandomPolicy(policy
                    .getSecureRandomAlgorithmAndProvider()))
                .createByteRandom();

        _hmacSecretKeyAlgorithm =
            policy.getHmacSecretKeyAlgorithmAndSpec().getAlgorithm();

        _hmacSecretKeyLength =
            (policy.getHmacSecretKeyAlgorithmAndSpec()
                .getKeyLengthInBits()) / Byte.SIZE;
    }

    @Override
    public SecretKey genSecretKey() {

        byte[] randomBytes;
        try {
            randomBytes =
                _cryptoRandomBytes.nextRandom(_hmacSecretKeyLength);
        } catch (GeneralCryptoLibException e) {
            throw new CryptoLibException(e);
        }

        return new SecretKeySpec(randomBytes, _hmacSecretKeyAlgorithm);
    }

    /**
     * Constructs a SecureRandomPolicy, which is needed to create a
     * {@link com.scytl.cryptolib.primitives.securerandom.factory}.
     * 
     * @param configSecureRandomAlgorithmAndProvider
     *            the
     *            {@link com.scytl.cryptolib.primitives.securerandom.configuration.ConfigSecureRandomAlgorithmAndProvider}
     *            that should be returned when the method
     *            {@link com.scytl.cryptolib.primitives.securerandom.configuration.SecureRandomPolicy#getSecureRandomAlgorithmAndProvider()}
     *            is called.
     * @return a new SecureRandomPolicy.
     */
    private SecureRandomPolicy buildSecureRandomPolicy(
            final ConfigSecureRandomAlgorithmAndProvider configSecureRandomAlgorithmAndProvider) {

        return new SecureRandomPolicy() {

            @Override
            public ConfigSecureRandomAlgorithmAndProvider getSecureRandomAlgorithmAndProvider() {

                return configSecureRandomAlgorithmAndProvider;
            }
        };
    }
}
