com.sparkred.crypto.tools.RekeyEngine.java Source code

Java tutorial

Introduction

Here is the source code for com.sparkred.crypto.tools.RekeyEngine.java

Source

/*
 * Please read the README.md and LICENSE.md files contained in this repository or module.
 *
 * Please contact sales@sparkred.com or support@sparkred.com if you have any questions.
 *
 * This code is copyright Spark::red https://www.sparkred.com 2007-2016, all right reserved.
 */
package com.sparkred.crypto.tools;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.security.Security;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Date;
import java.util.List;

import javax.sql.DataSource;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.jasypt.encryption.pbe.StandardPBEStringEncryptor;

import atg.core.util.StringUtils;
import atg.nucleus.GenericService;
import atg.nucleus.ServiceException;
import atg.repository.MutableRepository;
import atg.repository.MutableRepositoryItem;
import atg.repository.RepositoryException;

import com.sparkred.crypto.CryptoConstants;
import com.sparkred.crypto.CryptoEngine;

/**
 * The Class RekeyEngine is used to do initial import encryptions from either plaintext columns or from data encrypted
 * with another type of encryption. It's also used to rekey and reencrypt data every 12 months.
 */
public class RekeyEngine extends GenericService {

    /** The crypto repository. */
    private MutableRepository mCryptoRepository;

    /** The data source for the data to be rekeyed. */
    private DataSource mDataDataSource;

    /** The decryptor component. */
    private Object mDecryptorComponent;

    /** The decryptor method. */
    private String mDecryptorMethod;

    /** The new key passphrase. */
    private String mNewKeyPassphrase;

    /** The table columns. */
    private List<String> mTableColumns;

    /** The engine to update. */
    private CryptoEngine mEngineToUpdate;

    /** The decrypt method. */
    private Method mDecryptMethod;

    /** The encryptor. */
    private StandardPBEStringEncryptor mEncryptor;

    /** The new data passphrase. */
    private String mNewDataPassphrase;

    /**
     * Initializes the decryptMethod, generates a new data passphrase, and sets up the local encryptor component.
     *
     * @throws SecurityException
     *             the security exception
     * @throws NoSuchMethodException
     *             the no such method exception
     */
    private void initialize() throws SecurityException, NoSuchMethodException {
        if (isLoggingDebug()) {
            logDebug("RekeyEngine.initialize:" + "starting....");
        }
        // Add the BouncyCastle JCE Security provider
        Security.addProvider(new BouncyCastleProvider());

        // Generate new data passphrase
        this.mNewDataPassphrase = generateNewDataPassphrase();
        if (isLoggingDebug()) {
            logDebug("RekeyEngine.initialize:" + "new data passphrase was generated:" + this.mNewDataPassphrase);
        }
        // Setup the decryptor
        Class[] decryptMethodArgs = new Class[1];
        decryptMethodArgs[0] = String.class;
        Method decryptMethod = getDecryptorComponent().getClass().getMethod(getDecryptorMethod(),
                decryptMethodArgs);
        this.mDecryptMethod = decryptMethod;
        if (isLoggingDebug()) {
            logDebug("RekeyEngine.initialize:" + "decryptMethod is setup.");
        }

        // Setup the encryptor
        StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
        encryptor.setProviderName(CryptoConstants.BOUNCY_CASTLE_PROVIDER_NAME);
        encryptor.setAlgorithm(CryptoConstants.STRONG_ALGO);
        encryptor.setPassword(this.mNewDataPassphrase);
        this.mEncryptor = encryptor;
        if (isLoggingDebug()) {
            logDebug("RekeyEngine.initialize:" + "encryptor is setup.");
        }
    }

    /**
     * Rekey. This method performs batch decrypt and encrypt operations on one or more columns in the database. It can
     * be used to perform initial encryption of plain text data, re-encrypt data that was encrypted with another system,
     * or re-encrypt data with a new key to meet PCI key rotation requirements.
     */
    public void reKey() {
        // UserTransactionDemarcation td = new UserTransactionDemarcation();
        // try {
        // try {
        // td.begin();
        // Setup JDBC connection
        Connection dataConnection = null;
        ResultSet rs = null;
        Statement selectStmt = null;
        try {
            initialize();

            dataConnection = getDataDataSource().getConnection();
            dataConnection.setAutoCommit(false);
            if (isLoggingDebug()) {
                logDebug("RekeyEngine.reKey:" + "dataconnection is set.");
            }
            // For each column we need to update...
            for (String tableColumn : getTableColumns()) {
                if (!StringUtils.isBlank(tableColumn) && tableColumn.split("\\.") != null
                        && tableColumn.split("\\.").length == 2) {
                    String[] columnData = tableColumn.split("\\.");
                    String tableName = columnData[0];
                    String columnName = columnData[1];

                    // Load up values
                    String selectQuery = "SELECT " + columnName + " FROM " + tableName;
                    if (isLoggingDebug()) {
                        logDebug("RekeyEngine.reKey:" + "selectQuery: " + selectQuery);
                    }
                    selectStmt = dataConnection.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
                            ResultSet.CONCUR_UPDATABLE);
                    rs = selectStmt.executeQuery(selectQuery);
                    while (rs.next()) {
                        if (isLoggingDebug()) {
                            logDebug("RekeyEngine.reKey:" + "about to work on Row ID: " + rs.getRowId(1));
                            logDebug("RekeyEngine.reKey:" + "about to work on Row Num: " + rs.getRow());
                        }
                        String encryptedString = rs.getString(1);
                        if (isLoggingDebug()) {
                            logDebug("RekeyEngine.reKey:" + "initial encrypted string: " + encryptedString);
                        }
                        // Decrypt using the referenced component and method
                        String decryptedString = (String) this.mDecryptMethod.invoke(getDecryptorComponent(),
                                encryptedString);

                        if (isLoggingDebug()) {
                            logDebug("RekeyEngine.reKey:" + "decrypted string: " + decryptedString);
                        }
                        // Encrypt using the new local encryptor using the new passphrase
                        String reEncryptedString = this.mEncryptor.encrypt(decryptedString);

                        if (isLoggingDebug()) {
                            logDebug("RekeyEngine.reKey:" + "re-encrypted string: " + reEncryptedString);
                        }
                        // Update the record
                        rs.updateString(columnName, reEncryptedString);
                        rs.updateRow();
                        if (isLoggingDebug()) {
                            logDebug("RekeyEngine.reKey:" + "updated Row ID: " + rs.getRowId(1));
                            logDebug("RekeyEngine.reKey:" + "updated Row Num: " + rs.getRow());
                        }
                    }
                }
            }

            // Encrypt the new passphrase
            final StandardPBEStringEncryptor dataPassEncryptor = new StandardPBEStringEncryptor();
            dataPassEncryptor.setProviderName(CryptoConstants.BOUNCY_CASTLE_PROVIDER_NAME);
            dataPassEncryptor.setAlgorithm(CryptoConstants.STRONG_ALGO);
            dataPassEncryptor.setPassword(getNewKeyPassphrase());
            String encryptedNewDataPassphrase = dataPassEncryptor.encrypt(this.mNewDataPassphrase);
            // Load crypto engine data
            MutableRepositoryItem cryptoEngineItem = getCryptoRepository().getItemForUpdate(
                    getEngineToUpdate().getCryptoEngineIdentifier(), CryptoConstants.CRYPTO_ENGINE_ITEM_DESC);

            // Persist the new data passphrase
            cryptoEngineItem.setPropertyValue(CryptoConstants.ENC_DATA_KEY_PROP_NAME, encryptedNewDataPassphrase);
            cryptoEngineItem.setPropertyValue(CryptoConstants.KEY_DATE_PROP_NAME, new Date());
            getCryptoRepository().updateItem(cryptoEngineItem);
            if (isLoggingDebug()) {
                logDebug("RekeyEngine.reKey:" + "crypto config saved.");
            }

        } catch (SQLException sqle) {
            if (isLoggingError()) {
                logError("RekeyEngine.reKey:" + "SQLException:", sqle);
            }
        } catch (InvocationTargetException ite) {
            if (isLoggingError()) {
                logError("RekeyEngine.reKey:" + "InvocationTargetException:", ite);
            }
        } catch (IllegalAccessException iae) {
            if (isLoggingError()) {
                logError("RekeyEngine.reKey:" + "IllegalAccessException:", iae);
            }
        } catch (NoSuchMethodException nsme) {
            if (isLoggingError()) {
                logError("RekeyEngine.reKey:" + "NoSuchMethodException:", nsme);
            }
        } catch (RepositoryException re) {
            if (isLoggingError()) {
                logError("RekeyEngine.reKey:" + "RepositoryException:", re);
            }
        } finally {
            if (dataConnection != null) {
                try {
                    if (rs != null) {
                        rs.close();
                    }
                    dataConnection.commit();
                    dataConnection.close();
                } catch (SQLException e) {
                    if (isLoggingError()) {
                        logError("RekeyEngine.reKey:" + "unable to close data connection.", e);
                    }
                }
            }
        }

        // finally {
        // td.end();
        // }
        // } catch (TransactionDemarcationException tde) {
        // if (isLoggingError()) {
        // logError("RekeyEngine.reKey:" + "Transaction Exception.", tde);
        // }
        // } catch (RepositoryException e) {
        // if (isLoggingError()) {
        // logError("RekeyEngine.reKey:" + "Repository Exception.", e);
        // }
        // }

    }

    /**
     * Generate new data password.
     *
     * @return the string
     */
    private String generateNewDataPassphrase() {
        String newDataPassphrase = new BigInteger(130, new SecureRandom()).toString(32);
        if (isLoggingDebug()) {
            logDebug("RekeyEngine.generateNewDataPassphrase:" + "newDataPassphrase is: " + newDataPassphrase);
        }
        return newDataPassphrase;
    }

    /*
     * (non-Javadoc)
     *
     * @see atg.nucleus.GenericService#doStartService()
     */
    @Override
    public void doStartService() throws ServiceException {
        // TODO Validations
    }

    /**
     * Gets the decryptor component.
     *
     * @return the decryptor component
     */
    public Object getDecryptorComponent() {
        return mDecryptorComponent;
    }

    /**
     * Sets the decryptor component.
     *
     * @param pDecryptorComponent
     *            the new decryptor component
     */
    public void setDecryptorComponent(Object pDecryptorComponent) {
        mDecryptorComponent = pDecryptorComponent;
    }

    /**
     * Gets the decryptor method.
     *
     * @return the decryptor method
     */
    public String getDecryptorMethod() {
        return mDecryptorMethod;
    }

    /**
     * Sets the decryptor method.
     *
     * @param pDecryptorMethod
     *            the new decryptor method
     */
    public void setDecryptorMethod(String pDecryptorMethod) {
        mDecryptorMethod = pDecryptorMethod;
    }

    /**
     * Gets the new key passphrase.
     *
     * @return the new key passphrase
     */
    public String getNewKeyPassphrase() {
        return mNewKeyPassphrase;
    }

    /**
     * Sets the new key passphrase.
     *
     * @param pNewKeyPassphrase
     *            the new new key passphrase
     */
    public void setNewKeyPassphrase(String pNewKeyPassphrase) {
        mNewKeyPassphrase = pNewKeyPassphrase;
    }

    /**
     * Gets the data data source.
     *
     * @return the data data source
     */
    public DataSource getDataDataSource() {
        return mDataDataSource;
    }

    /**
     * Sets the data data source.
     *
     * @param pDataDataSource
     *            the new data data source
     */
    public void setDataDataSource(DataSource pDataDataSource) {
        mDataDataSource = pDataDataSource;
    }

    /**
     * Gets the crypto repository.
     *
     * @return the crypto repository
     */
    public MutableRepository getCryptoRepository() {
        return mCryptoRepository;
    }

    /**
     * Sets the crypto repository.
     *
     * @param pCryptoRepository
     *            the new crypto repository
     */
    public void setCryptoRepository(MutableRepository pCryptoRepository) {
        mCryptoRepository = pCryptoRepository;
    }

    /**
     * Gets the table columns.
     *
     * @return the table columns
     */
    public List<String> getTableColumns() {
        return mTableColumns;
    }

    /**
     * Sets the table columns.
     *
     * @param pTableColumns
     *            the new table columns
     */
    public void setTableColumns(List<String> pTableColumns) {
        mTableColumns = pTableColumns;
    }

    /**
     * Gets the engine to update.
     *
     * @return the engine to update
     */
    public CryptoEngine getEngineToUpdate() {
        return mEngineToUpdate;
    }

    /**
     * Sets the engine to update.
     *
     * @param pEngineToUpdate
     *            the new engine to update
     */
    public void setEngineToUpdate(CryptoEngine pEngineToUpdate) {
        mEngineToUpdate = pEngineToUpdate;
    }
}