/*
 * Copyright 2006-2020 DLR, Germany
 * 
 * SPDX-License-Identifier: EPL-1.0
 * 
 * https://rcenvironment.de/
 */

package de.rcenvironment.core.authorization.cryptography.api;

import de.rcenvironment.core.utils.common.exception.OperationFailureException;

/**
 * An interface (SPI) for providers of basic cryptographic features, like key generation, hashing, signing, and encryption. It also includes
 * common conversions, especially between binary data and transport-safe string formats.
 * <p>
 * Currently, generated symmetric keys are AES-256, marked as internal version "1". This requires a JRE >= 8u161, as AES-256 was not
 * available by default in previous Oracle JRE releases.
 *
 * @author Robert Mischke
 */
public interface CryptographyOperationsProvider {

    /**
     * The bit length of a new symmetric keys generated by {@link #generateSymmetricKey()}.
     */
    int SYMMETRIC_KEY_NATIVE_BIT_LENGTH = 256; // requires JRE >= 8u161

    /**
     * The length of the byte array representation of new symmetric keys generated by {@link #generateSymmetricKey()}.
     */
    int SYMMETRIC_KEY_NATIVE_BYTE_LENGTH = SYMMETRIC_KEY_NATIVE_BIT_LENGTH / 8;

    /**
     * The version identifier of new symmetric keys generated by {@link #generateSymmetricKey()}. Older key versions may still be able to be
     * parsed in the future. Note that there is no separator at this time; we can add one once (if ever) we go beyond key version 9...
     */
    String SYMMETRIC_KEY_CURRENT_VERSION_PREFIX = "1:";

    /**
     * Base64 length of (256/8 = 32) bytes = 43 chars + prefix length.
     */
    int SYMMETRIC_KEY_EXPECTED_ENCODED_LENGTH = 43 + SYMMETRIC_KEY_CURRENT_VERSION_PREFIX.length();

    /**
     * @return a new symmetric key; currently, AES-256
     * @throws OperationFailureException on failure, e.g. cryptography library errors, or policy restrictions
     */
    SymmetricKey generateSymmetricKey() throws OperationFailureException;

    /**
     * @param key the symmetric key to encrypt with
     * @param input the input to encrypt
     * @return the ciphertext
     * @throws OperationFailureException on failure, e.g. cryptography library errors, or an invalid key
     */
    byte[] encrypt(SymmetricKey key, byte[] input) throws OperationFailureException;

    /**
     * Convenience method chaining encrypt() and encode().
     * 
     * @param key the symmetric key to encrypt with
     * @param input the input to encrypt
     * @return the encoded ciphertext
     * @throws OperationFailureException on failure, e.g. cryptography library errors, or an invalid key
     */
    String encryptAndEncodeByteArray(SymmetricKey key, byte[] input) throws OperationFailureException;

    /**
     * Convenience method chaining encrypt() and encode() on the UTF-8 bytes of the given string.
     * 
     * @param key the symmetric key to encrypt with
     * @param input the input to encrypt
     * @return the encoded ciphertext
     * @throws OperationFailureException on failure, e.g. cryptography library errors, or an invalid key
     */
    String encryptAndEncodeString(SymmetricKey key, String input) throws OperationFailureException;

    /**
     * @param key the symmetric key to decrypt with
     * @param input the input to decrypt
     * @return the restored plaintext
     * @throws OperationFailureException on failure, e.g. cryptography library errors, or an invalid key
     */
    byte[] decrypt(SymmetricKey key, byte[] input) throws OperationFailureException;

    /**
     * Convenience method chaining decode() and decrypt().
     * 
     * @param key the symmetric key to encrypt with
     * @param input the input to encrypt
     * @return the restored plaintext
     * @throws OperationFailureException on failure, e.g. cryptography library errors, or an invalid key
     */
    byte[] decodeAndDecryptByteArray(SymmetricKey key, String input) throws OperationFailureException;

    /**
     * Convenience method chaining decode() and decrypt() and transforming the resulting bytes back into an UTF-8 string.
     * 
     * @param key the symmetric key to encrypt with
     * @param input the input to decrypt
     * @return the restored plaintext
     * @throws OperationFailureException on failure, e.g. cryptography library errors, or an invalid key
     */
    String decodeAndDecryptString(SymmetricKey key, String input) throws OperationFailureException;

    /**
     * @param input the transport-safe string representation
     * @return the restored byte array
     */
    String encodeByteArray(byte[] input);

    /**
     * @param input the byte array
     * @return a transport-safe string representation
     */
    byte[] decodeByteArray(String input);

    /**
     * Note that this method is not strictly necessary because of {@link SymmetricKey#getEncodedForm()}; it is provided for API symmetry.
     * 
     * @param key the symmetric key
     * @return a transport-safe string representation
     */
    String encodeSymmetricKey(SymmetricKey key);

    /**
     * @param input the transport-safe string representation
     * @return the restored symmetric key
     * @throws OperationFailureException on invalid key data
     */
    SymmetricKey decodeSymmetricKey(String input) throws OperationFailureException;
}
