ECToken3.java Source code

Java tutorial

Introduction

Here is the source code for ECToken3.java

Source

/**
* Copyright (C) 2016 Verizon. All Rights Reserved.
*
* 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.
*/

import java.util.Random;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
import java.security.MessageDigest;
import java.util.Arrays;

import org.bouncycastle.crypto.engines.AESEngine;
import org.bouncycastle.crypto.modes.AEADBlockCipher;
import org.bouncycastle.crypto.modes.GCMBlockCipher;
import org.bouncycastle.crypto.params.AEADParameters;
import org.bouncycastle.crypto.params.KeyParameter;

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

public class ECToken3 {
    private final static Random RANDOM = new Random(System.currentTimeMillis());
    private final static int UPPERBOUND = 8;
    private final static int LOWERBOUND = 4;
    static final int MAC_SIZE_BITS = 128;
    private final static String ALPHANUMERIC = "-_0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxzy";

    //: --------------------------------------------------------------------
    //: bytes to hex
    //: --------------------------------------------------------------------
    final protected static char[] hexArray = "0123456789abcdef".toCharArray();

    public static String bytesToHex(byte[] bytes) {
        char[] hexChars = new char[bytes.length * 2];
        for (int j = 0; j < bytes.length; j++) {
            int v = bytes[j] & 0xFF;
            hexChars[j * 2] = hexArray[v >>> 4];
            hexChars[j * 2 + 1] = hexArray[v & 0x0F];
        }
        return new String(hexChars);
    }

    //: --------------------------------------------------------------------
    //: encrypt v3
    //: --------------------------------------------------------------------
    public static final String encryptv3(String key, String input) throws java.io.UnsupportedEncodingException,
            java.security.NoSuchAlgorithmException, javax.crypto.NoSuchPaddingException,
            java.security.InvalidKeyException, javax.crypto.IllegalBlockSizeException,
            javax.crypto.BadPaddingException, java.security.InvalidAlgorithmParameterException {

        //System.out.format("+-------------------------------------------------------------\n");
        //System.out.format("| Encrypt\n");
        //System.out.format("+-------------------------------------------------------------\n");
        //System.out.format("| key:                   %s\n", key);
        //System.out.format("| token:                 %s\n", input);

        //----------------------------------------------------
        // Get SHA-256 of key
        //----------------------------------------------------
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        md.update(key.getBytes("ASCII"));
        byte[] keyDigest = md.digest();

        //----------------------------------------------------
        // Get Random IV
        //----------------------------------------------------
        SecureRandom random = new SecureRandom();
        byte[] ivBytes = new byte[12];
        random.nextBytes(ivBytes);

        //----------------------------------------------------
        // Encrypt
        //----------------------------------------------------
        AEADBlockCipher cipher = new GCMBlockCipher(new AESEngine());
        cipher.init(true, new AEADParameters(new KeyParameter(keyDigest), MAC_SIZE_BITS, ivBytes));
        byte[] inputBytes = input.getBytes("ASCII");

        byte[] enc = new byte[cipher.getOutputSize(inputBytes.length)];

        try {
            int res = cipher.processBytes(inputBytes, 0, inputBytes.length, enc, 0);
            cipher.doFinal(enc, res);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        byte[] ivPlusCipherText = new byte[ivBytes.length + enc.length];
        System.arraycopy(ivBytes, 0, ivPlusCipherText, 0, ivBytes.length);
        System.arraycopy(enc, 0, ivPlusCipherText, ivBytes.length, enc.length);

        //System.out.format("+-------------------------------------------------------------\n");
        //System.out.format("| iv:                    %s\n", bytesToHex(ivBytes));
        //System.out.format("| ciphertext:            %s\n", bytesToHex(Arrays.copyOfRange(enc, 0, enc.length - 16)));
        //System.out.format("| tag:                   %s\n", bytesToHex(Arrays.copyOfRange(enc, enc.length - 16, enc.length)));
        //System.out.format("+-------------------------------------------------------------\n");
        //System.out.format("| token:                 %s\n", bytesToHex(ivPlusCipherText));
        //System.out.format("+-------------------------------------------------------------\n");

        String result = null;
        byte[] temp = null;
        Base64 encoder = new Base64(0, temp, true);
        byte[] encodedBytes = encoder.encode(ivPlusCipherText);
        String encodedStr = new String(encodedBytes, "ASCII").trim();
        String encodedStrTrim = encodedStr.trim();
        return encodedStr.trim();
    }

    //: --------------------------------------------------------------------
    //: decrypt v3
    //: --------------------------------------------------------------------
    public static final String decryptv3(String key, String input) throws java.io.UnsupportedEncodingException,
            java.security.NoSuchAlgorithmException, javax.crypto.NoSuchPaddingException,
            java.security.InvalidKeyException, javax.crypto.IllegalBlockSizeException,
            javax.crypto.BadPaddingException, java.security.InvalidAlgorithmParameterException {

        //----------------------------------------------------
        // Base64 decode
        //----------------------------------------------------
        String result = null;
        Base64 encoder = new Base64(true);
        byte[] inputBytes = encoder.decode(input.getBytes("ASCII"));

        //----------------------------------------------------
        // Get SHA-256 of key
        //----------------------------------------------------
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        md.update(key.getBytes("ASCII"));
        byte[] keyDigest = md.digest();

        //System.out.format("+-------------------------------------------------------------\n");
        //System.out.format("| Decrypt\n");
        //System.out.format("+-------------------------------------------------------------\n");
        //System.out.format("| key:                   %s\n", key);
        //System.out.format("| token:                 %s\n", input);

        //----------------------------------------------------
        // Rip up the ciphertext
        //----------------------------------------------------
        byte[] ivBytes = new byte[12];
        ivBytes = Arrays.copyOfRange(inputBytes, 0, ivBytes.length);

        byte[] cipherBytes = new byte[inputBytes.length - ivBytes.length];
        cipherBytes = Arrays.copyOfRange(inputBytes, ivBytes.length, inputBytes.length);

        //----------------------------------------------------
        // Decrypt
        //----------------------------------------------------
        AEADBlockCipher cipher = new GCMBlockCipher(new AESEngine());
        cipher.init(false, new AEADParameters(new KeyParameter(keyDigest), MAC_SIZE_BITS, ivBytes));

        //System.out.format("+-------------------------------------------------------------\n");
        //System.out.format("| iv:                    %s\n", bytesToHex(ivBytes));
        //System.out.format("| ciphertext:            %s\n", bytesToHex(Arrays.copyOfRange(cipherBytes, 0, cipherBytes.length - 16)));
        //System.out.format("| tag:                   %s\n", bytesToHex(Arrays.copyOfRange(cipherBytes, cipherBytes.length - 16, cipherBytes.length)));
        //System.out.format("+-------------------------------------------------------------\n");

        byte[] dec = new byte[cipher.getOutputSize(cipherBytes.length)];

        try {
            int res = cipher.processBytes(cipherBytes, 0, cipherBytes.length, dec, 0);
            cipher.doFinal(dec, res);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        //System.out.format("token: %s\n", new String(dec, "ASCII"));
        return new String(dec, "ASCII");
    }

    public static final void usage() {

        System.out.println("Usage: ECToken3 encrypt <key> <text>");
        System.out.println("       ECToken3 decrypt <key> <text>");
        System.out.println("");
        System.out.println("Version 2 compatibility:");
        System.out.println("  use -2 to specify version 2 tokens eg:");
        System.out.println("       ECToken3 -2 encrypt <key> <text>");
        System.out.println("       ECToken3 -2 decrypt <key> <text>");
        System.exit(1);
    }

    //: --------------------------------------------------------------------
    //: main
    //: --------------------------------------------------------------------
    public static final void main(String[] args) throws Exception {

        if (args.length == 1 && args[0].equals("--version")) {
            System.out.println("EC Token encryption and decryption utility.  Version: 3.0.0\n");
            System.exit(0);
        }

        int arg_offset = 0;
        if (args.length != 3) {
            usage();
        }

        String action = args[arg_offset + 0];
        String key = args[arg_offset + 1];
        String input = args[arg_offset + 2];
        String outString = "";
        if (action.equals("encrypt")) {
            outString = ECToken3.encryptv3(key, input);
        } else if (action.equals("decrypt")) {
            outString = ECToken3.decryptv3(key, input);
        }
        System.out.println(outString);
    }
}