// Path: src/main/java/trabe/AbeDecryptionException.java
// public class AbeDecryptionException extends DecryptionException {
// 
// 	private static final long serialVersionUID = 2848983353356933397L;
// 
// 	public AbeDecryptionException(String msg) {
// 		super(msg);
// 	}
// 
// 	public AbeDecryptionException(String msg, Throwable t) {
// 		super(msg, t);
// 	}
// }
// 
// Path: src/main/java/trabe/AbeEncryptionException.java
// public class AbeEncryptionException extends GeneralSecurityException {
// 
//     private static final long serialVersionUID = 1043863535572140323L;
// 
//     public AbeEncryptionException(String msg) {
//         super(msg);
//     }
//     
//     public AbeEncryptionException(String msg, Throwable t) {
//         super(msg, t);
//     }
// 
// }


import java.io.*;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import trabe.AbeDecryptionException;
import trabe.AbeEncryptionException;

    
    static {
    	//Security.addProvider(new BouncyCastleProvider());
    }

    private static byte[] hash(byte[] cpabeData) {
        try {
            MessageDigest sha256 = MessageDigest.getInstance(HASHING_ALGORITHM);
            return Arrays.copyOf(sha256.digest(cpabeData), AES_KEY_LENGTH);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            System.err.println(HASHING_ALGORITHM + " not provided by runtime environment. Exiting...");
            System.exit(1);
        }
        return null;
    }
    
    private static byte[] combine(byte[] cpabeData, byte[] lbeKey) {
    	byte[] hashedCpabeSecret = hash(cpabeData);
    	if (lbeKey != null) {
    		if (hashedCpabeSecret.length != lbeKey.length) {
    			throw new RuntimeException("wrong key size for lbeKey, " + hashedCpabeSecret.length + " bytes required");
    		}
    		for (int i = 0; i < lbeKey.length; i++) {
    			hashedCpabeSecret[i] = (byte) (hashedCpabeSecret[i] ^ lbeKey[i]);
    		}
    	}
    	return hashedCpabeSecret;
    }
	

// Path: src/main/java/trabe/AbeDecryptionException.java
// public class AbeDecryptionException extends DecryptionException {
// 
// 	private static final long serialVersionUID = 2848983353356933397L;
// 
// 	public AbeDecryptionException(String msg) {
// 		super(msg);
// 	}
// 
// 	public AbeDecryptionException(String msg, Throwable t) {
// 		super(msg, t);
// 	}
// }
// 
// Path: src/main/java/trabe/AbeEncryptionException.java
// public class AbeEncryptionException extends GeneralSecurityException {
// 
//     private static final long serialVersionUID = 1043863535572140323L;
// 
//     public AbeEncryptionException(String msg) {
//         super(msg);
//     }
//     
//     public AbeEncryptionException(String msg, Throwable t) {
//         super(msg, t);
//     }
// 
// }


// Path: src/main/java/trabe/aes/AesEncryption.java
import java.io.*;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import trabe.AbeDecryptionException;
import trabe.AbeEncryptionException;

    
    static {
    	//Security.addProvider(new BouncyCastleProvider());
    }

    private static byte[] hash(byte[] cpabeData) {
        try {
            MessageDigest sha256 = MessageDigest.getInstance(HASHING_ALGORITHM);
            return Arrays.copyOf(sha256.digest(cpabeData), AES_KEY_LENGTH);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            System.err.println(HASHING_ALGORITHM + " not provided by runtime environment. Exiting...");
            System.exit(1);
        }
        return null;
    }
    
    private static byte[] combine(byte[] cpabeData, byte[] lbeKey) {
    	byte[] hashedCpabeSecret = hash(cpabeData);
    	if (lbeKey != null) {
    		if (hashedCpabeSecret.length != lbeKey.length) {
    			throw new RuntimeException("wrong key size for lbeKey, " + hashedCpabeSecret.length + " bytes required");
    		}
    		for (int i = 0; i < lbeKey.length; i++) {
    			hashedCpabeSecret[i] = (byte) (hashedCpabeSecret[i] ^ lbeKey[i]);
    		}
    	}
    	return hashedCpabeSecret;
    }
	

	public static void encrypt(byte[] cpabeKey, byte[] lbeKey, byte[] iv, InputStream input, OutputStream output) throws IOException, AbeEncryptionException {
