// 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;
/**
   Copyright 2017 Carlos Macasaet

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       https://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */
package com.macasaet.fernet;




/**
 * A Fernet shared secret key.
 *
 * <p>Copyright &copy; 2017 Carlos Macasaet.</p>
 *
 * @author Carlos Macasaet
 */
@SuppressWarnings({"PMD.AvoidDuplicateLiterals", "PMD.TooManyMethods"})
public class Key {

    private final byte[] signingKey;
    private final byte[] encryptionKey;

    /**
     * Create a Key from individual components.
     *
     * @param signingKey
     *            a 128-bit (16 byte) key for signing tokens.
     * @param encryptionKey
     *            a 128-bit (16 byte) key for encrypting and decrypting token contents.
     */
    public Key(final byte[] signingKey, final byte[] encryptionKey) {
// 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;

/**
   Copyright 2017 Carlos Macasaet

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       https://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */
package com.macasaet.fernet;




/**
 * A Fernet shared secret key.
 *
 * <p>Copyright &copy; 2017 Carlos Macasaet.</p>
 *
 * @author Carlos Macasaet
 */
@SuppressWarnings({"PMD.AvoidDuplicateLiterals", "PMD.TooManyMethods"})
public class Key {

    private final byte[] signingKey;
    private final byte[] encryptionKey;

    /**
     * Create a Key from individual components.
     *
     * @param signingKey
     *            a 128-bit (16 byte) key for signing tokens.
     * @param encryptionKey
     *            a 128-bit (16 byte) key for encrypting and decrypting token contents.
     */
    public Key(final byte[] signingKey, final byte[] encryptionKey) {
        if (signingKey == null || signingKey.length != signingKeyBytes) {