Package au.net.causal.projo.prefs.security

Source Code of au.net.causal.projo.prefs.security.StoredEncryptedPasswordSource

package au.net.causal.projo.prefs.security;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;

import org.jasypt.encryption.pbe.PBEByteEncryptor;
import org.jasypt.exceptions.EncryptionOperationNotPossibleException;

import au.net.causal.projo.prefs.PreferenceKeyMetadata;
import au.net.causal.projo.prefs.PreferenceNode;
import au.net.causal.projo.prefs.PreferencesException;

/**
* A password source where the master password is stored encrypted in a preference node and a custom encrypter is used to encrypt and descrypt the password.
* When the master password does not exist, it is generated from another password source.
* <p>
*
* Useful for when a native encrypter should be used, but where all other data should be encrypted in a portable way using a master password.
*
* @author prunge
*/
public class StoredEncryptedPasswordSource implements PasswordSource
{
  private final PreferenceNode node;
  private final String key;
  private final PBEByteEncryptor encrypter;
  private final Charset passwordEncoding = StandardCharsets.UTF_8;
 
  private final PasswordSource passwordGenerator;
 
  /**
   * Creates a <code>StoredEncryptedPasswordSource</code>.
   *
   * @param node the preference node to store the master password in.  Must support storing byte[] data.
   * @param key the key to store the master password under.
   * @param encrypter the encrypter to use for encrypting and decrypting passwords.
   * @param passwordGenerator if a master password does not exist, a new one is generated from this generator.
   *
   * @throws NullPointerException if any parameter is null.
   */
  public StoredEncryptedPasswordSource(PreferenceNode node, String key, PBEByteEncryptor encrypter, PasswordSource passwordGenerator)
  {
    if (node == null)
      throw new NullPointerException("node == null");
    if (key == null)
      throw new NullPointerException("key == null");
    if (encrypter == null)
      throw new NullPointerException("encrypter == null");
    if (passwordGenerator == null)
      throw new NullPointerException("passwordGenerator == null");
   
    this.node = node;
    this.key = key;
    this.encrypter = encrypter;
    this.passwordGenerator = passwordGenerator;
  }

  @Override
  public char[] readPassword(Mode mode)
  throws PreferencesException
  {
    byte[] encryptedPassword = node.getValue(key, new PreferenceKeyMetadata<>(byte[].class));
    byte[] passwordBytes;   
    if (encryptedPassword == null)
    {
      passwordBytes = generatePassword();
      if (passwordBytes == null) //cancelled by user?
        return(null);
     
      try
      {
        encryptedPassword = encrypter.encrypt(passwordBytes);
        node.putValue(key, encryptedPassword, new PreferenceKeyMetadata<>(byte[].class));
      }
      catch (EncryptionOperationNotPossibleException e)
      {
        throw new PreferencesException("Failed to encrypt password: " + e, e);
      }
      catch (UserAbortedEnteringPasswordException e)
      {
        //Could be thrown if the encrypter is a sourced encrypter
        //In this case, treat as a cancel
        return(null);
      }
    }
    else
    {
      try
      {
        passwordBytes = encrypter.decrypt(encryptedPassword);
      }
      catch (EncryptionOperationNotPossibleException e)
      {
        throw new PreferencesException("Failed to decrypt password: " + e, e);
      }
      catch (UserAbortedEnteringPasswordException e)
      {
        //Could be thrown if the encrypter is a sourced encrypter
        //In this case, treat as a cancel
        return(null);
      }
    }
   
    char[] password = bytesToChars(passwordBytes);
   
    return(password);
  }

  /**
   * Generates bytes for a new password by using the password generator.
   *
   * @return the generated password.
   *
   * @throws PreferencesException if an error occurs.
   */
  protected byte[] generatePassword()
  throws PreferencesException
  {
    char[] newPassword = passwordGenerator.readPassword(Mode.ENCRYPTION);
    if (newPassword == null)
      return(null);
   
    byte[] newPasswordBytes = charsToBytes(newPassword);
    return(newPasswordBytes);
  }
 
  private byte[] charsToBytes(char[] c)
  {
    //TODO technically this is 'insecure' as it creates a string that may be left in memory
    //realistically, this doesn't reduce security that much anyway so ignore for now
    //but would like to fix later
    return(new String(c).getBytes(passwordEncoding));
  }
 
  private char[] bytesToChars(byte[] b)
  {
    //TODO technically this is 'insecure' as it creates a string that may be left in memory
    //realistically, this doesn't reduce security that much anyway so ignore for now
    //but would like to fix later
    return(new String(b, passwordEncoding).toCharArray());
  }

}
TOP

Related Classes of au.net.causal.projo.prefs.security.StoredEncryptedPasswordSource

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.