content: /*
   * Universal Password Manager
   * Copyright (C) 2005-2013 Adrian Smith
   *
   * This file is part of Universal Password Manager.
   *   
   * Universal Password Manager is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * Universal Password Manager is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with Universal Password Manager; if not, write to the Free Software
   * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
   */
  package com._17od.upm.crypto;
  
  import java.security.NoSuchAlgorithmException;
  import java.security.SecureRandom;
  
  import org.bouncycastle.crypto.BufferedBlockCipher;
  import org.bouncycastle.crypto.CipherParameters;
  import org.bouncycastle.crypto.InvalidCipherTextException;
  import org.bouncycastle.crypto.PBEParametersGenerator;
  import org.bouncycastle.crypto.digests.SHA256Digest;
  import org.bouncycastle.crypto.engines.AESEngine;
  import org.bouncycastle.crypto.generators.PKCS12ParametersGenerator;
  import org.bouncycastle.crypto.modes.CBCBlockCipher;
  import org.bouncycastle.crypto.paddings.PKCS7Padding;
  import org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher;
  
  
  public class EncryptionService {
  
      private static final String randomAlgorithm = "SHA1PRNG";
      public static final int SALT_LENGTH = 8;
  
      private byte[] salt;
      private BufferedBlockCipher encryptCipher;
      private BufferedBlockCipher decryptCipher;
  
      public EncryptionService(char[] password) throws CryptoException {
          try {
              this.salt = generateSalt();
          } catch (NoSuchAlgorithmException e) {
              throw new CryptoException(e);
          }
          initCipher(password);
      }
  
      public EncryptionService(char[] password, byte[] salt) {
          this.salt = salt;
          initCipher(password);
      }
  
      public void initCipher(char[] password) {
          PBEParametersGenerator keyGenerator = new PKCS12ParametersGenerator(new SHA256Digest());
          keyGenerator.init(PKCS12ParametersGenerator.PKCS12PasswordToBytes(password), salt, 20);
          CipherParameters keyParams = keyGenerator.generateDerivedParameters(256, 128);
          
          encryptCipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESEngine()), new PKCS7Padding());
          encryptCipher.init(true, keyParams);
          decryptCipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESEngine()), new PKCS7Padding());
          decryptCipher.init(false, keyParams);
      }
  
      private byte[] generateSalt() throws NoSuchAlgorithmException {
          SecureRandom saltGen = SecureRandom.getInstance(randomAlgorithm);
          byte pSalt[] = new byte[SALT_LENGTH];
          saltGen.nextBytes(pSalt);
          return pSalt;
      }
  
      public byte[] encrypt(byte[] plainText) throws CryptoException {
          byte[] encryptedBytes = new byte[encryptCipher.getOutputSize(plainText.length)];
          int outputLength = encryptCipher.processBytes(plainText, 0, plainText.length, encryptedBytes, 0);
          try {
              outputLength += encryptCipher.doFinal(encryptedBytes, outputLength);
          } catch (InvalidCipherTextException e) {
              throw new CryptoException(e);
          }
  
          byte[] results = new byte[outputLength];
          System.arraycopy(encryptedBytes, 0, results, 0, outputLength);
          return results;
      }
      
      public byte[] decrypt(byte[] encryptedBytes) throws CryptoException {
          byte[] decryptedBytes = new byte[decryptCipher.getOutputSize(encryptedBytes.length)];
          int outputLength = decryptCipher.processBytes(encryptedBytes, 0, encryptedBytes.length, decryptedBytes, 0);
          try {
              outputLength += decryptCipher.doFinal(decryptedBytes, outputLength);
          } catch (InvalidCipherTextException e) {
              throw new CryptoException(e);
          }
  
          byte[] results = new byte[outputLength];
          System.arraycopy(decryptedBytes, 0, results, 0, outputLength);
          return results;
      }
  
      public byte[] getSalt() {
          return salt;
      }
  
  }
  