// 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;
     */
    public static byte[] sealObject(Serializable object) {
        ObjectSealer objectSealer = new ObjectSealer(config.getCipher(), config.getSecretKey());
        return objectSealer.sealObject(object);
    }

    /**
     * Parses a SealedObject from the given byte array and retrieves the original wrapped object
     *
     * @param encryptedObject a byte array representing a SealedObject
     * @return the original Serializable object
     * @throws CryptoOperationRuntimeException
     * @see #sealObject(java.io.Serializable) the matching wrapping operation
     */
    public static Object unsealObject(byte[] encryptedObject) {
        ObjectSealer objectSealer = new ObjectSealer(config.getCipher(), config.getSecretKey());
        return objectSealer.unsealObject(encryptedObject, config.getSealMaxBytes());
    }


    /**
     * Generates a strong hash from a given clear text password
     *
     * @param password the password
     * @return a String of 3 blocks: the number of iterations,
     * then the hexadecimal representation of the salt,
     * and then the hexadecimal representation of the password hash
     */
    public static String generateStrongPasswordHash(char[] password) {
        int iterations = config.getIterations();
// 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;

     */
    public static byte[] sealObject(Serializable object) {
        ObjectSealer objectSealer = new ObjectSealer(config.getCipher(), config.getSecretKey());
        return objectSealer.sealObject(object);
    }

    /**
     * Parses a SealedObject from the given byte array and retrieves the original wrapped object
     *
     * @param encryptedObject a byte array representing a SealedObject
     * @return the original Serializable object
     * @throws CryptoOperationRuntimeException
     * @see #sealObject(java.io.Serializable) the matching wrapping operation
     */
    public static Object unsealObject(byte[] encryptedObject) {
        ObjectSealer objectSealer = new ObjectSealer(config.getCipher(), config.getSecretKey());
        return objectSealer.unsealObject(encryptedObject, config.getSealMaxBytes());
    }


    /**
     * Generates a strong hash from a given clear text password
     *
     * @param password the password
     * @return a String of 3 blocks: the number of iterations,
     * then the hexadecimal representation of the salt,
     * and then the hexadecimal representation of the password hash
     */
    public static String generateStrongPasswordHash(char[] password) {
        int iterations = config.getIterations();
        byte[] salt = SaltUtils.generateSalt(SALT_SIZE_BYTES * 8);