Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * =============================================================================
   * 
   *   Copyright (c) 2007, The JASYPT team (http://www.jasypt.org)
   * 
   *   Licensed under the Apache License, Version 2.0 (the "License");
   *   you may not use this file except in compliance with the License.
   *   You may obtain a copy of the License at
   * 
  *       http://www.apache.org/licenses/LICENSE-2.0
  * 
  *   Unless required by applicable law or agreed to in writing, software
  *   distributed under the License is distributed on an "AS IS" BASIS,
  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  *   See the License for the specific language governing permissions and
  *   limitations under the License.
  * 
  * =============================================================================
  */
 package org.jasypt.encryption.pbe;
 
 
 

Standard implementation of the PBEByteEncryptor interface. This class lets the user specify the algorithm to be used for encryption, the password to use, the number of hashing iterations and the salt generator that will be applied for obtaining the encryption key.

This class is thread-safe.


Configuration

The algorithm, password, key-obtention iterations and salt generator can take values in any of these ways:

  • Using its default values (except for password).
  • Setting a org.jasypt.encryption.pbe.config.PBEConfig object which provides new configuration values.
  • Calling the corresponding setAlgorithm(...), setPassword(...), setKeyObtentionIterations(...) or setSaltGenerator(...) methods.
And the actual values to be used for initialization will be established by applying the following priorities:
  1. First, the default values are considered (except for password).
  2. Then, if a org.jasypt.encryption.pbe.config.PBEConfig object has been set with setConfig(...), the non-null values returned by its getX() methods override the default values.
  3. Finally, if the corresponding setX(...) method has been called on the encryptor itself for any of the configuration parameters, the values set by these calls override all of the above.


Initialization

Before it is ready to encrypt, an object of this class has to be initialized. Initialization happens:

  • When initialize() is called.
  • When encrypt(...) or decrypt(...) are called for the first time, if initialize() has not been called before.
Once an encryptor has been initialized, trying to change its configuration will result in an AlreadyInitializedException being thrown.


Usage

An encryptor may be used for:

  • Encrypting messages, by calling the encrypt(...) method.
  • Decrypting messages, by calling the decrypt(...) method.
If a random salt generator is used, two encryption results for the same message will always be different (except in the case of random salt coincidence). This may enforce security by difficulting brute force attacks on sets of data at a time and forcing attackers to perform a brute force attack on each separate piece of encrypted data.

To learn more about the mechanisms involved in encryption, read PKCS #5: Password-Based Cryptography Standard.

Author(s):
Daniel Fernández Garrido
Since:
1.0
public final class StandardPBEByteEncryptor implements PBEByteEncryptor {
    
    
The default algorithm to be used if none specified: PBEWithMD5AndDES.
    public static final String DEFAULT_ALGORITHM = 
        .;

    
The default number of hashing iterations applied for obtaining the encryption key from the specified password, set to 1000.
    public static final int DEFAULT_KEY_OBTENTION_ITERATIONS = 1000;
    // Algorithm for Password Based Encoding. Must be registered in 
    // org.jasypt.encryption.pbe.algorithms.PBEAlgorithms.
    private String algorithm = ;
    
    // Password to be applied. This will NOT have a default value. If none
    // is set during configuration, an exception will be thrown.
    private String password = null;
    
    // Number of hashing iterations to be applied for obtaining the encryption
    // key from the specified password.
    
    // SaltGenerator to be used. Initialization of a salt generator is costly,
    // and so default value will be applied only in initialize(), if it finally
    // becomes necessary.
    private SaltGenerator saltGenerator = null;
    // Size in bytes of the salt to be used for obtaining the
    // encryption key. This size will depend on the PBE algorithm being used,
    // so instead of being set by the user it will be provided by the
    // org.jasypt.encryption.pbe.algorithms.PBEAlgorithms registry.
    private int saltSizeBytes = 0;
    
    
    // Config object set (optionally).
    private PBEConfig config = null;
    /*
     * Set of booleans which indicate whether the config or default values
     * have to be overriden because of the setX methods having been
     * called.
     */
    private boolean algorithmSet = false;
    private boolean passwordSet = false;
    private boolean iterationsSet = false;
    private boolean saltGeneratorSet = false;
    
    
    /*
     * Flag which indicates whether the encryptor has been initialized or not.
     * 
     * Once initialized, no further modifications to its configuration will
     * be allowed.
     */
    private boolean initialized = false;
    
    // Encryption key generated.
    private SecretKey key = null;
    
    // Ciphers to be used for encryption and decryption.
    private Cipher encryptCipher = null;
    private Cipher decryptCipher = null;
    
    

    
    
Creates a new instance of StandardPBEByteEncryptor.
    public StandardPBEByteEncryptor() {
        super();
    }

    
    

Sets a org.jasypt.encryption.pbe.config.PBEConfig object for the encryptor. If this config object is set, it will be asked values for:

  • Algorithm
  • Password
  • Hashing iterations for obtaining the encryption key
  • Salt generator

The non-null values it returns will override the default ones, and will be overriden by any values specified with a setX method.

Parameters:
config the PBEConfig object to be used as the source for configuration parameters.
    public synchronized void setConfig(PBEConfig config) {
        Validate.notNull(config"Config cannot be set null");
        if (isInitialized()) {
            throw new AlreadyInitializedException();
        }
        this. = config;
    }

    
    

Sets the algorithm to be used for encryption, like PBEWithMD5AndDES.

This algorithm has to be supported by your Java Virtual Machine, and it must be one of the algorithms registered at org.jasypt.encryption.pbe.algorithms.PBEAlgorithms.

Parameters:
algorithm the name of the algorithm to be used.
See also:
org.jasypt.encryption.pbe.algorithms.PBEAlgorithms
    public synchronized void setAlgorithm(String algorithm) {
        Validate.notEmpty(algorithm"Algorithm cannot be set empty");
        PBEAlgorithms.validateAlgorithm(algorithm);
        if (isInitialized()) {
            throw new AlreadyInitializedException();
        }
        this. = algorithm;
        this. = true;
    }
    
    
    

Sets the password to be used.

There is no default value for password, so not setting this parameter either from a org.jasypt.encryption.pbe.config.PBEConfig object or from a call to setPassword will result in an EncryptionInitializationException being thrown during initialization.

Parameters:
password the password to be used.
    public synchronized void setPassword(String password) {
        Validate.notEmpty(password"Password cannot be set empty");
        if (isInitialized()) {
            throw new AlreadyInitializedException();
        }
        this. = password;
        this. = true;
    }
    
    
    

Set the number of hashing iterations applied to obtain the encryption key.

This mechanism is explained in PKCS #5: Password-Based Cryptography Standard.

Parameters:
keyObtentionIterations the number of iterations
    public synchronized void setKeyObtentionIterations(
            int keyObtentionIterations) {
        Validate.isTrue(keyObtentionIterations > 0, 
                "Number of iterations for key obtention must be " +
                "greater than zero");
        if (isInitialized()) {
            throw new AlreadyInitializedException();
        }
        this. = keyObtentionIterations;
        this. = true;
    }

    
    

Sets the salt generator to be used. If no salt generator is specified, an instance of org.jasypt.salt.RandomSaltGenerator will be used.

Parameters:
saltGenerator the salt generator to be used.
    public synchronized void setSaltGenerator(SaltGenerator saltGenerator) {
        Validate.notNull(saltGenerator"Salt generator cannot be set null");
        if (isInitialized()) {
            throw new AlreadyInitializedException();
        }
        this. = saltGenerator;
        this. = true;
    }
    

    
    

Returns true if the encryptor has already been initialized, false if not.
Initialization happens:

  • When initialize is called.
  • When encrypt or decrypt are called for the first time, if initialize has not been called before.

Once an encryptor has been initialized, trying to change its configuration (algorithm, password, key obtention iterations or salt generator) will result in an AlreadyInitializedException being thrown.

Returns:
true if the encryptor has already been initialized, false if not.
    public synchronized boolean isInitialized() {
        return this.;
    }

    
    

Initialize the encryptor.

This operation will consist in determining the actual configuration values to be used, and then initializing the encryptor with them.
These values are decided by applying the following priorities:

  1. First, the default values are considered (except for password).
  2. Then, if a org.jasypt.encryption.pbe.config.PBEConfig object has been set with setConfig, the non-null values returned by its getX methods override the default values.
  3. Finally, if the corresponding setX method has been called on the encryptor itself for any of the configuration parameters, the values set by these calls override all of the above.

Once an encryptor has been initialized, trying to change its configuration (algorithm, password, key obtention iterations or salt generator) will result in an AlreadyInitializedException being thrown.

Throws:
org.jasypt.exceptions.EncryptionInitializationException if initialization could not be correctly done (for example, no password has been set).
    public synchronized void initialize() {
        
        // Double-check to avoid synchronization issues
        if (!this.) {
            
            /*
             * If a PBEConfig object has been set, we need to 
             * consider the values it returns (if, for each value, the
             * corresponding "setX" method has not been called).
             */
            if (this. != null) {
                
                String configAlgorithm = .getAlgorithm();
                if (configAlgorithm != null) {
                    Validate.notEmpty(
                            "Algorithm cannot be set empty");
                    PBEAlgorithms.validateAlgorithm();
                }
                
                
                String configPassword = .getPassword();
                if (configPassword != null) {
                    Validate.notEmpty(configPassword
                            "Password cannot be set empty");
                }
                
                Integer configKeyObtentionIterations = 
                    .getKeyObtentionIterations();
                if (configKeyObtentionIterations != null) {
                    Validate.isTrue(configKeyObtentionIterations.intValue() > 0, 
                            "Number of iterations for key obtention must be " +
                            "greater than zero");
                }
                
                SaltGenerator configSaltGenerator = .getSaltGenerator();
                
                this. = 
                    ((this.) || (configAlgorithm == null))?
                            this. : configAlgorithm;
                this. = 
                    ((this.) || (configPassword == null))?
                            this. : configPassword;
                this. = 
                    ((this.) || 
                     (configKeyObtentionIterations == null))?
                            this. : 
                            configKeyObtentionIterations.intValue();
                this. = 
                    ((this.) || (configSaltGenerator == null))?
                            this. : configSaltGenerator;
                
            }
            
            /*
             * If the encryptor was not set a salt generator in any way,
             * it is time to apply its default value.
             */
            if (this. == null) {
                this. = new RandomSaltGenerator();
            }
            // The specific parameter (salt size) for the chosen algorithm
            // is retrieved from the algorithm registry.
            PBEAlgorithms.Parameters parameters =
                PBEAlgorithms.getParameters(this.);
            this. = parameters.getSaltSizeBytes();
            
            try {
            
                // Password cannot be null.
                if (this. == null) {
                    throw new EncryptionInitializationException(
                            "Password not set for Password Based Encryptor");
                }
                
                /*
                 * Encryption and decryption Ciphers are created the usual way.
                 */
                PBEKeySpec pbeKeySpec = 
                    new PBEKeySpec(this..toCharArray());
                SecretKeyFactory factory =
                    SecretKeyFactory.getInstance(this.);
                
                this. = factory.generateSecret(pbeKeySpec);
                
                this. = Cipher.getInstance(this.);
                this. = Cipher.getInstance(this.);
                
            } catch (EncryptionInitializationException e) {
                throw e;
            } catch (Throwable t) {
                throw new EncryptionInitializationException(t);
            }
            this. = true;
        }
        
    }


    

Encrypts a message using the specified configuration.

The mechanisms applied to perform the encryption operation are described in PKCS #5: Password-Based Cryptography Standard.

This encryptor uses a salt for each encryption operation. The size of the salt depends on the algorithm being used. This salt is used for creating the encryption key and, if generated by a random generator, it is also appended unencrypted at the beginning of the results so that a decryption operation can be performed.

If a random salt generator is used, two encryption results for the same message will always be different (except in the case of random salt coincidence). This may enforce security by difficulting brute force attacks on sets of data at a time and forcing attackers to perform a brute force attack on each separate piece of encrypted data.

Parameters:
message the byte array message to be encrypted
Returns:
the result of encryption
Throws:
org.jasypt.exceptions.EncryptionOperationNotPossibleException if the encryption operation fails, ommitting any further information about the cause for security reasons.
org.jasypt.exceptions.EncryptionInitializationException if initialization could not be correctly done (for example, no password has been set).
    public byte[] encrypt(byte[] message
            throws EncryptionOperationNotPossibleException {
        
        if (message == null) {
            return null;
        }
        
        // Check initialization
        if (!isInitialized()) {
            initialize();
        }
        
        try {
            
            // Create salt
            byte[] salt = this..generateSalt(this.);
            /*
             * Perform encryption using the Cipher
             */
            PBEParameterSpec parameterSpec = 
                new PBEParameterSpec(saltthis.);
            byte[] encryptedMessage = null;
            synchronized (this.) {
                this..init(
                        .this.parameterSpec);
                encryptedMessage = this..doFinal(message);
            }
            // Finally we build an array containing both the unencrypted salt
            // and the result of the encryption. This is done only
            // if the salt generator we are using specifies to do so.
            if (this..includePlainSaltInEncryptionResults()) {
                encryptedMessage = ArrayUtils.addAll(saltencryptedMessage);
            }
            
            return encryptedMessage;
            
        } catch (InvalidKeyException e) {
            // The problem could be not having the unlimited strength policies
            // installed, so better give a usefull error message.
            handleInvalidKeyException();
            throw new EncryptionOperationNotPossibleException();
        } catch (Exception e) {
            // If encryption fails, it is more secure not to return any 
            // information about the cause in nested exceptions. Simply fail.
            throw new EncryptionOperationNotPossibleException();
        }
        
    }


    

Decrypts a message using the specified configuration.

The mechanisms applied to perform the decryption operation are described in PKCS #5: Password-Based Cryptography Standard.

If a random salt generator is used, this decryption operation will expect to find an unencrypted salt at the beginning of the encrypted input, so that the decryption operation can be correctly performed (there is no other way of knowing it).

Parameters:
encryptedMessage the byte array message to be decrypted
Returns:
the result of decryption
Throws:
org.jasypt.exceptions.EncryptionOperationNotPossibleException if the decryption operation fails, ommitting any further information about the cause for security reasons.
org.jasypt.exceptions.EncryptionInitializationException if initialization could not be correctly done (for example, no password has been set).
    public byte[] decrypt(byte[] encryptedMessage
            throws EncryptionOperationNotPossibleException {
        
        if (encryptedMessage == null) {
            return null;
        }
        
        // Check initialization
        if (!isInitialized()) {
            initialize();
        }
    
        try {
            // If we are using a salt generator which specifies the salt
            // to be included into the encrypted message itself, get it from 
            // there. If not, the salt is supposed to be fixed and thus the
            // salt generator can be safely asked for it again.
            byte[] salt = null
            if (this..includePlainSaltInEncryptionResults()) {
                salt = ArrayUtils.subarray(
                        encryptedMessage, 0, this.);
            } else {
                salt = this..generateSalt(this.);
            }
            
            
            /*
             * Perform decryption using the Cipher
             */
            PBEParameterSpec parameterSpec = 
                new PBEParameterSpec(saltthis.);
            byte[] decryptedMessage = null;
            
            // If we are using a salt generator which specifies the salt
            // to be included into the encrypted message itself, we need to
            // extract the part of the encrypted message which really belongs
            // to the encryption result, and not the prepended salt.
            byte[] encryptedMessageKernel = null
            if (this..includePlainSaltInEncryptionResults()) {
                encryptedMessageKernel = 
                    ArrayUtils.subarray(encryptedMessagethis.
                            encryptedMessage.length);
            } else {
                encryptedMessageKernel = encryptedMessage
            }
                 
            synchronized (this.) {
                this..init(
                        .this.parameterSpec);
                decryptedMessage = 
                    this..doFinal(encryptedMessageKernel);
            }
            // Return the results
            return decryptedMessage;
            
            
        } catch (InvalidKeyException e) {
            // The problem could be not having the unlimited strength policies
            // installed, so better give a usefull error message.
            handleInvalidKeyException();
            throw new EncryptionOperationNotPossibleException();
        } catch (Exception e) {
            // If decryption fails, it is more secure not to return any 
            // information about the cause in nested exceptions. Simply fail.
            throw new EncryptionOperationNotPossibleException();
        }
        
    }    
    /*
     * Method used to provide an useful error message in the case that the
     * user tried to use a strong PBE algorithm like TripleDES and he/she
     * has not installed the Unlimited Strength Policy files (the default
     * message for this is simply "invalid key size", which does not provide
     * enough clues for the user to know what is really going on).
     */
    private void handleInvalidKeyException() {
        
        String vmVendor = System.getProperty("java.vm.vendor");
        if ((this..equals(
                .)) &&
            (vmVendor != null) && 
            (vmVendor.toUpperCase().contains("SUN"))) {
            
            throw new EncryptionOperationNotPossibleException(
                    "Encryption raised an exception. A possible cause is " +
                    "you are using strong encryption algorithms and " +
                    "you have not installed the Java Cryptography " + 
                    "Extension (JCE) Unlimited Strength Jurisdiction " +
                    "Policy Files in this Java Virtual Machine");
            
        }
        
    }
    
New to GrepCode? Check out our FAQ X