# CryptoUtil.java

    /*
    * Copyright (c) 2016, 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.apache.synapse.commons.crypto;

    import org.apache.axis2.AxisFault;
    import org.apache.commons.lang.StringUtils;
    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.wso2.securevault.CipherFactory;
    import org.wso2.securevault.CipherOperationMode;
    import org.wso2.securevault.DecryptionProvider;
    import org.wso2.securevault.commons.MiscellaneousUtil;
    import org.wso2.securevault.definition.CipherInformation;
    import org.wso2.securevault.definition.IdentityKeyStoreInformation;
    import org.wso2.securevault.definition.KeyStoreInformationFactory;
    import org.wso2.securevault.keystore.IdentityKeyStoreWrapper;

    import java.security.Provider;
    import java.security.Security;
    import java.util.Properties;

    /**
     * This class will provide the required methods to decrypt given encrypted parameter value.
     */
    public class CryptoUtil {
        private static Log log = LogFactory.getLog(CryptoUtil.class);
        private DecryptionProvider baseCipher;
        private boolean isInitialized = false;
        private EncodeDecodeTypes inType = null;
        private EncodeDecodeTypes outType = null;
        private String algorithm = null;
        private static final String SECURITY_JCE_PROVIDER = "security.jce.provider";

        /**
         * Public constructor
         *
         * @param secureVaultProperties
         * @throws org.apache.axis2.AxisFault
         */
        public CryptoUtil(Properties secureVaultProperties) throws AxisFault {
            init(secureVaultProperties);
        }

        /**
         * Method to initialise crypto util. which will generate the required cipher etc.
         *
         * @param secureVaultProperties
         * @throws org.apache.axis2.AxisFault
         */
        public void init(Properties secureVaultProperties) throws AxisFault {
            //Create a KeyStore Information  for private key entry KeyStore
            IdentityKeyStoreInformation identityInformation =
                    KeyStoreInformationFactory.createIdentityKeyStoreInformation(secureVaultProperties);
            String identityKeyPass = null;
            String identityStorePass = null;
            if (identityInformation != null) {
                identityKeyPass = identityInformation
                        .getKeyPasswordProvider().getResolvedSecret();
                identityStorePass = identityInformation
                        .getKeyStorePasswordProvider().getResolvedSecret();
            }
            if (!Util.validatePasswords(identityStorePass, identityKeyPass)) {
                if (log.isDebugEnabled()) {
                    log.info("Either Identity or Trust keystore password is mandatory" +
                             " in order to initialized secret manager.");
                }
                throw new AxisFault("Error inititialising cryptoutil, required parameters not provided");
            }
            IdentityKeyStoreWrapper identityKeyStoreWrapper = new IdentityKeyStoreWrapper();
            identityKeyStoreWrapper.init(identityInformation, identityKeyPass);
            algorithm = MiscellaneousUtil.getProperty(secureVaultProperties,
                                                             CryptoConstants.CIPHER_ALGORITHM,
                                                             CryptoConstants.CIPHER_ALGORITHM_DEFAULT);
            String provider = MiscellaneousUtil.getProperty(secureVaultProperties,
                                                            CryptoConstants.SECURITY_PROVIDER, null);
            String cipherType = MiscellaneousUtil.getProperty(secureVaultProperties,
                                                              CryptoConstants.CIPHER_TYPE, null);

            String inTypeString = MiscellaneousUtil.getProperty(secureVaultProperties, CryptoConstants.INPUT_ENCODE_TYPE,
                                                                null);
            inType = Util.getEncodeDecodeType(inTypeString, EncodeDecodeTypes.BASE64);

            String outTypeString = MiscellaneousUtil.getProperty(secureVaultProperties, CryptoConstants.OUTPUT_ENCODE_TYPE,
                                                                 null);
            outType = Util.getEncodeDecodeType(outTypeString, null);

            CipherInformation cipherInformation = new CipherInformation();
            cipherInformation.setAlgorithm(algorithm);
            cipherInformation.setCipherOperationMode(CipherOperationMode.DECRYPT);
            cipherInformation.setType(cipherType);
            cipherInformation.setInType(null); //skipping decoding encoding in securevault
            cipherInformation.setOutType(null); //skipping decoding encoding in securevault
            if (provider != null && !provider.isEmpty()) {
                addProvider(provider);
                cipherInformation.setProvider(provider);
                //todo need to add other providers if there are any.
            }
            baseCipher = CipherFactory.createCipher(cipherInformation, identityKeyStoreWrapper);
            isInitialized = true;
        }

        /**
         * Method used to decrypt and encode or decode accordingly.
         *
         * @param encryptedBytes
         * @return response
         */
        public byte[] decrypt(byte[] encryptedBytes) {
            if (inType != null) {
                encryptedBytes = EncodeDecodeHelper.decode(encryptedBytes, inType);
            }
            byte[] response;
            response = baseCipher.decrypt(encryptedBytes);
            if (outType != null) {
                response = EncodeDecodeHelper.encode(response, outType);
            }
            return response;
        }

        public boolean isInitialized() {
            return isInitialized;
        }

        private static void addProvider(String jceProvider) throws AxisFault {
            if (StringUtils.isEmpty(System.getProperty(SECURITY_JCE_PROVIDER))) {
                String providerClass;
                if (CryptoConstants.BOUNCY_CASTLE_FIPS_PROVIDER.equals(jceProvider)) {
                    providerClass = "org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider";
                } else {
                    providerClass = "org.bouncycastle.jce.provider.BouncyCastleProvider";
                }
                try {
                    Security.addProvider((Provider) Class.forName(providerClass).getDeclaredConstructor().newInstance());
                } catch (Exception e) {
                    throw new AxisFault("Error while initializing the JCE provider: " + providerClass, e);
                }
            }
        }

    }