org.yes.cart.shoppingcart.support.impl.AbstractCryptedTuplizerImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.yes.cart.shoppingcart.support.impl.AbstractCryptedTuplizerImpl.java

Source

/*
 * Copyright 2009 Denys Pavlov, Igor Azarnyi
 *
 *    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.yes.cart.shoppingcart.support.impl;

import org.apache.commons.codec.binary.Base64InputStream;
import org.apache.commons.codec.binary.Base64OutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.yes.cart.shoppingcart.ShoppingCart;
import org.yes.cart.shoppingcart.support.CartDetuplizationException;
import org.yes.cart.shoppingcart.support.CartTuplizationException;

import javax.crypto.*;
import javax.crypto.spec.DESKeySpec;
import java.io.*;
import java.security.InvalidKeyException;
import java.text.MessageFormat;

/**
 * Default implementation of cookie tuplizer.
 * <p/>
 * The cookies are crypted in base64 form. According to RFC 2109
 * specification cookie storage limit at least 300 cookies at least 4096
 * bytes per cookie, so it allow to store 1228800 bytes aprox 1 Mb.
 * Base64 representation will be splited to chunks.
 * <p/>
 * User: dogma
 * Date: 2011-May-17
 * Time: 2:17:57 PM
 */
public abstract class AbstractCryptedTuplizerImpl {

    private static final long serialVersionUID = 20100116L;

    private static final Logger LOG = LoggerFactory.getLogger(AbstractCryptedTuplizerImpl.class);

    private final Cipher desCipher;
    private final Cipher desUnCipher;

    private SecretKey secretKey;

    /**
     * Default Constructor.
     *
     * @param keyRingPassword      key ring password to use.
     * @param secretKeyFactoryName Secret Key Factory Name.
     * @param cipherName           Cipher name.
     */
    public AbstractCryptedTuplizerImpl(final String keyRingPassword, final String secretKeyFactoryName,
            final String cipherName) {

        try {
            final DESKeySpec desKeySpec = new DESKeySpec(keyRingPassword.getBytes());

            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(secretKeyFactoryName);
            secretKey = keyFactory.generateSecret(desKeySpec);

            // Create Cipher
            desCipher = Cipher.getInstance(cipherName);
            desCipher.init(Cipher.ENCRYPT_MODE, secretKey);

            // create uncipher
            desUnCipher = Cipher.getInstance(cipherName);
            desUnCipher.init(Cipher.DECRYPT_MODE, secretKey);
        } catch (Exception ike) {
            LOG.error(ike.getMessage(), ike);
            throw new RuntimeException("Unable to load Cipher for CookieTuplizer", ike);
        }

    }

    /**
     * Converts cart object into a String tuple.
     *
     * @param serializable cart
     *
     * @return string
     *
     * @throws CartTuplizationException when cannot convert to string tuple
     */
    protected String toToken(final Serializable serializable) throws CartTuplizationException {

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        synchronized (desCipher) {
            Base64OutputStream base64EncoderStream = new Base64OutputStream(byteArrayOutputStream, true,
                    Integer.MAX_VALUE, null); //will be split manually
            CipherOutputStream cipherOutputStream = new CipherOutputStream(base64EncoderStream, desCipher);
            ObjectOutputStream objectOutputStream = null;
            try {
                objectOutputStream = new ObjectOutputStream(cipherOutputStream);
                objectOutputStream.writeObject(serializable);
                objectOutputStream.flush();
                objectOutputStream.close();
            } catch (Throwable ioe) {
                LOG.error(MessageFormat.format("Unable to serialize object {0}", serializable), ioe);
                throw new CartTuplizationException(ioe);
            } finally {
                try {
                    if (objectOutputStream != null) {
                        objectOutputStream.close();
                    }
                    cipherOutputStream.close();
                    base64EncoderStream.close();
                    byteArrayOutputStream.close();
                } catch (IOException e) {
                    LOG.error("Can not close stream", e);
                }
            }
        }

        return byteArrayOutputStream.toString();

    }

    /**
     * Convert string tuple back to the original object.
     *
     * @param tuple string tuple
     *
     * @return cart object of null
     *
     * @throws CartDetuplizationException when cannot deserialize the object
     */
    protected ShoppingCart toObject(String tuple) throws CartDetuplizationException {

        if (tuple == null || tuple.length() == 0) {
            return null;
        }
        final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(tuple.getBytes());
        final Base64InputStream base64DecoderStream = new Base64InputStream(byteArrayInputStream);
        final CipherInputStream cipherInputStream = new CipherInputStream(base64DecoderStream, desUnCipher);
        ObjectInputStream objectInputStream = null;
        try {
            objectInputStream = new ObjectInputStream(cipherInputStream);
            return (ShoppingCart) objectInputStream.readObject();

        } catch (Exception exception) {
            try {
                desUnCipher.init(Cipher.DECRYPT_MODE, secretKey); //reinit
            } catch (InvalidKeyException e) {
                LOG.error("Cant reinit desUnCipher", exception);
            }
            final String errMsg = "Unable to convert bytes assembled from tuple into object";
            LOG.error(errMsg, exception);
            throw new CartDetuplizationException(errMsg, exception);
        } finally {
            try {
                if (objectInputStream != null) {
                    objectInputStream.close();
                }
                cipherInputStream.close();
                base64DecoderStream.close();
                byteArrayInputStream.close();
            } catch (IOException ioe) { // leave this one silent as we have the object.
                LOG.error("Unable to close object stream", ioe);
            }

        }
    }

}