/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF 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.securevault.tool; import org.apache.commons.cli.*; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.synapse.securevault.*; import org.apache.synapse.securevault.definition.CipherInformation; import org.apache.synapse.securevault.definition.IdentityKeyStoreInformation; import org.apache.synapse.securevault.definition.TrustKeyStoreInformation; import org.apache.synapse.securevault.keystore.IdentityKeyStoreWrapper; import org.apache.synapse.securevault.keystore.KeyStoreWrapper; import org.apache.synapse.securevault.keystore.TrustKeyStoreWrapper; import org.apache.synapse.securevault.secret.SecretInformation; import javax.crypto.spec.SecretKeySpec; import java.io.*; import java.security.Key; /** * Tool for encrypting and decrypting. <br> * <br> * Arguments and their meanings: * <ul> * <li>source Either cipher or plain text as an in-lined form * <li>sourceFile Source from a file * <li>passphrase if a simple symmetric encryption using a pass phrase shall be used * <li>keystore If keys are in a store, it's location * <li>storepass Password for access keyStore * <li>keypass To get private key * <li>alias Alias to identify key owner * <li>storetype Type of keyStore * <li>keyfile If key is in a file * <li>trusted Is KeyStore a trusted store ? . if presents this , consider as a trusted store * <li>opmode encrypt or decrypt * <li>algorithm encrypt or decrypt algorithm (default RSA) * <li>outencode Currently BASE64 or BIGINTEGER16 * <li>inencode Currently BASE64 or BIGINTEGER16 * <p/> * <ul> */ public final class CipherTool { /* The cipher or plain text as an in-lined */ private static final String SOURCE_IN_LINED = "source"; /* The the source from a file*/ private static final String SOURCE_FILE = "sourcefile"; /* Pass phrase to use for en- or decryption. */ private static final String PASSPHRASE = "passphrase"; /* The argument name for KeyStore location */ private static final String KEY_STORE = "keystore"; /* The KeyStore type*/ private static final String STORE_TYPE = "storetype"; /* The argument name for password to access KeyStore*/ private static final String STORE_PASS = "storepass"; /* The argument name for password for access private key */ private static final String KEY_PASS = "keypass"; /* The alias to identify key owner */ private static final String ALIAS = "alias"; /* If the key is from a file , then it's location*/ private static final String KEY_FILE = "keyfile"; /* The algorithm for encrypting or decrypting */ private static final String ALGORITHM = "algorithm"; /* The operation mode of cihper - encrypt or decrypt */ private static final String OP_MODE = "opmode"; /* The cipher type - asymmetric , symmetric */ private static final String CIPHER_TYPE = "ciphertype"; /* If the target has to be written to a file*/ private static final String TARGET_FILE = "targetfile"; /* If the output of cipher operation need to be encode - only base64*/ private static final String OUT_TYPE = "outencode"; /* If the encode of the input type base64*/ private static final String IN_TYPE = "inencode"; /* Is this keyStore a trusted one */ private static final String TRUSTED = "trusted"; private static Log log = LogFactory.getLog(CipherTool.class); private CipherTool() { } public static void main(String[] args) throws Exception { // loads the options Options options = getOptions(); // create the command line parser CommandLineParser parser = new GnuParser(); // parse the command line arguments try { CommandLine cmd = parser.parse(options, args); // Loads the cipher relate information CipherInformation cipherInformation = getCipherInformation(cmd); // Source as an in-lined String source = getArgument(cmd, SOURCE_IN_LINED, null); assertEmpty(source, SOURCE_IN_LINED); Key key = findKey(cmd, cipherInformation); boolean isEncrypt = (cipherInformation.getCipherOperationMode() == CipherOperationMode.ENCRYPT); EncryptionProvider encryptionProvider = null; DecryptionProvider decryptionProvider = null; if (key != null) { if (isEncrypt) { encryptionProvider = CipherFactory.createCipher(cipherInformation, key); } else { decryptionProvider = CipherFactory.createCipher(cipherInformation, key); } } else { boolean isTrusted = isArgumentPresent(cmd, TRUSTED); KeyStoreWrapper keyStoreWrapper; if (isTrusted) { keyStoreWrapper = new TrustKeyStoreWrapper(); ((TrustKeyStoreWrapper) keyStoreWrapper).init(getTrustKeyStoreInformation(cmd)); } else { keyStoreWrapper = new IdentityKeyStoreWrapper(); //Password for access private key String keyPass = getArgument(cmd, KEY_PASS, null); assertEmpty(keyPass, KEY_PASS); ((IdentityKeyStoreWrapper) keyStoreWrapper).init( getIdentityKeyStoreInformation(cmd), keyPass); } if (isEncrypt) { encryptionProvider = CipherFactory.createCipher(cipherInformation, keyStoreWrapper); } else { decryptionProvider = CipherFactory.createCipher(cipherInformation, keyStoreWrapper); } } PrintStream out = System.out; if (isEncrypt) { out.println("Output : " + new String(encryptionProvider.encrypt(source.getBytes()))); } else { out.println("Output : " + new String(decryptionProvider.decrypt(source.getBytes()))); } } catch (ParseException e) { handleException("Error passing arguments ", e); } } /** * Utility method to extract command line arguments * * @param cmd Command line which capture all command line arguments * @param argName Name of the argument to be extracted * @param defaultValue The default value * @return value of the argument if there is , o.w null */ private static String getArgument(CommandLine cmd, String argName, String defaultValue) { if (cmd == null) { handleException("CommandLine is null"); } if (argName == null || "".equals(argName)) { if (log.isDebugEnabled()) { log.debug("Provided argument name is null. Returning null as value"); } return defaultValue; } if (cmd.hasOption(argName)) { return cmd.getOptionValue(argName); } return defaultValue; } /** * Utility method to find boolean argument * * @param cmd Command line which capture all command line arguments * @param argName Name of the argument to be extracted * @return True if presents */ private static boolean isArgumentPresent(CommandLine cmd, String argName) { if (cmd == null) { handleException("CommandLine is null"); } if (argName == null || "".equals(argName)) { if (log.isDebugEnabled()) { log.debug("Provided argument name is null. Returning null as value"); } return false; } return cmd.hasOption(argName); } /** * Factory method to construct @see CipherInformation from command line options * * @param cmd Command line which capture all command line arguments * @return CipherInformation object */ private static CipherInformation getCipherInformation(CommandLine cmd) { CipherInformation information = new CipherInformation(); information.setAlgorithm(getArgument(cmd, ALGORITHM, CipherInformation.DEFAULT_ALGORITHM)); information.setCipherOperationMode(CipherOperationMode.valueOf( getArgument(cmd, OP_MODE, CipherOperationMode.ENCRYPT.toString()).toUpperCase())); String encInType = getArgument(cmd, IN_TYPE, null); if (encInType != null) { information.setInType(EncodingType.valueOf(encInType.toUpperCase())); } String encOutType = getArgument(cmd, OUT_TYPE, null); if (encOutType != null) { information.setOutType(EncodingType.valueOf(encOutType.toUpperCase())); } information.setType(getArgument(cmd, CIPHER_TYPE, null)); return information; } /** * Factory method to create a @see keyStoreInformation from command line options * * @param cmd Command line which capture all command line arguments * @return KeyStoreInformation object */ private static IdentityKeyStoreInformation getIdentityKeyStoreInformation(CommandLine cmd) { IdentityKeyStoreInformation information = new IdentityKeyStoreInformation(); String alias = getArgument(cmd, ALIAS, null); assertEmpty(alias, ALIAS); information.setAlias(alias); String keyStore = getArgument(cmd, KEY_STORE, null); assertEmpty(keyStore, KEY_STORE); information.setLocation(keyStore); information.setStoreType(getArgument(cmd, STORE_TYPE, KeyStoreType.JKS.toString())); String storePass = getArgument(cmd, STORE_PASS, null); assertEmpty(storePass, STORE_PASS); SecretInformation secretInformation = new SecretInformation(); secretInformation.setAliasSecret(storePass); information.setKeyStorePasswordProvider(secretInformation); return information; } /** * Factory method to create a @see keyStoreInformation from command line options * * @param cmd Command line which capture all command line arguments * @return KeyStoreInformation object */ private static TrustKeyStoreInformation getTrustKeyStoreInformation(CommandLine cmd) { TrustKeyStoreInformation information = new TrustKeyStoreInformation(); information.setAlias(getArgument(cmd, ALIAS, null)); String keyStore = getArgument(cmd, KEY_STORE, null); assertEmpty(keyStore, KEY_STORE); information.setLocation(keyStore); information.setStoreType(getArgument(cmd, STORE_TYPE, KeyStoreType.JKS.toString())); String storePass = getArgument(cmd, STORE_PASS, null); assertEmpty(storePass, STORE_PASS); SecretInformation secretInformation = new SecretInformation(); secretInformation.setAliasSecret(storePass); information.setKeyStorePasswordProvider(secretInformation); return information; } /** * Factory method to create options * * @return Options object */ private static Options getOptions() { Options options = new Options(); Option source = new Option(SOURCE_IN_LINED, true, "Plain text in-lined"); Option sourceFile = new Option(SOURCE_FILE, true, "Plain text from a file"); Option passphrase = new Option(PASSPHRASE, true, "Passphrase to use for symmetric en- or decryption."); Option keyStore = new Option(KEY_STORE, true, "Private key entry KeyStore"); Option storeType = new Option(STORE_TYPE, true, " KeyStore type"); Option storePassword = new Option(STORE_PASS, true, "Password for keyStore access"); Option keyPassword = new Option(KEY_PASS, true, "Password for access private key entry"); Option alias = new Option(ALIAS, true, "Alias name for identify key owner"); Option trusted = new Option(TRUSTED, false, "Is this KeyStore trusted one"); Option keyFile = new Option(KEY_FILE, true, "Private key from a file"); Option cipherType = new Option(CIPHER_TYPE, true, "Cipher type"); Option opMode = new Option(OP_MODE, true, "encrypt or decrypt"); Option algorithm = new Option(ALGORITHM, true, "Algorithm to be used"); Option targetFile = new Option(TARGET_FILE, true, "Target file"); Option outType = new Option(OUT_TYPE, true, "Encode type for output"); Option intType = new Option(IN_TYPE, true, "Encode type of input source"); options.addOption(source); options.addOption(sourceFile); options.addOption(passphrase); options.addOption(keyStore); options.addOption(storeType); options.addOption(storePassword); options.addOption(keyPassword); options.addOption(alias); options.addOption(trusted); options.addOption(keyFile); options.addOption(algorithm); options.addOption(cipherType); options.addOption(opMode); options.addOption(targetFile); options.addOption(outType); options.addOption(intType); return options; } /** * Factory method to retrieve a previously stored key in a file * * @param filePath Path to file * @return Retrieved key */ private static Key getKey(String filePath) { if (filePath == null || "".equals(filePath)) { handleException("File path cannot be empty or null"); } File keyFile = new File(filePath); if (!keyFile.exists()) { handleException("File cannot be found in : " + filePath); } ObjectInputStream in = null; try { in = new ObjectInputStream(new FileInputStream(keyFile)); Object object = in.readObject(); if (object instanceof Key) { return (Key) object; } } catch (IOException e) { handleException("Error reading key from given path : " + filePath, e); } catch (ClassNotFoundException e) { handleException("Cannot load a key from the file : " + filePath, e); } finally { if (in != null) { try { in.close(); } catch (IOException ignored) { } } } return null; } /** * Find the key based on the given command line arguments * * @param cmd command line arguments * @param cipherInformation cipher information * @return an valid <code>Key</code> if found , otherwise */ private static Key findKey(CommandLine cmd, CipherInformation cipherInformation) { // if pass phrase is specified, use simple symmetric en-/decryption String passPhrase = getArgument(cmd, PASSPHRASE, null); Key key = null; if (passPhrase != null) { key = new SecretKeySpec(passPhrase.getBytes(), cipherInformation.getAlgorithm()); } else { // Key information must not contain any password // If Key need to be loaded from a file String keyFile = getArgument(cmd, KEY_FILE, null); if (keyFile != null) { key = getKey(keyFile); } } return key; } private static void handleException(String msg, Exception e) { log.error(msg, e); throw new SecureVaultException(msg, e); } private static void handleException(String msg) { log.error(msg); throw new SecureVaultException(msg); } private static void assertEmpty(String value, String key) { if (value == null || "".equals(value)) { handleException("The argument : " + key + " : cannot be null or empty."); } } }