// Path: fernet-java8/src/main/java/com/macasaet/fernet/Constants.java
// static final String cipherTransformation = encryptionAlgorithm + "/CBC/PKCS5Padding";
// 
// Path: fernet-java8/src/main/java/com/macasaet/fernet/Constants.java
// static final Decoder decoder = getUrlDecoder();
// 
// Path: fernet-java8/src/main/java/com/macasaet/fernet/Constants.java
// static final Encoder encoder = getUrlEncoder();
// 
// Path: fernet-java8/src/main/java/com/macasaet/fernet/Constants.java
// static final String encryptionAlgorithm = "AES";
// 
// Path: fernet-java8/src/main/java/com/macasaet/fernet/Constants.java
// static final int encryptionKeyBytes = 16;
// 
// Path: fernet-java8/src/main/java/com/macasaet/fernet/Constants.java
// static final int fernetKeyBytes = signingKeyBytes + encryptionKeyBytes;
// 
// Path: fernet-java8/src/main/java/com/macasaet/fernet/Constants.java
// static final String signingAlgorithm = "HmacSHA256";
// 
// Path: fernet-java8/src/main/java/com/macasaet/fernet/Constants.java
// static final int signingKeyBytes = 16;
// 
// Path: fernet-java8/src/main/java/com/macasaet/fernet/Constants.java
// static final int tokenPrefixBytes = versionBytes + timestampBytes + initializationVectorBytes;


import static com.macasaet.fernet.Constants.cipherTransformation;
import static com.macasaet.fernet.Constants.decoder;
import static com.macasaet.fernet.Constants.encoder;
import static com.macasaet.fernet.Constants.encryptionAlgorithm;
import static com.macasaet.fernet.Constants.encryptionKeyBytes;
import static com.macasaet.fernet.Constants.fernetKeyBytes;
import static com.macasaet.fernet.Constants.signingAlgorithm;
import static com.macasaet.fernet.Constants.signingKeyBytes;
import static com.macasaet.fernet.Constants.tokenPrefixBytes;
import static java.util.Arrays.copyOf;
import static java.util.Arrays.copyOfRange;
import static javax.crypto.Cipher.DECRYPT_MODE;
import static javax.crypto.Cipher.ENCRYPT_MODE;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.time.Instant;
import java.util.Arrays;
import java.util.Base64.Encoder;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.Mac;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
     *            the seconds after the epoch that the token was generated
     * @param initializationVector
     *            the encryption and decryption initialization vector
     * @param cipherText
     *            the encrypted content of the token
     * @return the HMAC signature
     */
    public byte[] sign(final byte version, final Instant timestamp, final IvParameterSpec initializationVector,
            final byte[] cipherText) {
        try (ByteArrayOutputStream byteStream = new ByteArrayOutputStream(
                getTokenPrefixBytes() + cipherText.length)) {
            return sign(version, timestamp, initializationVector, cipherText, byteStream);
        } catch (final IOException e) {
            // this should not happen as I/O is to memory only
            throw new IllegalStateException(e.getMessage(), e);
        }
    }

    /**
     * Encrypt a payload to embed in a Fernet token
     *
     * @param payload the raw bytes of the data to store in a token
     * @param initializationVector random bytes from a high-entropy source to initialise the AES cipher
     * @return the AES-encrypted payload. The length will always be a multiple of 16 (128 bits).
     * @see #decrypt(byte[], IvParameterSpec)
     */
    @SuppressWarnings("PMD.LawOfDemeter")
    public byte[] encrypt(final byte[] payload, final IvParameterSpec initializationVector) {
        final SecretKeySpec encryptionKeySpec = getEncryptionKeySpec();
        try {
// Path: fernet-java8/src/main/java/com/macasaet/fernet/Constants.java
// static final String cipherTransformation = encryptionAlgorithm + "/CBC/PKCS5Padding";
// 
// Path: fernet-java8/src/main/java/com/macasaet/fernet/Constants.java
// static final Decoder decoder = getUrlDecoder();
// 
// Path: fernet-java8/src/main/java/com/macasaet/fernet/Constants.java
// static final Encoder encoder = getUrlEncoder();
// 
// Path: fernet-java8/src/main/java/com/macasaet/fernet/Constants.java
// static final String encryptionAlgorithm = "AES";
// 
// Path: fernet-java8/src/main/java/com/macasaet/fernet/Constants.java
// static final int encryptionKeyBytes = 16;
// 
// Path: fernet-java8/src/main/java/com/macasaet/fernet/Constants.java
// static final int fernetKeyBytes = signingKeyBytes + encryptionKeyBytes;
// 
// Path: fernet-java8/src/main/java/com/macasaet/fernet/Constants.java
// static final String signingAlgorithm = "HmacSHA256";
// 
// Path: fernet-java8/src/main/java/com/macasaet/fernet/Constants.java
// static final int signingKeyBytes = 16;
// 
// Path: fernet-java8/src/main/java/com/macasaet/fernet/Constants.java
// static final int tokenPrefixBytes = versionBytes + timestampBytes + initializationVectorBytes;


// Path: fernet-java8/src/main/java/com/macasaet/fernet/Key.java
import static com.macasaet.fernet.Constants.cipherTransformation;
import static com.macasaet.fernet.Constants.decoder;
import static com.macasaet.fernet.Constants.encoder;
import static com.macasaet.fernet.Constants.encryptionAlgorithm;
import static com.macasaet.fernet.Constants.encryptionKeyBytes;
import static com.macasaet.fernet.Constants.fernetKeyBytes;
import static com.macasaet.fernet.Constants.signingAlgorithm;
import static com.macasaet.fernet.Constants.signingKeyBytes;
import static com.macasaet.fernet.Constants.tokenPrefixBytes;
import static java.util.Arrays.copyOf;
import static java.util.Arrays.copyOfRange;
import static javax.crypto.Cipher.DECRYPT_MODE;
import static javax.crypto.Cipher.ENCRYPT_MODE;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.time.Instant;
import java.util.Arrays;
import java.util.Base64.Encoder;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.Mac;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

     *            the seconds after the epoch that the token was generated
     * @param initializationVector
     *            the encryption and decryption initialization vector
     * @param cipherText
     *            the encrypted content of the token
     * @return the HMAC signature
     */
    public byte[] sign(final byte version, final Instant timestamp, final IvParameterSpec initializationVector,
            final byte[] cipherText) {
        try (ByteArrayOutputStream byteStream = new ByteArrayOutputStream(
                getTokenPrefixBytes() + cipherText.length)) {
            return sign(version, timestamp, initializationVector, cipherText, byteStream);
        } catch (final IOException e) {
            // this should not happen as I/O is to memory only
            throw new IllegalStateException(e.getMessage(), e);
        }
    }

    /**
     * Encrypt a payload to embed in a Fernet token
     *
     * @param payload the raw bytes of the data to store in a token
     * @param initializationVector random bytes from a high-entropy source to initialise the AES cipher
     * @return the AES-encrypted payload. The length will always be a multiple of 16 (128 bits).
     * @see #decrypt(byte[], IvParameterSpec)
     */
    @SuppressWarnings("PMD.LawOfDemeter")
    public byte[] encrypt(final byte[] payload, final IvParameterSpec initializationVector) {
        final SecretKeySpec encryptionKeySpec = getEncryptionKeySpec();
        try {
            final Cipher cipher = Cipher.getInstance(cipherTransformation);