org.slc.sli.encryption.tool.Encryptor.java Source code

Java tutorial

Introduction

Here is the source code for org.slc.sli.encryption.tool.Encryptor.java

Source

/*
 * Copyright 2012-2013 inBloom, Inc. and its affiliates.
 *
 * Licensed 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.slc.sli.encryption.tool;

import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import java.io.*;
import java.security.GeneralSecurityException;
import java.security.Key;
import java.security.KeyStore;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Scanner;

/**
 * Class used to encrypt/decrypt properties
 * 
 * @author ccheng
 *
 */
public class Encryptor {

    private static final String KEYSTOREPASS = "keyStorePass";
    private static final String DALKEYALIAS = "dalKeyAlias";
    private static final String DALKEYPASS = "dalKeyPass";
    private static final String DALINITVEC = "dalInitializationVector";
    private static final String DALALGORITHM = "dalAlgorithm";

    private static final String KEYSTORE_TYPE = "JCEKS";
    private static final String CIPHER_ALGORITHM = "AES";
    private static final String CHARSET = "UTF8";

    private String keyStorePass;
    private String keyLocation;
    KeyStore keystore;

    public Encryptor(String keyStoreLocation, String keyStorePassword) throws Exception {
        setKeyLocation(keyStoreLocation);
        setKeyStorePass(keyStorePassword);

        String keyLocation = getKeyLocation();
        File keyfile = new File(keyLocation);

        //        System.out.println("\nUsing keystore: " + getKeyLocation());

        if (keyfile.exists()) {
            // load keystore
            FileInputStream fis = null;
            try {
                fis = new FileInputStream(getKeyLocation());
                keystore = KeyStore.getInstance(KEYSTORE_TYPE);
                keystore.load(fis, this.getKeyStorePass().toCharArray());
                fis.close();
            } finally {
                if (fis != null) {
                    fis.close();
                }
            }
        } else {
            throw new FileNotFoundException(
                    "Unable to load file '" + keyLocation + "' -- Please specify a valid keystore file.");
        }
    }

    public String encrypt(String alias, String password, String value)
            throws GeneralSecurityException, IOException {
        Key key = keystore.getKey(alias, password.toCharArray());
        // create a cipher object and use the generated key to initialize it
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, key);
        byte[] encrypted = cipher.doFinal(value.getBytes(CHARSET));

        return byteArrayToHexString(encrypted);
    }

    public String encrypt(String alias, String password, String algorithm, String initVec, String message)
            throws GeneralSecurityException {
        Key key = keystore.getKey(alias, password.toCharArray());
        Cipher cipher = Cipher.getInstance(algorithm);

        IvParameterSpec ivspec = null;
        if (initVec != null) {
            byte[] ivBytes;
            try {
                ivBytes = Hex.decodeHex(initVec.toCharArray());
            } catch (DecoderException e) {
                throw new RuntimeException(e);
            }
            ivspec = new IvParameterSpec(ivBytes);

            cipher.init(Cipher.ENCRYPT_MODE, (SecretKey) key, ivspec);
        } else {
            cipher.init(Cipher.ENCRYPT_MODE, (SecretKey) key);
        }

        byte[] encryptedBytes = cipher.doFinal(message.getBytes());
        String encoded = Base64.encodeBase64String(encryptedBytes);

        return encoded;
    }

    public String decrypt(String alias, String password, String message)
            throws GeneralSecurityException, IOException {
        Key key = keystore.getKey(alias, password.toCharArray());
        // create a cipher object and use the generated key to initialize it
        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, key);
        byte[] decrypted = cipher.doFinal(hexStringToByteArray(message));
        return new String(decrypted, CHARSET);
    }

    public String decrypt(String alias, String password, String algorithm, String initVec, String message)
            throws GeneralSecurityException {
        Key key = keystore.getKey(alias, password.toCharArray());
        Cipher cipher = Cipher.getInstance(algorithm);

        IvParameterSpec ivspec = null;
        if (initVec != null) {
            byte[] ivBytes;
            try {
                ivBytes = Hex.decodeHex(initVec.toCharArray());
            } catch (DecoderException e) {
                throw new RuntimeException(e);
            }
            ivspec = new IvParameterSpec(ivBytes);

            cipher.init(Cipher.DECRYPT_MODE, (SecretKey) key, ivspec);
        } else {
            cipher.init(Cipher.DECRYPT_MODE, (SecretKey) key);
        }

        byte[] decoded = Base64.decodeBase64(message.getBytes());
        String decrypted = new String(cipher.doFinal(decoded));

        return decrypted;
    }

    private static String byteArrayToHexString(byte[] b) {
        StringBuffer sb = new StringBuffer(b.length * 2);
        for (int i = 0; i < b.length; i++) {
            int v = b[i] & 0xff;
            if (v < 16) {
                sb.append('0');
            }
            sb.append(Integer.toHexString(v));
        }
        return sb.toString().toUpperCase();
    }

    private static byte[] hexStringToByteArray(String s) {
        byte[] b = new byte[s.length() / 2];
        for (int i = 0; i < b.length; i++) {
            int index = i * 2;
            int v = Integer.parseInt(s.substring(index, index + 2), 16);
            b[i] = (byte) v;
        }
        return b;
    }

    public String getKeyStorePass() {
        return keyStorePass;
    }

    final public void setKeyStorePass(String keyStorePass) {
        this.keyStorePass = keyStorePass;
    }

    final public String getKeyLocation() {
        return keyLocation;
    }

    final public void setKeyLocation(String keyLocation) {
        this.keyLocation = keyLocation;
    }

    private static Map<String, String> parsePropertiesFile(String propertiesFile) throws IOException {
        Map<String, String> properties = new HashMap<String, String>();

        Properties props = new Properties();
        props.load(new FileInputStream(new File(propertiesFile)));

        for (Object propObj : props.keySet()) {
            String prop = propObj.toString();
            if (prop.endsWith(KEYSTOREPASS)) {
                properties.put(KEYSTOREPASS, props.get(prop).toString());
            } else if (prop.endsWith(DALKEYALIAS)) {
                properties.put(DALKEYALIAS, props.get(prop).toString());
            } else if (prop.endsWith(DALKEYPASS)) {
                properties.put(DALKEYPASS, props.get(prop).toString());
            } else if (prop.endsWith(DALINITVEC)) {
                properties.put(DALINITVEC, props.get(prop).toString());
            } else if (prop.endsWith(DALALGORITHM)) {
                properties.put(DALALGORITHM, props.get(prop).toString());
            }
        }

        return properties;
    }

    /**
     * New functionality allows encrypting using the same algorithm
     * the api uses for encrypting PII fields in MongoDB.
     *
     * for example:
      java -jar encryption-tool.java --decrypt
      ../data-access/dal/keyStore/localKeyStore.jks
      ../data-access/dal/keyStore/localEncryption.properties
      aDvgicSt81j/YdPUhvr4Ig==
        
     * or to encrypt:
      java -jar encryption-tool.java
      ../data-access/dal/keyStore/localKeyStore.jks
      ../data-access/dal/keyStore/localEncryption.properties
      Lauretta
        
     * you can also exclude the message at the end, then this program works
     * in streaming mode: every line received from System.in is en/decrypted
     * and returned to System.out
        
     * @param args
     * @throws Exception
     */

    public static void main(String[] args) throws Exception {
        PrintStream out = System.out;
        if (args.length < 2 || args.length > 6) {
            out.println("For encryption:");
            out.println(
                    "Usage: java -jar encryption-tool.jar <keystore_location> <keystore_password> <key_alias> <key_password> <string>");
            out.println("For decryption");
            out.println(
                    "Usage: java -jar encryption-tool.jar --decrypt <keystore_location> <keystore_password> <key_alias> <key_password> <string>");
            out.println();
            out.println("Using a properties file: \n  Property names must end with the following values. ");
            out.println("  " + KEYSTOREPASS + " (required)");
            out.println("  " + DALKEYALIAS + " (required)");
            out.println("  " + DALKEYPASS + " (required) ");
            out.println("  " + DALINITVEC + " (optional)");
            out.println("  " + DALALGORITHM + "(optional, defaults to \"AES/CBC/PKCS5Padding\")");

            out.println("Encryption:");
            out.println(
                    "  Usage: java jar encyption-tool-1.0-jar <keystore_location> <properties_file> [<string>]");
            out.println("Decryption:");
            out.println(
                    "  Usage: java jar encyption-tool-1.0-jar -decrypt <keystore_location> <properties_file> [<string>]");

            return;
        }

        boolean decrypt = false;
        String[] effectiveArgs = args;
        if (args[0].equals("--decrypt")) {
            decrypt = true;
            effectiveArgs = new String[args.length - 1];
            System.arraycopy(args, 1, effectiveArgs, 0, args.length - 1);
        }

        String propertiesLocation = null;
        String keystoreLocation = null;
        String keystorePassword = null;
        String keyAlias = null;
        String keyPassword = null;
        String message = null;
        String initVector = null;
        String algorithm = "AES/CBC/PKCS5Padding";

        if (args.length == 5 || args.length == 6) {
            //OLDER FUNCTIONALITY
            keystoreLocation = effectiveArgs[0];
            keystorePassword = effectiveArgs[1];
            keyAlias = effectiveArgs[2];
            keyPassword = effectiveArgs[3];
            message = effectiveArgs[4];

            Encryptor encryptor = new Encryptor(keystoreLocation, keystorePassword);

            if (!decrypt) {
                String encryptedString = encryptor.encrypt(keyAlias, keyPassword, message);
                out.println("Encrypted string for " + message + " is: " + encryptedString + "\n");
            } else {
                String decryptedString = encryptor.decrypt(keyAlias, keyPassword, message);
                out.println("Descrypted string for " + message + " is: " + decryptedString + "\n");
            }

        } else {
            //NEWER FUNCTIONALITY
            keystoreLocation = effectiveArgs[0];
            propertiesLocation = effectiveArgs[1];

            if (effectiveArgs.length == 3) {
                message = effectiveArgs[2];
            } else {
                message = null;
            }

            Map<String, String> properties = parsePropertiesFile(propertiesLocation);

            keystorePassword = properties.get(KEYSTOREPASS);
            keyPassword = properties.get(DALKEYPASS);
            keyAlias = properties.get(DALKEYALIAS);

            if (properties.containsKey(DALINITVEC)) {
                initVector = properties.get(DALINITVEC);
            }
            if (properties.containsKey(DALALGORITHM)) {
                algorithm = properties.get(DALALGORITHM);
            }

            Encryptor encryptor = new Encryptor(keystoreLocation, keystorePassword);

            if (!decrypt) {
                if (message != null) {
                    String encrypted = encryptor.encrypt(keyAlias, keyPassword, algorithm, initVector, message);
                    out.println(encrypted);
                } else {
                    Scanner s = new Scanner(System.in);
                    s.useDelimiter("\n");
                    while (s.hasNext()) {
                        String cleartext = s.next();
                        String encrypted = encryptor.encrypt(keyAlias, keyPassword, algorithm, initVector,
                                cleartext);
                        out.println(encrypted);
                    }
                }
            } else {
                if (message != null) {
                    String decrypted = encryptor.decrypt(keyAlias, keyPassword, algorithm, initVector, message);
                    out.println(decrypted);
                } else {
                    Scanner s = new Scanner(System.in);
                    s.useDelimiter("\n");
                    while (s.hasNext()) {
                        String ciphertext = s.next().trim();
                        String decrypted = encryptor.decrypt(keyAlias, keyPassword, algorithm, initVector,
                                ciphertext);
                        out.println(decrypted);
                    }
                }
            }
        }
    }

}