/*
 * 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.slogger.crypto;

import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;

import javax.crypto.SecretKey;

/**
 * Common methods that are to be implemented to provide the needed cryptography to the secure
 * logger.
 */
public interface SecureLoggerCryptographyProvider {

  /**
   * Decrypts the given data with an asymmetric private key.
   *
   * @param data the data
   * @param privateKey the key
   * @return the decrypted data
   * @throws GeneralSecurityException failed to decrypt the data.
   */

  byte[] asymmetricDecrypt(final byte[] data, final PrivateKey privateKey)
      throws GeneralSecurityException;

  /**
   * Encrypts the given data with an asymmetric public key.
   *
   * @param data the data
   * @param publicKey the key
   * @return the encrypted data
   * @throws GeneralSecurityException failed to encrypt the data.
   */

  byte[] asymmetricEncrypt(final byte[] data, final PublicKey publicKey)
      throws GeneralSecurityException;

  /**
   * Generates a new symmetric key for the application.
   *
   * @return the secret key.
   */
  SecretKey generateSymmetricKey() throws GeneralSecurityException;

  /**
   * Generates a symmetric key for the application with the provided data.
   *
   * @param key the key bytes
   * @return the key.
   */
  SecretKey generateSymmetricKey(final byte[] key) throws GeneralSecurityException;

  /**
   * Generates a MAC for the given data, using the given {@link javax.crypto.SecretKey}.
   *
   * @param key the {@link javax.crypto.SecretKey} to use.
   * @param data the message to be authenticated.
   * @return the generated message MAC.
   * @throws GeneralSecurityException the MAC generation fails.
   */
  byte[] getMac(final SecretKey key, final byte[]... data) throws GeneralSecurityException;

  /**
   * Returns the unique private key of a given cipher keystore.
   *
   * @param keystore the key store
   * @param password the password
   * @return the key
   * @throws GeneralSecurityException failed to get the key.
   */
  PrivateKey getUserCipherPrivateKey(final SecureLoggerKeyStore keystore, final char[] password)
      throws GeneralSecurityException;

  /**
   * Returns the unique public key of a given cipher keystore.
   *
   * @param keystore the key store
   * @return the key
   * @throws GeneralSecurityException failed to get the key.
   */
  PublicKey getUserCipherPublicKey(final SecureLoggerKeyStore keystore)
      throws GeneralSecurityException;

  /**
   * Returns the unique private key of a given singing keystore.
   *
   * @param keystore the key store
   * @param password the password
   * @return the key
   * @throws GeneralSecurityException failed to get the key.
   */
  PrivateKey getUserSignaturePrivateKey(final SecureLoggerKeyStore keystore, final char[] password)
      throws GeneralSecurityException;

  /**
   * Returns the unique public key of a given singing keystore.
   *
   * @param keystore the key store
   * @return the key
   * @throws GeneralSecurityException failed to get the key.
   */
  PublicKey getUserSignaturePublicKey(final SecureLoggerKeyStore keystore)
      throws GeneralSecurityException;

  /**
   * Inits the required resources for further calls.
   *
   * @throws GeneralSecurityException failed to initialize the provider.
   */
  void init() throws GeneralSecurityException;

  /**
   * Reads a certificate from a given certificate input stream.
   *
   * @param is the stream
   * @return the certificate
   * @throws GeneralSecurityException failed to read the certificate.
   */
  Certificate readCertificate(final InputStream is) throws GeneralSecurityException;

  /**
   * Reads a keystore from a given input stream and stores it into the cryptography provider for
   * further usage.
   *
   * @param is the stream
   * @param password the password
   * @return the key store
   * @throws IOException I/O error occurred
   * @throws GeneralSecurityException failed to read the key store.
   */

  SecureLoggerKeyStore readKeyStore(final InputStream is, final char[] password)
      throws IOException, GeneralSecurityException;

  /**
   * Signs the given data with an asymmetric private key.
   *
   * @param data tha data
   * @param privateKey the key
   * @return the signature
   * @throws GeneralSecurityException failed to sign the data.
   */
  byte[] sign(final byte[] data, final PrivateKey privateKey) throws GeneralSecurityException;

  /**
   * Verifies a signature.
   *
   * @param data the data
   * @param signature the signature
   * @param publicKey the key
   * @return the signature is correct
   * @throws GeneralSecurityException failed to verify the signature.
   */
  boolean verify(final byte[] data, final byte[] signature, PublicKey publicKey)
      throws GeneralSecurityException;

  /**
   * Verifies that a given MAC is indeed the MAC for the given data, using the given
   * {@link javax.crypto.SecretKey}.
   *
   * @param key the {@link javax.crypto.SecretKey} to use.
   * @param mac the MAC to be verified.
   * @param data the message to be authenticated.
   * @return true if the MAC is the MAC of the given data and SecretKey, false otherwise.
   * @throws GeneralSecurityException MAC verification process fails.
   */
  boolean verifyMac(final SecretKey key, final byte[] mac, final byte[]... data)
      throws GeneralSecurityException;
}
