/*
 * EncryptorDecryptor.java
 *
 * Copyright 2011 John W Dawson
 *
 * This code is distributed under the terms of the GNU General Public License, version 3
 *
 * This class performs encryption & decryption of configuration data
 */
 
import java.security.*;
import java.security.spec.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import java.util.logging.*;
import java.io.*;
public class EncryptorDecryptor
{
  private CipherOutputStream encryptor;
  private HexToBytes decryptor;
  private static final String DEFAULT_PASSWORD = "l9j4fl93f9m0gd94f";
  private BytesToHex encryptedOutput = new BytesToHex ();
  private UnpaddedByteArrayOutputStream decryptedOutput = new UnpaddedByteArrayOutputStream ();
  static Logger log = Logger.getLogger ("LdapAddressBook");
  
  public EncryptorDecryptor (String password)
  {    
    try
    {
      // Create a 16 byte encryption key from the password, padded out with the start of the default
      // password if required
      SecretKeySpec encryptionKey;
      if (password.length() >= 16)
      {
        encryptionKey = new SecretKeySpec (password.substring (0, 16).getBytes(), "AES");
      }
      else
      {
        encryptionKey = new SecretKeySpec 
                          ((password + DEFAULT_PASSWORD.substring (0, 16-password.length())).getBytes(), 
                          "AES");
      }
      
      // Create a cypher to do the encryption
      Cipher encryptAES = Cipher.getInstance("AES/ECB/NoPadding");
      
      // Initialise with key
      encryptAES.init(Cipher.ENCRYPT_MODE, encryptionKey);
      
      // Create a stream to encrypt fields
      encryptor = new CipherOutputStream (encryptedOutput, encryptAES);
  
      // Create a cypher to do the decryption
      Cipher decryptAES = Cipher.getInstance("AES/ECB/NoPadding");
      
      // Initialise with key
      decryptAES.init(Cipher.DECRYPT_MODE, encryptionKey);
      
      // Create a stream to decrypt fields
      decryptor = new HexToBytes (
                    new CipherOutputStream (decryptedOutput, decryptAES));
                    
    }
    catch (Exception e)
    {
      log.severe ("Error during program initialisation: " + e.getMessage());
      e.printStackTrace();
      System.exit (1);
    }
  }
  
  public String encrypt (String plainText)
  {
    if (plainText != null)
    {
      try
      {
        // Push the plain text into the stream  
        encryptor.write (plainText.getBytes());
        
        // Pad with zero bytes
        for (int i = (plainText.length() - 1) % 16 + 1; i < 16; ++i)
        {
           encryptor.write (0);
        }
    
        // Flush text  through and pull the encrypted data out the other end
        encryptor.flush();
        return encryptedOutput.toHexString();
      }
      catch (IOException e)
      {
        log.warning ("Error encrypting configuration value");
        return null;
      }
    }
    else
    {
      return null;
    }
  }

  public String decrypt (String encrypted)
  {
    if (encrypted != null)
    {
      try
      {
        decryptor.write (encrypted);
        return decryptedOutput.toString();
      }
      catch (IOException e)
      {
        return null;
      }
    }
    else
    {
      return null;
    }
  }

}