ninja.utils.CookieEncryption.java Source code

Java tutorial

Introduction

Here is the source code for ninja.utils.CookieEncryption.java

Source

/*
 * Copyright 2015 ninjaframework.
 *
 * 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 ninja.utils;

import com.google.common.base.Optional;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.util.Objects;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.security.NoSuchAlgorithmException;

/**
 * This class encrypts/decrypts session cookie data. Resultant encrypted strings are encoded in base64, and decryption
 * expects base64 encoded string.
 */
@Singleton
public class CookieEncryption {

    public static final String ALGORITHM = "AES";

    private static final Logger logger = LoggerFactory.getLogger(CookieEncryption.class);

    private final Optional<SecretKeySpec> secretKeySpec;

    private final boolean encryptionEnabled;

    @Inject
    public CookieEncryption(NinjaProperties properties) {

        Optional<SecretKeySpec> secretKeySpec = Optional.absent();

        if (properties.getBooleanWithDefault(NinjaConstant.applicationCookieEncrypted, false)) {

            encryptionEnabled = true;

            String secret = properties.getOrDie(NinjaConstant.applicationSecret);
            try {
                int maxKeyLengthBits = Cipher.getMaxAllowedKeyLength(ALGORITHM);
                if (maxKeyLengthBits == Integer.MAX_VALUE) {
                    maxKeyLengthBits = 256;
                }

                secretKeySpec = Optional
                        .of(new SecretKeySpec(secret.getBytes(), 0, maxKeyLengthBits / Byte.SIZE, ALGORITHM));

                logger.info("Ninja session encryption is using {} / {} bit.", secretKeySpec.get().getAlgorithm(),
                        maxKeyLengthBits);

            } catch (Exception exception) {
                logger.error("Can not create class to encrypt cookie.", exception);
                throw new RuntimeException(exception);
            }

        } else {
            encryptionEnabled = false;
            secretKeySpec = Optional.absent();
        }

        this.secretKeySpec = secretKeySpec;

    }

    /**
     * Encrypts data with secret key.
     *
     * @param data text to encrypt
     * @return encrypted text in base64 format
     */
    public String encrypt(String data) {

        Objects.requireNonNull(data, "Data to be encrypted");

        if (!encryptionEnabled) {
            return data;
        }

        try {
            // encrypt data
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec.get());
            byte[] encrypted = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));

            // convert encrypted bytes to string in base64
            return Base64.encodeBase64URLSafeString(encrypted);

        } catch (InvalidKeyException ex) {
            logger.error(getHelperLogMessage(), ex);
            throw new RuntimeException(ex);
        } catch (GeneralSecurityException ex) {
            logger.error("Failed to encrypt data.", ex);
            throw new RuntimeException(ex);
        }
    }

    /**
     * Decrypts data with secret key.
     *
     * @param data text to decrypt in base64 format
     * @return decrypted text
     */
    public String decrypt(String data) {

        Objects.requireNonNull(data, "Data to be decrypted");

        if (!encryptionEnabled) {
            return data;
        }

        // convert base64 encoded string to bytes
        byte[] decoded = Base64.decodeBase64(data);
        try {
            // decrypt bytes
            Cipher cipher = Cipher.getInstance(ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec.get());
            byte[] decrypted = cipher.doFinal(decoded);

            // convert bytes to string
            return new String(decrypted, StandardCharsets.UTF_8);

        } catch (InvalidKeyException ex) {
            logger.error(getHelperLogMessage(), ex);
            throw new RuntimeException(ex);
        } catch (GeneralSecurityException ex) {
            logger.error("Failed to decrypt data.", ex);
            throw new RuntimeException(ex);
        }
    }

    private String getHelperLogMessage() {
        StringBuilder sb = new StringBuilder();
        sb.append("Invalid key provided. Check if application secret is properly set.")
                .append(System.lineSeparator());
        sb.append("You can remove '").append(NinjaConstant.applicationSecret)
                .append("' key in configuration file ");
        sb.append("and restart application. Ninja will generate new key for you.");
        return sb.toString();
    }
}