001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyrighted [year] [name of copyright owner]". 013 * 014 * Copyright 2011-2016 ForgeRock AS. 015 */ 016 017package org.forgerock.json.crypto.cli; 018 019import java.io.File; 020import java.io.FileNotFoundException; 021import java.io.IOException; 022import java.security.Key; 023import java.security.KeyStore; 024 025import org.apache.commons.cli.CommandLine; 026import org.apache.commons.cli.CommandLineParser; 027import org.apache.commons.cli.HelpFormatter; 028import org.apache.commons.cli.Options; 029import org.apache.commons.cli.ParseException; 030import org.apache.commons.cli.PosixParser; 031import org.forgerock.json.JsonValue; 032import org.forgerock.json.crypto.JsonEncryptFunction; 033import org.forgerock.json.crypto.JsonCryptoException; 034import org.forgerock.json.crypto.JsonDecryptFunction; 035import org.forgerock.json.crypto.simple.SimpleDecryptor; 036import org.forgerock.json.crypto.simple.SimpleEncryptor; 037import org.forgerock.json.crypto.simple.SimpleKeyStoreSelector; 038import org.forgerock.security.keystore.KeyStoreBuilder; 039import org.forgerock.security.keystore.KeyStoreType; 040import org.forgerock.util.Utils; 041 042import com.fasterxml.jackson.databind.ObjectMapper; 043 044/** 045 * Command-line interface to encrypt/decrypt. 046 */ 047public class Main { 048 049 private static final ObjectMapper MAPPER = new ObjectMapper(); 050 private static final Options OPTIONS; // Command line options 051 052 private static final String PROPERTIES_ALIAS_OPTION = "alias"; 053 private static final String PROPERTIES_CIPHER_OPTION = "cipher"; 054 private static final String DEFAULT_CIPHER = "AES/CBC/PKCS5Padding"; 055 private static final String PROPERTIES_SRCJSON_OPTION = "srcjson"; 056 private static final String PROPERTIES_DESTJSON_OPTION = "destjson"; 057 private static final String PROPERTIES_KEYPASS_OPTION = "keypass"; 058 private static final String PROPERTIES_KEYSTORE_OPTION = "keystore"; 059 private static final String PROPERTIES_STOREPASS_OPTION = "storepass"; 060 private static final String PROPERTIES_STORETYPE_OPTION = "storetype"; 061 private static final String PROPERTIES_PROVIDERNAME_OPTION = "providername"; 062 private static final String PROPERTIES_PROVIDERCLASS_OPTION = "providerclass"; 063 private static final String PROPERTIES_PROVIDERARG_OPTION = "providerarg"; 064 private static final String PROPERTIES_PROVIDERPATH_OPTION = "providerpath"; 065 private static final String PROPERTIES_ENCRYPT_COMMAND = "encrypt"; 066 private static final String PROPERTIES_DECRYPT_COMMAND = "decrypt"; 067 private static final String PROPERTIES_HELP_COMMAND = "help"; 068 069 private CommandLine cmd = null; // Command Line arguments 070 071 static { 072 OPTIONS = new Options(); 073 OPTIONS.addOption(PROPERTIES_ENCRYPT_COMMAND, false, 074 "Encrypt input file"); 075 OPTIONS.addOption(PROPERTIES_DECRYPT_COMMAND, false, 076 "Decrypt input file"); 077 OPTIONS.addOption("h", PROPERTIES_HELP_COMMAND, false, 078 "Display help"); 079 080 081 //Required encryption options 082 OPTIONS.addOption(PROPERTIES_ALIAS_OPTION, true, 083 "Cryptography key alias."); 084 OPTIONS.addOption(PROPERTIES_CIPHER_OPTION, true, 085 "Cipher algorithm. " + DEFAULT_CIPHER + " by default"); 086 //Required input options 087 OPTIONS.addOption(PROPERTIES_SRCJSON_OPTION, true, 088 "Input JSON File"); 089 //Optional output options 090 OPTIONS.addOption(PROPERTIES_DESTJSON_OPTION, true, 091 "Output JSON File"); 092 //Required keystore options 093 OPTIONS.addOption(PROPERTIES_KEYSTORE_OPTION, true, 094 "KeyStore File"); 095 OPTIONS.addOption(PROPERTIES_STOREPASS_OPTION, true, 096 "KeyStore password."); 097 OPTIONS.addOption(PROPERTIES_STORETYPE_OPTION, true, 098 "KeyStore type. Default: " + KeyStore.getDefaultType()); 099 OPTIONS.addOption(PROPERTIES_KEYPASS_OPTION, true, 100 "Key password"); 101 OPTIONS.addOption(PROPERTIES_PROVIDERNAME_OPTION, true, 102 "KeyStore provider"); 103 OPTIONS.addOption(PROPERTIES_PROVIDERCLASS_OPTION, true, 104 "KeyStore provider class"); 105 OPTIONS.addOption(PROPERTIES_PROVIDERARG_OPTION, true, 106 "KeyStore provider options"); 107 OPTIONS.addOption(PROPERTIES_PROVIDERPATH_OPTION, true, 108 "KeyStore provider path"); 109 } 110 111 /** 112 * Entry point. 113 * @param args CLI Args. 114 * @throws Exception On error. 115 */ 116 public static void main(String[] args) throws Exception { 117 Main cliProg = new Main(); 118 cliProg.loadArgs(args); 119 cliProg.exec(); 120 } 121 122 /** 123 * Execute the CLI on the class instance. 124 * @throws Exception On error. 125 */ 126 public void exec() throws Exception { 127 if (cmd.hasOption(PROPERTIES_ENCRYPT_COMMAND)) { 128 Key key = getSimpleKeySelector(cmd.getOptionValue(PROPERTIES_KEYSTORE_OPTION), 129 cmd.getOptionValue(PROPERTIES_STORETYPE_OPTION, KeyStore.getDefaultType()), 130 cmd.getOptionValue(PROPERTIES_STOREPASS_OPTION), 131 cmd.getOptionValue(PROPERTIES_PROVIDERNAME_OPTION)) 132 .select(cmd.getOptionValue(PROPERTIES_ALIAS_OPTION)); 133 if (key == null) { 134 throw new JsonCryptoException("key not found: " + cmd.getOptionValue(PROPERTIES_ALIAS_OPTION)); 135 } 136 JsonEncryptFunction encrypt = new JsonEncryptFunction(new SimpleEncryptor( 137 cmd.getOptionValue(PROPERTIES_CIPHER_OPTION, DEFAULT_CIPHER), key, 138 cmd.getOptionValue(PROPERTIES_ALIAS_OPTION))); 139 JsonValue value = getSourceValue(cmd.getOptionValue(PROPERTIES_SRCJSON_OPTION), true); 140 setDestinationValue(cmd.getOptionValue(PROPERTIES_DESTJSON_OPTION), value.as(encrypt)); 141 } else if (cmd.hasOption(PROPERTIES_DECRYPT_COMMAND)) { 142 JsonDecryptFunction decrypt = new JsonDecryptFunction(new SimpleDecryptor( 143 getSimpleKeySelector(cmd.getOptionValue(PROPERTIES_KEYSTORE_OPTION), 144 cmd.getOptionValue(PROPERTIES_STORETYPE_OPTION, KeyStore.getDefaultType()), 145 cmd.getOptionValue(PROPERTIES_STOREPASS_OPTION), 146 cmd.getOptionValue(PROPERTIES_PROVIDERNAME_OPTION)))); 147 JsonValue value = getSourceValue(cmd.getOptionValue(PROPERTIES_SRCJSON_OPTION), true); 148 setDestinationValue(cmd.getOptionValue(PROPERTIES_DESTJSON_OPTION), value.as(decrypt)); 149 } else { 150 usage(); 151 } 152 } 153 154 private SimpleKeyStoreSelector getSimpleKeySelector(String keystore, String type, String password, String provider) 155 throws Exception { 156 final KeyStore ks = new KeyStoreBuilder() 157 .withKeyStoreFile(keystore) 158 .withPassword(password) 159 .withProvider(provider) 160 .withKeyStoreType(Utils.asEnum(type, KeyStoreType.class)) 161 .build(); 162 return new SimpleKeyStoreSelector(ks, password); 163 } 164 165 private JsonValue getSourceValue(String source, boolean file) throws IOException { 166 JsonValue src = null; 167 if (file) { 168 File srcFile = new File(source); 169 if (srcFile.exists()) { 170 src = new JsonValue(MAPPER.readValue(srcFile, Object.class)); 171 } else { 172 throw new FileNotFoundException("JsonSource file not found at: " + srcFile.getAbsolutePath()); 173 } 174 } else { 175 src = new JsonValue(MAPPER.readValue(source, Object.class)); 176 } 177 return src; 178 } 179 180 private void setDestinationValue(String destination, JsonValue value) throws IOException { 181 if (null == destination) { 182 MAPPER.writeValue(System.out, value.getObject()); 183 } else { 184 File dest = new File(destination); 185 dest.getParentFile().mkdirs(); 186 MAPPER.writeValue(dest, value.getObject()); 187 } 188 } 189 190 /** 191 * Validate and set command line arguments. Exit after printing usage if anything is 192 * astray. 193 * 194 * @param args String[] args as featured in public static void main() 195 */ 196 private void loadArgs(String[] args) { 197 CommandLineParser parser = new PosixParser(); 198 try { 199 cmd = parser.parse(OPTIONS, args); 200 } catch (ParseException e) { 201 System.err.println("Error parsing arguments"); 202 e.printStackTrace(); 203 System.exit(1); 204 } 205 206 if (cmd.hasOption('h')) { 207 usage(); 208 System.exit(0); 209 } 210 211 // Check for mandatory args 212 if (cmd.hasOption(PROPERTIES_HELP_COMMAND)) { 213 usage(); 214 System.exit(0); 215 } 216 } 217 218 private static void usage() { 219 HelpFormatter formatter = new HelpFormatter(); 220 formatter.printHelp("java -jar json-crypto-1.0.0-command-line.jar", OPTIONS); 221 } 222}