org.wso2.carbon.apimgt.core.impl.FileEncryptionUtility.java Source code

Java tutorial

Introduction

Here is the source code for org.wso2.carbon.apimgt.core.impl.FileEncryptionUtility.java

Source

/*
 * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
 *
 * WSO2 Inc. licenses this file to you 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.wso2.carbon.apimgt.core.impl;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.wso2.carbon.apimgt.core.configuration.models.FileEncryptionConfigurations;
import org.wso2.carbon.apimgt.core.exception.APIManagementException;
import org.wso2.carbon.apimgt.core.exception.APIMgtDAOException;
import org.wso2.carbon.apimgt.core.internal.ServiceReferenceHolder;
import org.wso2.carbon.apimgt.core.util.APIFileUtils;
import org.wso2.carbon.secvault.SecureVault;
import org.wso2.carbon.secvault.SecureVaultUtils;
import org.wso2.carbon.secvault.exception.SecureVaultException;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.List;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;

import static org.wso2.carbon.apimgt.core.util.APIMgtConstants.EncryptionConstants;

/**
 *  Class for File Encryption Related functions
 */
public class FileEncryptionUtility {
    private static final Logger log = LoggerFactory.getLogger(FileEncryptionUtility.class);
    private static final FileEncryptionUtility instance = new FileEncryptionUtility();
    private static final int AES_Key_Size = 128;

    public static final String CARBON_HOME = "carbon.home";
    public static final String SECURITY_DIR = File.separator + "resources" + File.separator + "security";

    private FileEncryptionConfigurations config;
    private String aesKeyFileLocation;
    private SecureVault secureVault;

    /**
     * Gives FileEncryptionUtility instance
     *
     * @return FileEncryptionUtility object
     */
    public static FileEncryptionUtility getInstance() {
        return instance;
    }

    /**
     * Sets the location to store the encrypted AES key file
     * Sets secure vault instance to encrypt AES key
     * Calls createAndStoreAESKey() method
     *
     * @throws APIManagementException if an error occurs while initializing the file encryption
     */
    public void init() throws APIManagementException {
        setConfig(ServiceReferenceHolder.getInstance().getAPIMConfiguration().getFileEncryptionConfigurations());
        setAesKeyFileLocation();
        setSecureVault(ServiceReferenceHolder.getInstance().getSecureVault());
        if (secureVault == null) {
            throw new APIManagementException("Secure vault OSGi service cannot be accessed");
        }
        createAndStoreAESKey();
    }

    /**
     * Encrypts the contents of a file and stores it in a new file
     *
     * @param inputFilePath    absolute path of the file to encrypt
     * @param outputFilePath   expected absolute path of the new encrypted file
     * @throws APIManagementException  if an error occurs encrypting the file
     */
    public void encryptFile(String inputFilePath, String outputFilePath) throws APIManagementException {
        InputStream inputStream = null;
        CipherOutputStream cipherOutStream = null;
        try {
            Cipher aesCipher = Cipher.getInstance(EncryptionConstants.AES);
            SecretKeySpec aesKeySpec = new SecretKeySpec(getAESKey(), EncryptionConstants.AES);
            aesCipher.init(Cipher.ENCRYPT_MODE, aesKeySpec);

            Files.deleteIfExists(Paths.get(outputFilePath));
            inputStream = APIFileUtils.readFileContentAsStream(inputFilePath);
            cipherOutStream = new CipherOutputStream(new FileOutputStream(outputFilePath), aesCipher);
            IOUtils.copy(inputStream, cipherOutStream);
            APIFileUtils.deleteFile(inputFilePath);
            log.debug("Successfully encrypted file using stored AES key");
        } catch (NoSuchPaddingException | NoSuchAlgorithmException | IOException | InvalidKeyException e) {
            String msg = "Error while encrypting the file at " + inputFilePath;
            throw new APIManagementException(msg, e);
        } finally {
            IOUtils.closeQuietly(inputStream);
            IOUtils.closeQuietly(cipherOutStream);
        }
    }

    /**
     * Decrypts the content of an encrypted file and returns the text
     *
     * @param inputFilePath  absolute path of the encrypted file
     * @return content of the file after decryption
     * @throws APIManagementException if an error occurs while reading from the encrypted file
     */
    public String readFromEncryptedFile(String inputFilePath) throws APIManagementException {
        CipherInputStream cipherInStream = null;
        ByteArrayOutputStream byteArrayOutStream = null;
        try {
            if (!Files.exists(Paths.get(inputFilePath))) {
                throw new APIManagementException("File to decrypt does not exist");
            }
            Cipher aesCipher = Cipher.getInstance(EncryptionConstants.AES);
            SecretKeySpec aesKeySpec = new SecretKeySpec(getAESKey(), EncryptionConstants.AES);
            aesCipher.init(Cipher.DECRYPT_MODE, aesKeySpec);

            cipherInStream = new CipherInputStream(APIFileUtils.readFileContentAsStream(inputFilePath), aesCipher);
            byteArrayOutStream = new ByteArrayOutputStream();
            IOUtils.copy(cipherInStream, byteArrayOutStream);
            byte[] outByteArray = byteArrayOutStream.toByteArray();
            log.debug("Successfully decrypted file using stored AES key");
            return new String(SecureVaultUtils.toChars(outByteArray));
        } catch (IOException | InvalidKeyException | NoSuchPaddingException | NoSuchAlgorithmException e) {
            String msg = "Error while decrypting file " + inputFilePath;
            throw new APIManagementException(msg, e);
        } finally {
            IOUtils.closeQuietly(cipherInStream);
            IOUtils.closeQuietly(byteArrayOutStream);
        }
    }

    /**
     * Encrypts the list of files given in the configuration, which are located /resources/security directory.
     * Encrypted files will have "encrypted" before its original name.
     *
     * @throws APIManagementException if an error occurs while encrypting the list of files
     */
    public void encryptFiles() throws APIManagementException {
        List<String> namesOfFilesToEncrypt = getConfig().getFilesToEncrypt();
        String encryptedFilesLocation = System.getProperty(CARBON_HOME) + SECURITY_DIR + File.separator;
        for (String filename : namesOfFilesToEncrypt) {
            String originalFile = encryptedFilesLocation + filename;
            String encryptedFile = encryptedFilesLocation + "encrypted" + filename;
            encryptFile(originalFile, encryptedFile);
        }
    }

    /**
     * Creates and stores an AES key
     *
     * @throws APIManagementException if an error occurs while creating or storing AES key
     */
    void createAndStoreAESKey() throws APIManagementException {
        try {
            //create a new AES key
            KeyGenerator keyGenerator = KeyGenerator.getInstance(EncryptionConstants.AES);
            keyGenerator.init(AES_Key_Size);
            byte[] aesKey = keyGenerator.generateKey().getEncoded();

            //store key => encrypt -> encode -> chars -> string
            byte[] encryptedKeyBytes = SecureVaultUtils.base64Encode(getSecureVault().encrypt(aesKey));
            String encryptedKeyString = new String(SecureVaultUtils.toChars(encryptedKeyBytes));

            Files.deleteIfExists(Paths.get(getAesKeyFileLocation()));
            APIFileUtils.createFile(getAesKeyFileLocation());
            APIFileUtils.writeToFile(getAesKeyFileLocation(), encryptedKeyString);
            log.debug("AES key successfully created and stored");
        } catch (NoSuchAlgorithmException | SecureVaultException | APIMgtDAOException | IOException e) {
            String msg = "Error while creating or storing created AES key";
            throw new APIManagementException(msg, e);
        }
    }

    /**
     * Decrypts the AES key using secure vault and returns it as a byte array
     *
     * @return AES key as a byte array
     * @throws APIManagementException if an error occurs while reading or decrypting the AES key file
     */
    private byte[] getAESKey() throws APIManagementException {
        byte[] encryptedAesKeyB;
        byte[] aesKey;
        try {
            String encryptedAesKeyStr = APIFileUtils.readFileContentAsText(getAesKeyFileLocation());
            encryptedAesKeyB = SecureVaultUtils.base64Decode(SecureVaultUtils.toBytes(encryptedAesKeyStr));
            aesKey = getSecureVault().decrypt(encryptedAesKeyB);
        } catch (APIMgtDAOException e) {
            String msg = "Error while retrieving stored AES key";
            throw new APIManagementException(msg, e);
        } catch (SecureVaultException e) {
            String msg = "Error while decrypting AES key";
            throw new APIManagementException(msg, e);
        }
        return aesKey;
    }

    public FileEncryptionConfigurations getConfig() {
        return config;
    }

    public void setConfig(FileEncryptionConfigurations config) {
        this.config = config;
    }

    String getAesKeyFileLocation() {
        return aesKeyFileLocation;
    }

    void setAesKeyFileLocation() {
        this.aesKeyFileLocation = System.getProperty(CARBON_HOME) + SECURITY_DIR + File.separator
                + EncryptionConstants.ENCRYPTED_AES_KEY_FILE;
    }

    SecureVault getSecureVault() {
        return secureVault;
    }

    void setSecureVault(SecureVault secureVault) {
        this.secureVault = secureVault;
    }
}