View Javadoc
1   /*
2    * This file is part of Waarp Project (named also Waarp or GG).
3    *
4    *  Copyright (c) 2019, Waarp SAS, and individual contributors by the @author
5    *  tags. See the COPYRIGHT.txt in the distribution for a full listing of
6    * individual contributors.
7    *
8    *  All Waarp Project is free software: you can redistribute it and/or
9    * modify it under the terms of the GNU General Public License as published by
10   * the Free Software Foundation, either version 3 of the License, or (at your
11   * option) any later version.
12   *
13   * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY
14   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15   * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16   *
17   *  You should have received a copy of the GNU General Public License along with
18   * Waarp . If not, see <http://www.gnu.org/licenses/>.
19   */
20  package org.waarp.uip;
21  
22  import org.waarp.common.crypto.Blowfish;
23  import org.waarp.common.crypto.Des;
24  import org.waarp.common.crypto.KeyObject;
25  import org.waarp.common.exception.CryptoException;
26  import org.waarp.common.file.FileUtils;
27  import org.waarp.common.logging.SysErrLogger;
28  import org.waarp.common.utility.SystemPropertyUtil;
29  import org.waarp.common.utility.WaarpStringUtils;
30  import org.waarp.common.utility.WaarpSystemUtil;
31  
32  import java.io.BufferedReader;
33  import java.io.DataInputStream;
34  import java.io.File;
35  import java.io.FileInputStream;
36  import java.io.FileOutputStream;
37  import java.io.IOException;
38  import java.io.InputStreamReader;
39  
40  /**
41   * Console Command Line Main class to provide Password Management for GoldenGate
42   * Products.
43   */
44  public class WaarpPassword {
45    static boolean desModel = true;
46    static boolean clearPasswordView;
47    static final String HELPOPTIONS = "Options available\r\n" +
48                                      "* -ki file to specify the Key File by default\r\n" +
49                                      "* -ko file to specify a new Key File to build and save\r\n\r\n" +
50                                      "* -des to specify DES format (default)\r\n" +
51                                      "* -blf to specify BlowFish format\r\n\r\n" +
52                                      "* -pi file to specify a GGP File by default(password)\r\n" +
53                                      "* -pwd to specify a clear ggp password as entry\r\n" +
54                                      "* -cpwd to specify a crypted ggp password as entry\r\n" +
55                                      "* -po file to specify a GGP File as output for the password\r\n" +
56                                      "* -clear to specify uncrypted password shown as clear text";
57    static final String GGPEXTENSION = "ggp";
58    static String ki;
59    static String ko;
60    static String pi;
61    static String po;
62    static String pwd;
63    static String cpwd;
64  
65    private File keyFile;
66    private File passwordFile;
67    private String clearPassword;
68    private String cryptedPassword;
69  
70    private final KeyObject currentKey;
71  
72    /**
73     * @param args
74     *
75     * @throws Exception
76     */
77    public static void main(final String[] args) throws Exception {
78      if (!loadOptions(args)) {
79        // Bad options
80        WaarpSystemUtil.systemExit(2);
81        return;
82      }
83      final WaarpPassword waarpPassword = new WaarpPassword();
84      if (po == null && pi == null) {
85        // stop
86        SysErrLogger.FAKE_LOGGER.sysout("Key written");
87        WaarpSystemUtil.systemExit(0);
88        return;
89      }
90      if (waarpPassword.clearPassword == null ||
91          waarpPassword.clearPassword.length() == 0) {
92        SysErrLogger.FAKE_LOGGER.sysout("Password to crypt:");
93        final String newp = waarpPassword.readString();
94        if (newp == null || newp.length() == 0) {
95          SysErrLogger.FAKE_LOGGER.syserr("No password as input");
96          WaarpSystemUtil.systemExit(4);
97          return;
98        }
99        waarpPassword.setClearPassword(newp);
100       if (po != null) {
101         waarpPassword.setPasswordFile(new File(po));
102         waarpPassword.savePasswordFile();
103       }
104       if (clearPasswordView) {
105         SysErrLogger.FAKE_LOGGER.sysout(
106             "ClearPwd: " + waarpPassword.getClearPassword());
107         SysErrLogger.FAKE_LOGGER.sysout(
108             "CryptedPwd: " + waarpPassword.getCryptedPassword());
109       }
110     }
111   }
112 
113   public static boolean loadOptions(final String[] args) {
114     desModel = true;
115     clearPasswordView = false;
116     ki = null;
117     ko = null;
118     pi = null;
119     po = null;
120     pwd = null;
121     cpwd = null;
122 
123     int i;
124     if (args.length == 0) {
125       SysErrLogger.FAKE_LOGGER.syserr(HELPOPTIONS);
126       return false;
127     }
128     if (!SystemPropertyUtil.isFileEncodingCorrect()) {
129       SysErrLogger.FAKE_LOGGER.syserr(
130           "Issue while trying to set UTF-8 as default file encoding: use -Dfile.encoding=UTF-8 as java command argument\n" +
131           "Currently file.encoding is: " +
132           SystemPropertyUtil.get(SystemPropertyUtil.FILE_ENCODING));
133       return false;
134     }
135     for (i = 0; i < args.length; i++) {
136       if ("-ki".equalsIgnoreCase(args[i])) {
137         i++;
138         if (i < args.length) {
139           ki = args[i];
140         } else {
141           SysErrLogger.FAKE_LOGGER.syserr("-ki needs a file as argument");
142           return false;
143         }
144       } else if ("-ko".equalsIgnoreCase(args[i])) {
145         i++;
146         if (i < args.length) {
147           ko = args[i];
148         } else {
149           SysErrLogger.FAKE_LOGGER.syserr("-ko needs a file as argument");
150           return false;
151         }
152       } else if ("-pi".equalsIgnoreCase(args[i])) {
153         i++;
154         if (i < args.length) {
155           pi = args[i];
156         } else {
157           SysErrLogger.FAKE_LOGGER.syserr("-pi needs a file as argument");
158           return false;
159         }
160       } else if ("-po".equalsIgnoreCase(args[i])) {
161         i++;
162         if (i < args.length) {
163           po = args[i];
164         } else {
165           SysErrLogger.FAKE_LOGGER.syserr("-po needs a file as argument");
166           return false;
167         }
168       } else if ("-des".equalsIgnoreCase(args[i])) {
169         desModel = true;
170       } else if ("-blf".equalsIgnoreCase(args[i])) {
171         desModel = false;
172       } else if ("-pwd".equalsIgnoreCase(args[i])) {
173         i++;
174         if (i < args.length) {
175           pwd = args[i];
176         } else {
177           SysErrLogger.FAKE_LOGGER.syserr("-pwd needs a password as argument");
178           return false;
179         }
180       } else if ("-cpwd".equalsIgnoreCase(args[i])) {
181         i++;
182         if (i < args.length) {
183           cpwd = args[i];
184         } else {
185           SysErrLogger.FAKE_LOGGER.syserr(
186               "-cpwd needs a crypted password as argument");
187           return false;
188         }
189       } else if ("-clear".equalsIgnoreCase(args[i])) {
190         clearPasswordView = true;
191       } else {
192         SysErrLogger.FAKE_LOGGER.syserr("Unknown option: " + args[i]);
193         return false;
194       }
195     }
196     if (ki == null && ko == null) {
197       SysErrLogger.FAKE_LOGGER.syserr(
198           "You must specify one of ki or ko options");
199       return false;
200     }
201     if (ki == null) {
202       ki = ko;
203     }
204     if (ki == null && (po != null || pi != null)) {
205       SysErrLogger.FAKE_LOGGER.syserr(
206           "If pi or po options are set, ki or ko options must be set also!\n");
207       return false;
208     }
209     if (pi == null && po == null && (pwd != null || cpwd != null)) {
210       SysErrLogger.FAKE_LOGGER.syserr(
211           "Cannot create a password if no password GGP file is specified with pi or po options");
212       return false;
213     }
214     return true;
215   }
216 
217   public WaarpPassword() throws Exception {
218     if (desModel) {
219       currentKey = new Des();
220     } else {
221       currentKey = new Blowfish();
222     }
223     if (ko != null) {
224       createNewKey();
225       saveKey(new File(ko));
226     }
227     if (ki != null) {
228       loadKey(new File(ki));
229     }
230     if (pi != null) {
231       setPasswordFile(new File(pi));
232       loadPasswordFile();
233     }
234     if (pwd != null) {
235       setClearPassword(pwd);
236     }
237     if (cpwd != null) {
238       setCryptedPassword(cpwd);
239     }
240     if (po != null) {
241       setPasswordFile(new File(po));
242       savePasswordFile();
243     }
244     if (clearPassword != null) {
245       if (clearPasswordView) {
246         SysErrLogger.FAKE_LOGGER.sysout("ClearPwd: " + getClearPassword());
247       }
248       SysErrLogger.FAKE_LOGGER.sysout("CryptedPwd: " + getCryptedPassword());
249     }
250   }
251 
252   private String readString() {
253     String read = "";
254     final InputStreamReader input =
255         new InputStreamReader(System.in, WaarpStringUtils.UTF8);
256     final BufferedReader reader = new BufferedReader(input);
257     try {
258       read = reader.readLine();
259     } catch (final IOException e) {
260       SysErrLogger.FAKE_LOGGER.syserr(e);
261     }
262     return read;
263   }
264 
265   /**
266    * Create a new Key but do not save it on file
267    *
268    * @throws Exception
269    */
270   public final void createNewKey() throws Exception {
271     try {
272       currentKey.generateKey();
273     } catch (final Exception e) {
274       throw new CryptoException("Create New Key in error", e);
275     }
276     if (clearPassword != null) {
277       setClearPassword(clearPassword);
278     }
279   }
280 
281   /**
282    * @param file source file
283    *
284    * @throws CryptoException
285    */
286   public final void loadKey(final File file) throws CryptoException {
287     keyFile = file;
288     try {
289       currentKey.setSecretKey(file);
290     } catch (final IOException e) {
291       throw new CryptoException("Load Key in error", e);
292     }
293   }
294 
295   /**
296    * @param file destination file, if null previously set file is used
297    *
298    * @throws CryptoException
299    */
300   public final void saveKey(final File file) throws CryptoException {
301     if (file != null) {
302       keyFile = file;
303     }
304     try {
305       currentKey.saveSecretKey(keyFile);
306     } catch (final IOException e) {
307       throw new CryptoException("Save Key in error", e);
308     }
309   }
310 
311   /**
312    * @return True if the associated key is ready
313    */
314   public final boolean keyReady() {
315     return currentKey.keyReady();
316   }
317 
318   /**
319    * @return The File associated with the current Key
320    */
321   public final File getKeyFile() {
322     return keyFile;
323   }
324 
325   /**
326    * Set the new password and its crypted value
327    *
328    * @param passwd
329    *
330    * @throws Exception
331    */
332   public final void setClearPassword(final String passwd) throws Exception {
333     clearPassword = passwd;
334     cryptedPassword = currentKey.cryptToHex(clearPassword);
335   }
336 
337   /**
338    * @return the passwordFile
339    */
340   public final File getPasswordFile() {
341     return passwordFile;
342   }
343 
344   /**
345    * @param passwordFile the passwordFile to set
346    *
347    * @throws IOException
348    */
349   public final void setPasswordFile(final File passwordFile) {
350     this.passwordFile = passwordFile;
351   }
352 
353   /**
354    * Save the Crypted Paswword to the File
355    *
356    * @throws IOException
357    */
358   public final void savePasswordFile() throws IOException {
359     final FileOutputStream outputStream = new FileOutputStream(passwordFile);
360     try {
361       outputStream.write(cryptedPassword.getBytes(WaarpStringUtils.UTF8));
362     } finally {
363       FileUtils.close(outputStream);
364     }
365   }
366 
367   /**
368    * Load the crypted password from the file
369    *
370    * @throws Exception
371    */
372   public final void loadPasswordFile() throws Exception {
373     if (passwordFile.canRead()) {
374       final int len = (int) passwordFile.length();
375       final byte[] key = new byte[len];
376       final FileInputStream inputStream;
377       inputStream = new FileInputStream(passwordFile);
378       DataInputStream dis = null;
379       try {
380         dis = new DataInputStream(inputStream);
381         dis.readFully(key);
382       } finally {
383         if (dis != null) {
384           FileUtils.close(dis);
385         } else {
386           FileUtils.close(inputStream);
387         }
388       }
389       setCryptedPassword(new String(key, WaarpStringUtils.UTF8));
390     } else {
391       throw new CryptoException("Cannot read crypto file");
392     }
393   }
394 
395   /**
396    * @return the cryptedPassword
397    */
398   public final String getCryptedPassword() {
399     return cryptedPassword;
400   }
401 
402   /**
403    * @param cryptedPassword the cryptedPassword to set
404    *
405    * @throws Exception
406    */
407   public final void setCryptedPassword(final String cryptedPassword)
408       throws Exception {
409     this.cryptedPassword = cryptedPassword;
410     clearPassword = currentKey.decryptHexInString(cryptedPassword);
411   }
412 
413   /**
414    * @return the clearPassword
415    */
416   public final String getClearPassword() {
417     return clearPassword;
418   }
419 
420 }