View Javadoc
1   /*
2    * The contents of this file are subject to the terms of the Common Development and
3    * Distribution License (the License). You may not use this file except in compliance with the
4    * License.
5    *
6    * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
7    * specific language governing permission and limitations under the License.
8    *
9    * When distributing Covered Software, include this CDDL Header Notice in each file and include
10   * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
11   * Header, with the fields enclosed by brackets [] replaced by your own identifying
12   * information: "Portions Copyrighted [year] [name of copyright owner]".
13   *
14   * Copyright 2011-2016 ForgeRock AS.
15   */
16  
17  package org.forgerock.json.crypto.cli;
18  
19  import java.io.File;
20  import java.io.FileNotFoundException;
21  import java.io.IOException;
22  import java.security.Key;
23  import java.security.KeyStore;
24  
25  import org.apache.commons.cli.CommandLine;
26  import org.apache.commons.cli.CommandLineParser;
27  import org.apache.commons.cli.HelpFormatter;
28  import org.apache.commons.cli.Options;
29  import org.apache.commons.cli.ParseException;
30  import org.apache.commons.cli.PosixParser;
31  import org.forgerock.json.JsonValue;
32  import org.forgerock.json.crypto.JsonEncryptFunction;
33  import org.forgerock.json.crypto.JsonCryptoException;
34  import org.forgerock.json.crypto.JsonDecryptFunction;
35  import org.forgerock.json.crypto.simple.SimpleDecryptor;
36  import org.forgerock.json.crypto.simple.SimpleEncryptor;
37  import org.forgerock.json.crypto.simple.SimpleKeyStoreSelector;
38  import org.forgerock.security.keystore.KeyStoreBuilder;
39  import org.forgerock.security.keystore.KeyStoreType;
40  import org.forgerock.util.Utils;
41  
42  import com.fasterxml.jackson.databind.ObjectMapper;
43  
44  /**
45   * Command-line interface to encrypt/decrypt.
46   */
47  public class Main {
48  
49      private static final ObjectMapper MAPPER = new ObjectMapper();
50      private static final Options OPTIONS; // Command line options
51  
52      private static final String PROPERTIES_ALIAS_OPTION = "alias";
53      private static final String PROPERTIES_CIPHER_OPTION = "cipher";
54      private static final String DEFAULT_CIPHER = "AES/CBC/PKCS5Padding";
55      private static final String PROPERTIES_SRCJSON_OPTION = "srcjson";
56      private static final String PROPERTIES_DESTJSON_OPTION = "destjson";
57      private static final String PROPERTIES_KEYPASS_OPTION = "keypass";
58      private static final String PROPERTIES_KEYSTORE_OPTION = "keystore";
59      private static final String PROPERTIES_STOREPASS_OPTION = "storepass";
60      private static final String PROPERTIES_STORETYPE_OPTION = "storetype";
61      private static final String PROPERTIES_PROVIDERNAME_OPTION = "providername";
62      private static final String PROPERTIES_PROVIDERCLASS_OPTION = "providerclass";
63      private static final String PROPERTIES_PROVIDERARG_OPTION = "providerarg";
64      private static final String PROPERTIES_PROVIDERPATH_OPTION = "providerpath";
65      private static final String PROPERTIES_ENCRYPT_COMMAND = "encrypt";
66      private static final String PROPERTIES_DECRYPT_COMMAND = "decrypt";
67      private static final String PROPERTIES_HELP_COMMAND = "help";
68  
69      private CommandLine cmd = null; // Command Line arguments
70  
71      static {
72          OPTIONS = new Options();
73          OPTIONS.addOption(PROPERTIES_ENCRYPT_COMMAND, false,
74                  "Encrypt input file");
75          OPTIONS.addOption(PROPERTIES_DECRYPT_COMMAND, false,
76                  "Decrypt input file");
77          OPTIONS.addOption("h", PROPERTIES_HELP_COMMAND, false,
78                  "Display help");
79  
80  
81          //Required encryption options
82          OPTIONS.addOption(PROPERTIES_ALIAS_OPTION, true,
83                  "Cryptography key alias.");
84          OPTIONS.addOption(PROPERTIES_CIPHER_OPTION, true,
85                  "Cipher algorithm. " + DEFAULT_CIPHER + " by default");
86          //Required input options
87          OPTIONS.addOption(PROPERTIES_SRCJSON_OPTION, true,
88                  "Input JSON File");
89          //Optional output options
90          OPTIONS.addOption(PROPERTIES_DESTJSON_OPTION, true,
91                  "Output JSON File");
92          //Required keystore options
93          OPTIONS.addOption(PROPERTIES_KEYSTORE_OPTION, true,
94                  "KeyStore File");
95          OPTIONS.addOption(PROPERTIES_STOREPASS_OPTION, true,
96                  "KeyStore password.");
97          OPTIONS.addOption(PROPERTIES_STORETYPE_OPTION, true,
98                  "KeyStore type. Default: " + KeyStore.getDefaultType());
99          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 }