// Path: commons-base/commons-crypto/src/main/java/ch/ge/ve/commons/crypto/exceptions/CryptoOperationRuntimeException.java
// public class CryptoOperationRuntimeException extends RuntimeException {
//     public CryptoOperationRuntimeException(String message) {
//         super(message);
//     }
// 
//     public CryptoOperationRuntimeException(String message, Throwable cause) {
//         super(message, cause);
//     }
// 
//     public CryptoOperationRuntimeException(Throwable cause) {
//         super(cause);
//     }
// 
//     public CryptoOperationRuntimeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
//         super(message, cause, enableSuppression, writableStackTrace);
//     }
// }
// 
// Path: commons-base/commons-crypto/src/main/java/ch/ge/ve/commons/crypto/utils/SaltUtils.java
// public class SaltUtils {
//     private static final SecureRandom SECURE_RANDOM = SecureRandomFactory.createPRNG();
// 
//     // Mask default constructor, this class should not be instantiated
//     private SaltUtils() {}
// 
//     /**
//      * Generates a salt using Java SecureRandom
//      *
//      * @param lengthInBits desired length of the salt
//      * @return the salt
//      */
//     public static byte[] generateSalt(int lengthInBits) {
//         Preconditions.checkArgument(lengthInBits % 8 == 0, String.format("The salt length must be a multiple of 8, but was %d!", lengthInBits));
//         byte[] salt = new byte[lengthInBits / 8];
//         SECURE_RANDOM.nextBytes(salt);
//         return salt;
//     }
// }
// 
// Path: commons-base/commons-crypto/src/main/java/ch/ge/ve/commons/crypto/utils/SecureRandomFactory.java
// public class SecureRandomFactory {
//     // Mask default constructor, this class shouldn't be instantiated
//     private SecureRandomFactory() {}
// 
//     /**
//      * Important notice from the SecureRandom javadoc:
//      * <p>The returned SecureRandom object has not been seeded. To seed the
//      * returned object, call the <code>setSeed</code> method.
//      * If <code>setSeed</code> is not called, the first call to
//      * <code>nextBytes</code> will force the SecureRandom object to seed itself.
//      * This self-seeding will not occur if <code>setSeed</code> was
//      * previously called.</p>
//      *
//      * @return a new, not already seeded, Pseudo Random Number Generator instance.
//      */
//     public static SecureRandom createPRNG() {
//         try {
//             return SecureRandom.getInstance("SHA1PRNG", "SUN");
//         } catch (NoSuchAlgorithmException | NoSuchProviderException e) {
//             throw new CryptoConfigurationRuntimeException("Error creating PRNG", e);
//         }
//     }
// 
// }


import ch.ge.ve.commons.crypto.exceptions.CryptoOperationRuntimeException;
import ch.ge.ve.commons.crypto.utils.SaltUtils;
import ch.ge.ve.commons.crypto.utils.SecureRandomFactory;
import com.google.common.base.Preconditions;
import com.google.common.primitives.Bytes;
import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.io.Serializable;
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.util.Arrays;
import java.util.Base64;
    /**
     * Computes a salted MAC of the input
     *
     * @param input any string
     * @param salt  the salt to be used by the MAC
     * @return the MAC (using algorithm defined in the {@link #config}) of the input string, using the provided salt
     */
    public static byte[] buildMAC(String input, byte[] salt) {
        return buildMAC(input.getBytes(), salt);
    }

    /**
     * Computes a salted MAC of the input
     *
     * @param input any byte array
     * @param salt  the salt to be used by the MAC
     * @return the MAC (using algorithm defined in the {@link #config}) of the input byte array, using the provided salt
     */
    public static byte[] buildMAC(byte[] input, byte[] salt) {
        try {
            Mac mac = config.getMac();
            mac.init(config.getSecretKey());
            if (salt != null) {
                mac.update(salt);
                final byte[] macText = mac.doFinal(input);
                return Bytes.concat(salt, macText);
            } else {
                return mac.doFinal(input);
            }
        } catch (GeneralSecurityException e) {
// Path: commons-base/commons-crypto/src/main/java/ch/ge/ve/commons/crypto/exceptions/CryptoOperationRuntimeException.java
// public class CryptoOperationRuntimeException extends RuntimeException {
//     public CryptoOperationRuntimeException(String message) {
//         super(message);
//     }
// 
//     public CryptoOperationRuntimeException(String message, Throwable cause) {
//         super(message, cause);
//     }
// 
//     public CryptoOperationRuntimeException(Throwable cause) {
//         super(cause);
//     }
// 
//     public CryptoOperationRuntimeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
//         super(message, cause, enableSuppression, writableStackTrace);
//     }
// }
// 
// Path: commons-base/commons-crypto/src/main/java/ch/ge/ve/commons/crypto/utils/SaltUtils.java
// public class SaltUtils {
//     private static final SecureRandom SECURE_RANDOM = SecureRandomFactory.createPRNG();
// 
//     // Mask default constructor, this class should not be instantiated
//     private SaltUtils() {}
// 
//     /**
//      * Generates a salt using Java SecureRandom
//      *
//      * @param lengthInBits desired length of the salt
//      * @return the salt
//      */
//     public static byte[] generateSalt(int lengthInBits) {
//         Preconditions.checkArgument(lengthInBits % 8 == 0, String.format("The salt length must be a multiple of 8, but was %d!", lengthInBits));
//         byte[] salt = new byte[lengthInBits / 8];
//         SECURE_RANDOM.nextBytes(salt);
//         return salt;
//     }
// }
// 
// Path: commons-base/commons-crypto/src/main/java/ch/ge/ve/commons/crypto/utils/SecureRandomFactory.java
// public class SecureRandomFactory {
//     // Mask default constructor, this class shouldn't be instantiated
//     private SecureRandomFactory() {}
// 
//     /**
//      * Important notice from the SecureRandom javadoc:
//      * <p>The returned SecureRandom object has not been seeded. To seed the
//      * returned object, call the <code>setSeed</code> method.
//      * If <code>setSeed</code> is not called, the first call to
//      * <code>nextBytes</code> will force the SecureRandom object to seed itself.
//      * This self-seeding will not occur if <code>setSeed</code> was
//      * previously called.</p>
//      *
//      * @return a new, not already seeded, Pseudo Random Number Generator instance.
//      */
//     public static SecureRandom createPRNG() {
//         try {
//             return SecureRandom.getInstance("SHA1PRNG", "SUN");
//         } catch (NoSuchAlgorithmException | NoSuchProviderException e) {
//             throw new CryptoConfigurationRuntimeException("Error creating PRNG", e);
//         }
//     }
// 
// }


// Path: commons-base/commons-crypto/src/main/java/ch/ge/ve/commons/crypto/SensitiveDataCryptoUtils.java
import ch.ge.ve.commons.crypto.exceptions.CryptoOperationRuntimeException;
import ch.ge.ve.commons.crypto.utils.SaltUtils;
import ch.ge.ve.commons.crypto.utils.SecureRandomFactory;
import com.google.common.base.Preconditions;
import com.google.common.primitives.Bytes;
import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.io.Serializable;
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.util.Arrays;
import java.util.Base64;

    /**
     * Computes a salted MAC of the input
     *
     * @param input any string
     * @param salt  the salt to be used by the MAC
     * @return the MAC (using algorithm defined in the {@link #config}) of the input string, using the provided salt
     */
    public static byte[] buildMAC(String input, byte[] salt) {
        return buildMAC(input.getBytes(), salt);
    }

    /**
     * Computes a salted MAC of the input
     *
     * @param input any byte array
     * @param salt  the salt to be used by the MAC
     * @return the MAC (using algorithm defined in the {@link #config}) of the input byte array, using the provided salt
     */
    public static byte[] buildMAC(byte[] input, byte[] salt) {
        try {
            Mac mac = config.getMac();
            mac.init(config.getSecretKey());
            if (salt != null) {
                mac.update(salt);
                final byte[] macText = mac.doFinal(input);
                return Bytes.concat(salt, macText);
            } else {
                return mac.doFinal(input);
            }
        } catch (GeneralSecurityException e) {
            throw new CryptoOperationRuntimeException(e);