import java.security.Provider;                                                                                           
import java.util.Enumeration;                                                                                            
import javax.crypto.Cipher;                                                                                              
import javax.crypto.KeyGenerator;                                                                                        
import javax.crypto.SecretKey;                                                                                           
import javax.crypto.spec.IvParameterSpec;                                                                                
import java.security.KeyStore;                                                                                           
import java.security.Key;                                                                                                
import java.security.Security;                                                                                           
import java.util.Base64;                                                                                                 
                                                                                                                         
public class ICSFAESEncryption {                                                                                         
    public static void main(String[] args) throws Exception {                                                            
                                                                                                                         
        // Remove IBMJCECCA if it is already present (to re-add at the top)                                              
        Security.removeProvider("IBMJCECCA");                                                                            
                                                                                                                         
        // Add IBMJCECCA as the first provider                                                                           
        Security.insertProviderAt(new com.ibm.crypto.hdwrCCA.provider.IBMJCECCA(), 1);                                   
                                                                                                                         
        // Add special system properties to use                                                                          
        System.setProperty("javax.net.ssl.keyStore", "safkeyringhw:///<keyring-name>");                               
        System.setProperty("javax.net.ssl.keyStoreType", "JCECCARACFKS");                                                
        System.setProperty("javax.net.ssl.keyStorePassword", "password");                                                
                                                                                                                         
                                                                                                                         
        // Print all providers to verify IBMJCECCA is first                                                              
        System.out.println("-----------------------------------------------");                                           
        System.out.println("Security Providers (IBMJCECCA should be first):");                                           
        System.out.println("-----------------------------------------------");                                           
        for (Provider provider : Security.getProviders()) {                                                              
            System.out.println(provider.getName());                                                                      
        }                                                                                                                
        System.out.println("-----------------------------------------------");                                           
                                                                                                                         
        //                                                                                                               
        // // Iterate through all providers                                                                              
        // for (Provider provider : Security.getProviders()) {                                                           
        //     System.out.println("- " + provider.getName());                                                            
        //                                                                                                               
        //     // Check if the provider is IBMJCECCA                                                                     
        //     if (provider.getName().equalsIgnoreCase("IBMJCECCA")) {                                                   
        //         // List all services offered by IBMJCECCA provider                                                    
        //         System.out.println("  Services offered by IBMJCECCA provider:");                                      
        //         System.out.println("-----------------------------------------------");                                
        //         for (Provider.Service service : provider.getServices()) {                                             
        //             System.out.println("   - " + service.getType() + ": " + service.getAlgorithm());                  
        //         }                                                                                                     
        //     }                                                                                                         
        // }                                                                                                             
        // System.out.println("-----------------------------------------------");                                        
                                                                                                                         
        // Load the RACF keystore (keyring)                                                                              
        KeyStore ks = KeyStore.getInstance("JCECCAKS", "IBMJCECCA");                                                     
        KeyStore racf = KeyStore.getInstance("JCECCARACFKS", "IBMJCECCA");  
        KeyStore aes  = KeyStore.getInstance("JCECCARACFKS", "IBMJCECCA");                                               
        // load all keystores                                                                                            
        ks.load(null, null); // No password needed for RACF keyrings                                                     
        racf.load(null, System.getProperty("javax.net.ssl.keyStorePassword").toCharArray());                             
        aes.load(null, System.getProperty("javax.net.ssl.keyStorePassword").toCharArray());                              
                                                                                                                         
        // List all available KeyStores                                                                                  
        System.out.println("Available KeyStores in Java:");                                                              
        System.out.println("-----------------------------------------------");                                           
        for (Provider provider : Security.getProviders()) {                                                              
            for (Provider.Service service : provider.getServices()) {                                                    
                if ("KeyStore".equals(service.getType())) {                                                              
                    System.out.println(" - " + service.getAlgorithm() + " (Provider: " + provider.getName() + ")");      
                }                                                                                                        
            }                                                                                                            
        }                                                                                                                
        System.out.println("-----------------------------------------------");                                           
                                                                                                                         
        // List all keyrings                                                                                             
        Enumeration<String> keyrings = ks.aliases();                                                                     
        System.out.println("Available Keyrings:");                                                                       
        while (keyrings.hasMoreElements()) {                                                                             
            System.out.println("- " + keyrings.nextElement());                                                           
        }                                                                                                                
        Enumeration<String> RACFkeyrings = racf.aliases();                                                               
        System.out.println("Available RACF keyrings:");                                                                  
        while (RACFkeyrings.hasMoreElements()) {                                                                         
            System.out.println("- " + RACFkeyrings.nextElement());                                                       
        }                                                                                                                
                                                                                                                         
        Enumeration<String> AESkeyrings = aes.aliases();                                                                 
        System.out.println("Available AES keyrings:");                                                                   
        while (AESkeyrings.hasMoreElements()) {                                                                          
            System.out.println("- " + AESkeyrings.nextElement());                                                        
        }                                                                                                                
                                                                                                                         
        // ICSF key label (Ensure the key exists in ICSF)                                                                
        String AESKeyLabel = "<your-key-label-for-pw-encryption>";                                           
        String keyLabel = "<keyring-owner>";                                                                                      
        String keyRing  = "<keyring-name>";                                                                           
                                                                                                                         
        // Load the secret keys                                                                                          
        // Key key = keyStore.getKey(keyLabel, null);  // null password for ICSF keys                                    
        // Key key = keyStore.getKey(keyRing, null);  // null password for ICSF keys                                     
        Key aeskey = aes.getKey(AESKeyLabel, null);  // null password for ICSF keys                                      
                                                                                                                         
                                                                                                                         
        // Output the key                                                                                                
        System.out.println("-----------------------------------------------");                                           
        // System.out.println("Retrieved key for keyLabel " + keyLabel + ": " + key);                                    
        System.out.println("Retrieved key for AESKeyLabel " + AESKeyLabel + ": " + aeskey);                              
        System.out.println("-----------------------------------------------");                                           
                                                                                                                         
                                                                                                                         
                                                                                                                         
        SecretKey aesKey = (SecretKey) aes.getKey(keyLabel, null);                                                       
                                                                                           
        // List all available AES key aliases in ICSF                                      
        System.out.println("Available Keys in ICSF:");                                     
        Enumeration<String> aliases = aes.aliases();                                       
        while (aliases.hasMoreElements()) {                                                
            System.out.println(" - " + aliases.nextElement());                             
        }                                                                                  
                                                                                           
        // Create Cipher instance for AES encryption                                       
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding", "IBMJCECCA");           
                                                                                           
        // Generate a random IV (Initialization Vector)                                    
        byte[] iv = new byte[16]; // AES block size = 16 bytes                             
        IvParameterSpec ivSpec = new IvParameterSpec(iv);                                  
                                                                                           
        // Encrypt Data                                                                    
        cipher.init(Cipher.ENCRYPT_MODE, aesKey, ivSpec);                                  
        String plainText = "Hello from z/OS!";                                             
        byte[] encryptedBytes = cipher.doFinal(plainText.getBytes());                      
                                                                                           
        // Encode encrypted data in Base64 for easy storage/display                        
        String encryptedText = Base64.getEncoder().encodeToString(encryptedBytes);         
        System.out.println("Encrypted Data: " + encryptedText);                            
                                                                                           
        // Decrypt Data                                                                    
        cipher.init(Cipher.DECRYPT_MODE, aesKey, ivSpec);                                  
        byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedText)); 
        String decryptedText = new String(decryptedBytes);                                 
        System.out.println("Decrypted Data: " + decryptedText);                            
    }                                                                                      
}                                                                                          
