1 /*
2  * @(#) $Id: CryptCommand.java,v 1.5 2003/07/08 08:13:53 pankaj Exp $
3  *
4  * Copyright (c) 2002-03 by Pankaj Kumar (http://www.pankaj-k.net). 
5  * All rights reserved.
6  *
7  * The license governing the use of this file can be found in the 
8  * root directory of the containing software.
9  */
10package org.jstk.crypt;
11
12import java.util.*;
13import java.security.*;
14import java.io.*;
15import javax.crypto.*;
16import javax.crypto.spec.*;
17
18import org.jstk.*;
19
20public class CryptCommand extends JSTKCommandAdapter{
21    protected static HashMap defaults = new HashMap();
22    static {
23        defaults.put("keystore", "my.keystore");
24        defaults.put("storepass", "changeit");
25        defaults.put("kstype", "JCEKS");
26        defaults.put("alias", "mykey");
27        defaults.put("transform", "DES/CFB8/NoPadding");
28        defaults.put("algorithm", "PBEWithMD5AndDES");
29    }
30    public String briefDescription(){
31        return "encrypt/decrypt using password or key from file or keystore";
32    }
33    public String optionsDescription(){
34        return
35            "  -op (enc|dec)       : Cryptographic operation: encryption or decryption.\n" +
36            "  -infile <infile>    : Input data file.\n" +
37            "  -outfile <outfile>  : Output data file.\n" +
38            "  -password <password>: Password for Password Based Encryption(PBE).\n" +
39            "  -transform <transform>: Cipher transform(<alg>/<mode>/<padding>).[" +
40            defaults.get("transform") + "]\n" +
41            "  -algorithm <algo>   : Algo. for password based encryption.[" +
42            defaults.get("algorithm") + "]\n" +
43            "  -stream             : use CipherInputStream or CipherOutputStream.\n" +
44            "  -iv <ivbytes>       : initialization vector bytes.\n" +
45            "  -keyfile <keyfile>  : File having the serialized key.\n" +
46            "  -keystore <keystore>: the keystore.[" +
47            defaults.get("keystore") + "]\n" +
48            "  -storepass <storepass>: Password for keystore.[" +
49            defaults.get("storepass") + "]\n" +
50            "  -kstype <kstype>    : the keystore type.[" +
51            defaults.get("kstype") + "]\n" +
52            "  -alias <alias>      : alias to access the key in the keystore.[" +
53            defaults.get("alias") + "]\n" +
54            "  -keypass <keypass>  : Password for key in the keystore.\n" +
55            "  -provider <provider>: provider name for KeyStore and Cipher.\n" +
56            "\n" +
57            "  <<keyinfo>> := (-keyfile <keyfile>|[-keystore <keystore>] [-storepass\n" +
58            "      <storepass>] [-kstype <kstype>] [-alias <alias>] [-keypass <keypass>])\n";
59    }
60
61    public String[] useForms(){
62        String[] forms = {
63            "-op (enc|dec) -infile <infile> -outfile <outfile> -password\n" +
64                "\t<password> [-algorithm <algorithm>] [-stream]",
65            "-op (enc|dec) -infile <infile> -outfile <outfile> <<keyinfo>>\n" +
66                "\t[-stream] [-iv <ivbytes>] [-transform <transform>] [-provider <provider>]"
67        };
68        return forms;
69    }
70
71    public String[] sampleUses(){
72        String[] uses = {
73            "-op enc -infile clear.data -outfile enc.data -password changeit",
74            "-op enc -infile clear.data -outfile enc.data -password changeit -stream",
75            "-op dec -infile enc.data -outfile dec.data -keyfile my.secretkey -iv 88888888",
76            "-op enc -infile clear.data -outfile enc.data -transform RSA/ECB/PKCS#1",
77        };
78        return uses;
79    }
80
81    protected Cipher initCipher(JSTKArgs args, int cipherMode) throws Exception {
82        String password = args.get("password");
83        String keyfile = args.get("keyfile");
84        String providerName = args.get("provider");
85        Key key = null;
86        if (password != null){
87            byte[] salt = {
88                (byte)0xc7, (byte)0x73, (byte)0x21, (byte)0x8c,
89                (byte)0x7e, (byte)0xc8, (byte)0xee, (byte)0x99 };
90            int count = 20;
91            String algorithm = args.get("algorithm");
92            PBEParameterSpec paramSpec = new PBEParameterSpec(salt, count);
93            PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
94            SecretKeyFactory keyFac = SecretKeyFactory.getInstance(algorithm);
95            key = keyFac.generateSecret(keySpec);
96            Cipher cipher = Cipher.getInstance(algorithm);
97            cipher.init(cipherMode, key, paramSpec);
98            return cipher;
99        } else {    // Key file specified
00            key = KeyUtil.getKey(args, Key.class);  // Get key from keyfile or keystore
01
02            // KeyUtil.getKey() would return PublicKey if keyfile contains a keypair.
03            if (cipherMode == Cipher.DECRYPT_MODE && (key instanceof PublicKey)){
04                key = KeyUtil.getKey(args, PrivateKey.class);   // Get key from keyfile or keystore
05            }
06        }
07
08        String transform = args.get("transform");
09        Cipher cipher;
10        if (providerName != null)
11            cipher = Cipher.getInstance(transform, providerName);
12        else
13            cipher = Cipher.getInstance(transform);
14
15        String ivString = args.get("iv");
16        if (ivString != null){
17            IvParameterSpec ips = new IvParameterSpec(ivString.getBytes());
18            cipher.init(cipherMode, key, ips);
19        } else {
20            cipher.init(cipherMode, key);
21        }
22        return cipher;
23    }
24
25    public Object execute(JSTKArgs args) throws JSTKException{
26        try {
27            args.setDefaults(defaults);
28
29            boolean stream = Boolean.valueOf((String)args.get("stream")).booleanValue();
30
31            int cipherMode;
32            String cryptOp = args.get("op");
33            if (cryptOp == null){
34                return new JSTKResult(null, false, "no cryptographic operation specified");
35            } else if (cryptOp.equals("enc")){
36                cipherMode = Cipher.ENCRYPT_MODE;
37            } else if (cryptOp.equals("dec")){
38                cipherMode = Cipher.DECRYPT_MODE;
39            } else {
40                return new JSTKResult(null, false, "unknown cryptographic operation: " + cryptOp);
41            }
42
43            String infileName = args.get("infile");
44            if (infileName == null)
45                return new JSTKResult(null, false, "no input file specified");
46
47            String outfileName = args.get("outfile");
48            if (outfileName == null)
49                return new JSTKResult(null, false, "no output file specified");
50
51            Cipher cipher = null;
52            try {
53                cipher = initCipher(args, cipherMode);
54            } catch (Exception e){
55                return new JSTKResult(null, false, e.getMessage());
56            }
57
58            FileInputStream fis = new FileInputStream(infileName);
59            FileOutputStream fos = new FileOutputStream(outfileName);
60
61            if (stream){    // Use CipherStream APIs
62                InputStream is = null;
63                OutputStream os = null;
64
65                if (cipherMode == Cipher.DECRYPT_MODE){
66                    is = new CipherInputStream(fis, cipher);
67                    os = fos;
68                } else {
69                    is = fis;
70                    os = new CipherOutputStream(fos, cipher);
71                }
72
73                // Operate on 1KB chunks.
74                perfData.updateBegin();
75                byte[] buf = new byte[1024];
76                int n, tot = 0;
77                while ((n = is.read(buf)) > 0){
78                    os.write(buf, 0, n);
79                    tot += n;
80                }
81                perfData.updateEnd(tot);
82                is.close();
83                os.close();
84            } else {
85                // Read the file in a memory buffer first.
86                ByteArrayOutputStream baos = new ByteArrayOutputStream();
87                byte[] buf = new byte[1024];
88                int n;
89                while ((n = fis.read(buf)) > 0)
90                    baos.write(buf, 0, n);
91                fis.close();
92                byte[] ibuf = baos.toByteArray();
93
94                perfData.updateBegin();
95                byte[] obuf = cipher.doFinal(ibuf);
96                perfData.updateEnd(ibuf.length);
97
98                fos.write(obuf);
99                fos.close();
00            }
01
02            return new JSTKResult(null, true, cryptOp + "rypted file \"" +
03                infileName + "\" to \"" + outfileName + "\"");
04        } catch (Exception exc){
05            throw new JSTKException("CryptCommand.execute() failed", exc);
06        }
07    }
08}