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 (and provider) 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, provider, 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(...), setProvider(...), setProviderName(...), 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 = "PBEWithMD5AndDES";

    
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;

    
The default salt size, only used if the chosen encryption algorithm is not a block algorithm and thus block size cannot be used as salt size.
    public static final int DEFAULT_SALT_SIZE_BYTES = 8;
    // Algorithm (and provider-related info) for Password Based Encoding.
    private String algorithm = ;
    private String providerName = null;
    private Provider provider = null;
    
    // 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,
    // and it will be set to the size of the block for the specific
    // chosen algorithm (if the algorithm is not a block algorithm, the 
    // default value will be used).
    private int saltSizeBytes = ;
    
    
    // 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;
    private boolean providerNameSet = false;
    private boolean providerSet = 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
  • Security Provider (or provider name)
  • 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 JCE provider (if you specify one, or the default JVM provider if you don't) and, if it is supported, you can also specify mode and padding for it, like ALGORITHM/MODE/PADDING.

Parameters:
algorithm the name of the algorithm to be used.
    public synchronized void setAlgorithm(String algorithm) {
        Validate.notEmpty(algorithm"Algorithm cannot be set empty");
        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;
    }
    
    
    

Sets the name of the security provider to be asked for the encryption algorithm. This security provider has to be registered beforehand at the JVM security framework.

The provider can also be set with the setProvider(java.security.Provider) method, in which case it will not be necessary neither registering the provider beforehand, nor calling this setProviderName(java.lang.String) method to specify a provider name.

Note that a call to setProvider(java.security.Provider) overrides any value set by this method.

If no provider name / provider is explicitly set, the default JVM provider will be used.

Parameters:
providerName the name of the security provider to be asked for the encryption algorithm.
Since:
1.3
    public synchronized void setProviderName(String providerName) {
        Validate.notNull(providerName"Provider name cannot be set null");
        if (isInitialized()) {
            throw new AlreadyInitializedException();
        }
        this. = providerName;
        this. = true;
    }
    
    
    

Sets the security provider to be asked for the encryption algorithm. The provider does not have to be registered at the security infrastructure beforehand, and its being used here will not result in its being registered.

If this method is called, calling setProviderName(java.lang.String) becomes unnecessary.

If no provider name / provider is explicitly set, the default JVM provider will be used.

Parameters:
provider the provider to be asked for the chosen algorithm
Since:
1.3
    public synchronized void setProvider(Provider provider) {
        Validate.notNull(provider"Provider cannot be set null");
        if (isInitialized()) {
            throw new AlreadyInitializedException();
        }
        this. = provider;
        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 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 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");
                }
                
                
                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();
                
                String configProviderName = .getProviderName();
                if (configProviderName != null) {
                    Validate.notEmpty(configProviderName,
                            "Provider name cannot be empty");
                }
                
                Provider configProvider = .getProvider();
                
                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;
                this. = 
                    ((this.) || (configProviderName == null))?
                            this. : configProviderName;
                this. = 
                    ((this.) || (configProvider == null))?
                            this. : configProvider;
                
            }
            
            /*
             * 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();
            }
            
            try {
            
                // Password cannot be null.
                if (this. == null) {
                    throw new EncryptionInitializationException(
                            "Password not set for Password Based Encryptor");
                } else {
                    // Normalize password to NFC form
                    this. = 
                        Normalizer.normalize(this..);
                }
                
                /*
                 * Encryption and decryption Ciphers are created the usual way.
                 */
                PBEKeySpec pbeKeySpec = 
                    new PBEKeySpec(this..toCharArray());
                
                if (this. != null) {
                    
                    SecretKeyFactory factory =
                        SecretKeyFactory.getInstance(
                                this.
                                this.);
                    
                    this. = factory.generateSecret(pbeKeySpec);
                    
                    this. = 
                        Cipher.getInstance(this.this.);
                    this. = 
                        Cipher.getInstance(this.this.);
                    
                } else if (this. != null) {
                    
                    SecretKeyFactory factory =
                        SecretKeyFactory.getInstance(
                                this.
                                this.);
                    
                    this. = factory.generateSecret(pbeKeySpec);
                    
                    this. = 
                        Cipher.getInstance(this.this.);
                    this. = 
                        Cipher.getInstance(this.this.);
                    
                } else {
                    
                    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);
            }
            
            // The salt size for the chosen algorithm is set to be equal 
            // to the algorithm's block size (if it is a block algorithm).
            int algorithmBlockSize = this..getBlockSize();
            if (algorithmBlockSize > 0) {
                this. = algorithmBlockSize;
            }
            
            
            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(e);
            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(e);
            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).
     */
        if ((e.getMessage() != null) && 
                ((e.getMessage().toUpperCase().indexOf("KEY SIZE") != -1))) {
            
            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