/*
 * 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.digital.envelope.service;

import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.util.Arrays;

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

import com.scytl.cryptolib.api.exceptions.GeneralCryptoLibException;
import com.scytl.cryptolib.asymmetric.utils.AsymmetricTestDataGenerator;
import com.scytl.cryptolib.digital.envelope.factory.CryptoDigitalEnvelope;
import com.scytl.cryptolib.primitives.primes.utils.PrimitivesTestDataGenerator;
import com.scytl.cryptolib.primitives.securerandom.constants.SecureRandomConstants;
import com.scytl.cryptolib.test.tools.utils.CommonTestDataGenerator;

public class DigitalEnvelopeServiceTest {

    private static final int MAXIMUM_NUMBER_ASYMMETRIC_KEY_PAIRS = 5;

    private static DigitalEnvelopeService _digitalEnvelopeServiceForDefaultPolicy;

    private static byte[] _data;

    private static PrivateKey[] _privateKeys;

    private static CryptoDigitalEnvelope _digitalEnvelope;

    private static CryptoDigitalEnvelope _digitalEnvelopeFromMultiKeys;

    @BeforeClass
    public static void setUp() throws Exception {

        Security.addProvider(new BouncyCastleProvider());

        _digitalEnvelopeServiceForDefaultPolicy =
            new DigitalEnvelopeService();

        _data = PrimitivesTestDataGenerator
            .getByteArray(CommonTestDataGenerator.getInt(1,
                SecureRandomConstants.MAXIMUM_GENERATED_BYTE_ARRAY_LENGTH));

        KeyPair[] keyPairs = AsymmetricTestDataGenerator
            .getKeyPairsForEncryption(CommonTestDataGenerator.getInt(2,
                MAXIMUM_NUMBER_ASYMMETRIC_KEY_PAIRS));
        PublicKey[] publicKeys =
            AsymmetricTestDataGenerator.extractPublicKeys(keyPairs);
        _privateKeys =
            AsymmetricTestDataGenerator.extractPrivateKeys(keyPairs);

        _digitalEnvelope = _digitalEnvelopeServiceForDefaultPolicy
            .createDigitalEnvelope(_data, publicKeys[0]);
        _digitalEnvelopeFromMultiKeys =
            _digitalEnvelopeServiceForDefaultPolicy
                .createDigitalEnvelope(_data, publicKeys);
    }

    @AfterClass
    public static void tearDown() {

        Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
    }

    @Test
    public final void whenGenerateAndOpenDigitalEnvelopeWithSingleKeyPairThenOk()
            throws GeneralCryptoLibException {

        byte[] data = _digitalEnvelopeServiceForDefaultPolicy
            .openDigitalEnvelope(_digitalEnvelope, _privateKeys[0]);

        Assert.assertTrue(Arrays.equals(data, _data));
    }

    @Test
    public final void whenGenerateAndOpenDigitalEnvelopeWithMultipleKeyPairsThenOk()
            throws GeneralCryptoLibException {

        for (PrivateKey privateKey : _privateKeys) {
            byte[] data = _digitalEnvelopeServiceForDefaultPolicy
                .openDigitalEnvelope(_digitalEnvelopeFromMultiKeys,
                    privateKey);

            Assert.assertTrue(Arrays.equals(data, _data));
        }
    }

    @Test
    public final void whenSerializeAndDeserializeSingleKeyPairDigitalEnvelopeThenOk()
            throws GeneralCryptoLibException {

        String serializedDigitalEnvelope = _digitalEnvelope.toJson();

        CryptoDigitalEnvelope deserializedDigitalEnvelope =
            CryptoDigitalEnvelope.fromJson(serializedDigitalEnvelope);

        byte[] data =
            _digitalEnvelopeServiceForDefaultPolicy.openDigitalEnvelope(
                deserializedDigitalEnvelope, _privateKeys[0]);

        Assert.assertTrue(Arrays.equals(data, _data));
    }

    @Test
    public final void whenSerializeAndDeserializeMultipleKeyPairsDigitalEnvelopeThenOk()
            throws GeneralCryptoLibException {

        String serializedDigitalEnvelope =
            _digitalEnvelopeFromMultiKeys.toJson();

        CryptoDigitalEnvelope deserializedDigitalEnvelope =
            CryptoDigitalEnvelope.fromJson(serializedDigitalEnvelope);

        for (PrivateKey privateKey : _privateKeys) {
            byte[] data = _digitalEnvelopeServiceForDefaultPolicy
                .openDigitalEnvelope(deserializedDigitalEnvelope,
                    privateKey);

            Assert.assertTrue(Arrays.equals(data, _data));
        }
    }
}
