edu.harvard.i2b2.analysis.security.HighEncryption.java Source code

Java tutorial

Introduction

Here is the source code for edu.harvard.i2b2.analysis.security.HighEncryption.java

Source

/*
 * Copyright (c) 2006-2015 Massachusetts General Hospital 
 * All rights reserved. This program and the accompanying materials 
 * are made available under the terms of the i2b2 Software License v2.1 
 * which accompanies this distribution. 
 * 
 * Contributors: 
 * 
 *     
 */
package edu.harvard.i2b2.analysis.security;

import java.io.FileNotFoundException;
import java.io.FileInputStream;
import java.text.CharacterIterator;
import java.text.StringCharacterIterator;
import java.util.Hashtable;

import java.sql.*;

import org.apache.commons.logging.LogFactory;
import org.apache.commons.logging.Log;

import edu.harvard.i2b2.common.exception.I2B2Exception;

/**
 * A class that recursively scans a directory and its sub_dirs,
 * The class implements Runnable
 * to allow to use this within a Thread in a larger program.
 */
public class HighEncryption {

    private static Log log = LogFactory.getLog(HighEncryption.class.getName());

    private Hashtable ht = new Hashtable();

    private RijndaelAlgorithm cipher; // Cipher for mrnrs

    // medical record number encryption parameters
    private String m_sBWH_IdentifyingFirstCharacter = "B";
    private String m_sMGH_IdentifyingFirstCharacter = "M";
    private String m_sEMPI_IdentifyingFirstCharacter = "Z";
    private String m_sENCYPT_IdentifyingFirstCharacter = ")";

    private String m_sTheFillCharacter = "X";
    private String m_sEncryptionErrorValue = "";
    // medical record number decryption parameters
    private int m_iBWH_de_standard_length = 8;
    private int m_iMGH_de_standard_length = 7;
    private int m_iEMPI_de_standard_length = 9;
    private String m_sTheDeFillCharacter = "0";

    public HighEncryption(String sFileName) throws Exception {
        this(sFileName, null);
    }

    public HighEncryption(String inFileName, String keys, Connection sConn) throws Exception {

        cipher = new RijndaelAlgorithm(keys, 128); //, "AES");
        Statement stmt = sConn.createStatement();
        ResultSet rs = stmt.executeQuery("SELECT description FROM key WHERE NAME='" + inFileName + "'");

        while (rs.next()) {
            ht.put(inFileName, cipher.decrypt(rs.getString(1)));
            //ConvertBaseNToDecDecrypt(rs.getString(1));
        }
        rs.close();

    }

    public HighEncryption(String inFileName, Hashtable keys) throws Exception {
        String key = null;
        //   makearray64(); // create the array regardless of how key will be acquired AHA@20011016
        if ((keys != null) && (keys.size() > 0))
            key = keys.get(inFileName).toString();

        if ((key == null) || (key.length() == 0)) {
            byte baBuffer[] = new byte[2056];
            try {
                FileInputStream oFileIn = new FileInputStream(inFileName);
                //int iBytes = oFileIn.read(baBuffer,0,2056);
                String sString = new String(baBuffer);
                //new String(baBuffer,0,0,iBytes);
                key = sString;
            } catch (FileNotFoundException fnfe) {
                log.fatal("HighEncryption initialization file-not-found error");
                throw new Exception("HighEncryption initialization error");
            } catch (Exception e) {
                log.fatal("HighEncryption initialization error");
                throw new Exception("HighEncryption initialization error");
            }
        }

        try {
            key = key.trim();
            cipher = new RijndaelAlgorithm(key, 128); //, "AES");  //long version for dates
        } catch (Exception ex) {
            //Lib.TError("HighEncryption initialization error");
            ex.printStackTrace();
            throw new Exception("HighEncryption initialization error");
        }
    }

    public boolean setDatabaseKey(Connection sConn, String masterKey, String sFilename, String newKey, String token,
            String username) throws Exception {
        if (token == null)
            token = "";

        String eNewKey = cipher.encrypt(newKey);

        if (!newKey.equals(cipher.decrypt(eNewKey)))
            throw new Exception("Error verifying decrpyt is eqal to encrypt");

        PreparedStatement setKey = sConn
                .prepareStatement("INSERT INTO key (name, description, token, userinserted, dateinserted) VALUES "
                        + "(?, ?, ?, ?, ?)");
        setKey.setString(1, sFilename);
        setKey.setString(2, eNewKey);
        setKey.setString(3, token);
        setKey.setString(4, username);
        setKey.setDate(5, new java.sql.Date(new java.util.Date().getTime()));

        int count = setKey.executeUpdate();
        if (count == 1)
            return true;
        else
            return false;
    }

    /**
     * Turns array of bytes into string
     *
     * @param buf   Array of bytes to convert to hex string
     * @return   Generated hex string
     */
    public static String asHex(byte buf[]) {
        StringBuffer strbuf = new StringBuffer(buf.length * 2);
        int i;

        for (i = 0; i < buf.length; i++) {
            if ((buf[i] & 0xff) < 0x10)
                strbuf.append("0");

            strbuf.append(Long.toString(buf[i] & 0xff, 16));
        }

        return strbuf.toString();
    }

    /**
     * mrn_encrypt makes the encrypted medical record number.
     * 
     * All empi numbers are 9 digits long, in the form 100xxxxxx.  Therefore, no
     * padding needs to be added to the front of the number.  The output empi 
     * number is an octal of length 11, as set by the variable: empi_stardard_length.
     *
     * All bwh numbers are 8 digits long, but sometimes when they start with 
     * zero's they are shorter (as though they were true numbers).  This routine
     * does not care, it always removes leading zero's.  The output bwh LMRN is 
     * an octal of length set by the variable m_iBWH_stardard_length.
     *
     * All mgh numbers are 7 digits long, but sometimes when they start with 
     * zero's they are shorter (as though they were true numbers).  This routine
     * does not care, it always removes leading zero's, however note that the 
     * encrypt routine will add them back again as part of the standard 
     * incryption method.  The output mgh LMRN is an octal of length set 
     * by the variable m_iMGH_stardard_length.
     *
     * @param theInput String is the cleartext bwh LMRN number.
     * @param standardLength Boolean if TRUE pads a return octal out with X's to
     *   make the total length what m_iXXX_stardard_length is set to.
     * @param theSite String is the name of the owner of the medical
     *   record number.
     * @returns the encrypted medical record number.
     * @exception the program returns a String as defined by the
     *   variable m_sEncryptionErrorValue.
     */
    public String mrn_encrypt(String theInput, boolean standardLength, String theSite) {
        if ((theInput == null) || (theInput.length() == 0))
            return m_sEncryptionErrorValue;
        StringBuffer theOutput = new StringBuffer(16);
        if (theSite.equalsIgnoreCase("BWH")) {
            theOutput.append(m_sBWH_IdentifyingFirstCharacter);
        } else if (theSite.equalsIgnoreCase("MGH")) {
            theOutput.append(m_sMGH_IdentifyingFirstCharacter);
        } else if (theSite.equalsIgnoreCase("EMP") || theSite.equalsIgnoreCase("EMPI")) {
            theOutput.append(m_sEMPI_IdentifyingFirstCharacter);
        } else {
            //Lib.TError("A valid site was not passed to mrn_encrypt function");
            return m_sEncryptionErrorValue;
        }
        String theLong = null;
        try {
            //Strip off extra 0 in front
            theLong = ConvertDecToBaseNEncrypt(Integer.toString(Integer.parseInt(theInput)), 32);
            //theLong = cipher.encrypt(theInput);
        } catch (Exception e) {
            //Lib.TError("Parsing error in mrn_encrypt, message was: "+e.getMessage());
            return m_sEncryptionErrorValue;
        }

        theOutput.append(theLong);
        return theOutput.toString();

        // RAJ:Following lines commented because exception is thrown
        // in length comparison
        // 
        /*
         if (!standardLength) return (theOutput.append(theLong).toString());
         try {
         int addXes = standard_length - theLong.length();
         if (addXes<0) {
         //Lib.TError("A number to encrypt exceeded the maximum allowable length, the number was: '"+theLong+"'.");
          return m_sEncryptionErrorValue;
          }
          else {
          theOutput.append(theLong);
          for (int i=0; i<addXes; i++) {
          theOutput.append(m_sTheFillCharacter);
          }
          return theOutput.toString();
          }
          }
          catch (Exception e) {
          //Lib.TError("Unhandled error in mrn_encrypt: "+e.getMessage());
           return m_sEncryptionErrorValue;
           }
           */

    }

    public String bwh_encnum_encrypt(String theInput) {
        if ((theInput == null) || (theInput.length() == 0))
            return m_sEncryptionErrorValue;
        try {
            // If AES just encrypt the whole input string, do not split of up and attach the 
            // remaining at the end.
            return m_sENCYPT_IdentifyingFirstCharacter + m_sBWH_IdentifyingFirstCharacter
                    + ConvertDecToBaseNEncrypt(theInput, 32);
        } catch (Exception e) {
            log.fatal("Unhandled error in bwh_encnum_encrypt: " + e.getMessage());
            return m_sEncryptionErrorValue;
        }
    }

    public String bwh_encnum_decrypt(String theInput) {
        if ((theInput == null) || (theInput.length() == 0))
            return m_sEncryptionErrorValue;
        try {
            return "TSI-BWH-" + ConvertBaseNToDecDecrypt(theInput.substring(2), 32);
        } catch (Exception e) {
            log.fatal("Unhandled error in bwh_encnum_decrypt: " + e.getMessage());
            return m_sEncryptionErrorValue;
        }
    }

    public String mgh_encnum_encrypt(String theInput) {
        if ((theInput == null) || (theInput.length() == 0))
            return m_sEncryptionErrorValue;
        try {
            // If AES just encrypt the whole input string, do not split of up and attach the 
            // remaining at the end.
            return m_sENCYPT_IdentifyingFirstCharacter + m_sMGH_IdentifyingFirstCharacter
                    + ConvertDecToBaseNEncrypt(theInput, 32);

        } catch (Exception e) {
            log.fatal("Unhandled error in mgh_encnum_encrypt: " + e.getMessage());
            return m_sEncryptionErrorValue;
        }
    }

    public String mgh_encnum_decrypt(String theInput) {
        if ((theInput == null) || (theInput.length() == 0))
            return m_sEncryptionErrorValue;
        try {
            return "TSI-MGH-" + ConvertBaseNToDecDecrypt(theInput.substring(2), 32);
        } catch (Exception e) {
            log.fatal("Unhandled error in mgh_encnum_decrypt: " + e.getMessage());
            return m_sEncryptionErrorValue;
        }
    }

    public String generic_encnum_encrypt(String theInput) throws I2B2Exception {
        return generic_encrypt(theInput);
    }

    public String generic_encrypt(String theInput) throws I2B2Exception {
        if ((theInput == null) || (theInput.length() == 0)) {
            log.warn("Empty input to generic encryption: ");
            return m_sEncryptionErrorValue;
        }
        try {
            String encryptedAccession = ConvertDecToBaseNEncrypt(theInput, 32);
            return encryptedAccession;
        } catch (Exception e) {
            log.fatal("Unhandled error in generic_encrypt: " + e.getMessage());
            throw new I2B2Exception(e.getMessage(), e);
        }
        //
        //   return m_sEncryptionErrorValue;
        //}
    }

    public String generic_encnum_derypt(String theInput) throws I2B2Exception {
        return generic_decrypt(theInput);
    }

    public String generic_decrypt(String theInput) throws I2B2Exception {
        if ((theInput == null) || (theInput.length() == 0)) {
            log.warn("Empty input to generic decryption: ");
            return m_sEncryptionErrorValue;
        }
        String accession64 = theInput;
        try {
            accession64 = ConvertBaseNToDecDecrypt(accession64, 32);
            return accession64;
        } catch (Exception e) {
            log.fatal("Unhandled error in generic_decrypt: " + e.getMessage());
            throw new I2B2Exception(e.getMessage(), e);
            //   return m_sEncryptionErrorValue;
        }
    }

    public String mrn_decrypt(String theInput, boolean standardLength) {
        if ((theInput == null) || (theInput.length() == 0))
            return m_sEncryptionErrorValue;
        int standard_length;
        //StringBuffer theOutput = new StringBuffer(16);
        if (theInput.startsWith(m_sMGH_IdentifyingFirstCharacter)) {
            standard_length = m_iMGH_de_standard_length;
        } else if (theInput.startsWith(m_sBWH_IdentifyingFirstCharacter)) {
            standard_length = m_iBWH_de_standard_length;
        } else if (theInput.startsWith(m_sEMPI_IdentifyingFirstCharacter)) {
            standard_length = m_iEMPI_de_standard_length;
        } else {
            //Lib.TError("A valid site was not passed to mrn_decrypt function");
            return m_sEncryptionErrorValue;
        }
        String theLong = null;
        String sTempNumber = theInput.substring(1);
        sTempNumber = sTempNumber.replaceAll(m_sTheFillCharacter, ""); //Lib.StrFindAndReplace(m_sTheFillCharacter,"",sTempNumber);
        try {
            theLong = ConvertBaseNToDecDecrypt(sTempNumber, 32);
            theLong = leftPad(theLong, standard_length, m_sTheDeFillCharacter);
        } catch (Exception e) {
            log.fatal("Parsing error in mrn_decrypt, message was: " + e.getMessage());
            return m_sEncryptionErrorValue;
        }
        return theLong;
    }

    public static String leftPad(String stringToPad, int size, String padder) {
        if (padder.length() == 0) {
            return stringToPad;
        }
        StringBuffer strb = new StringBuffer(size);
        StringCharacterIterator sci = new StringCharacterIterator(padder);

        while (strb.length() < (size - stringToPad.length())) {
            for (char ch = sci.first(); ch != CharacterIterator.DONE; ch = sci.next()) {
                if (strb.length() < size - stringToPad.length()) {
                    strb.insert(strb.length(), String.valueOf(ch));
                }
            }
        }
        return strb.append(stringToPad).toString();
    }

    public String rightPad(String s, int length, char pad) {
        StringBuffer buffer = new StringBuffer(s);
        int curLen = s.length();
        if (curLen < length) {
            for (int i = 0; i < length; i++) {
                buffer.append(pad);
            }
        }
        return buffer.toString();
    }

    //* B220
    // Samples: Y229033779X3XXXXXXXX, Y96289732X10003XXXXX
    public String encnum_decrypt(String sEncNumber) {
        if ((sEncNumber == null) || (sEncNumber.length() == 0)) {
            // log.fatal(("No IDX main number to decrypt");
            return m_sEncryptionErrorValue;
        }
        try {
            //int theLength = sEncNumber.length();
            int theGroupNumberStartsOn = sEncNumber.indexOf('X');
            // get the encounter number part, start after the 'Y'
            String sIdxEncNumber = sEncNumber.substring(1, theGroupNumberStartsOn);
            // decrypt the encounter number

            String sDecryptIdxEncNumber = cipher.decrypt(sIdxEncNumber);
            // get the group number part, start after the 'X'
            String sIdxGroupNumber = sEncNumber.substring(theGroupNumberStartsOn + 1, sEncNumber.length());
            // take off the trailing 'X's
            char sTheFillCharacter = m_sTheFillCharacter.charAt(0);
            int iLastX = sIdxGroupNumber.length();
            for (int i = 0; i < sIdxGroupNumber.length(); i++) {
                if (sIdxGroupNumber.charAt(i) == sTheFillCharacter) {
                    iLastX = i;
                    break;
                }
            }
            sIdxGroupNumber = sIdxGroupNumber.substring(0, iLastX);
            // make the encounter number in the form:
            // ... IDX-<group number>-<encounter number>
            String sFinalNumber = "IDX-MGH-" + sIdxGroupNumber + "-" + sDecryptIdxEncNumber;
            return sFinalNumber;
        } catch (Exception e) {
            log.fatal("Error in idxmgh_encnum_decrypt: " + e.getMessage());
            return m_sEncryptionErrorValue;
        }
    }

    //* 3231
    public String encnum_encrypt(String sExtraNumber, String sMainNumber) {
        int standard_length = 20;
        StringBuffer theOutput = new StringBuffer(standard_length);
        if ((sMainNumber == null) || (sMainNumber.length() == 0)) {
            // log.fatal("No IDX main number to encrypt");
            return m_sEncryptionErrorValue;
        }
        if ((sExtraNumber == null) || (sExtraNumber.length() == 0)) {
            log.error("No IDX extra number with main number " + sMainNumber);
            return m_sEncryptionErrorValue;
        }
        String sEncMainNumber = null;
        try {
            sEncMainNumber = cipher.encrypt(sMainNumber);
        } catch (Exception e) {
            log.fatal("Parsing error in idxmgh_encnum_encrypt, message was: " + e.getMessage());
            return m_sEncryptionErrorValue;
        }
        String theLong = sEncMainNumber + "X" + sExtraNumber;
        try {
            int addXes = standard_length - 1 - theLong.length();
            if (addXes < 0) {
                log.error("A number to encrypt exceeded the maximum allowable length, the number was: '" + theLong
                        + "'.");
                return m_sEncryptionErrorValue;
            } else {
                theOutput.append("Z");
                theOutput.append(theLong);
                for (int i = 0; i < addXes; i++) {
                    theOutput.append(m_sTheFillCharacter);
                }
                return theOutput.toString();
            }
        } catch (Exception e) {
            log.fatal("Unhandled error in mrn_encrypt: " + e.getMessage());
            return m_sEncryptionErrorValue;
        }
    }

    /*
     * ConvertDecToBaseNEncrypt makes the encrypted string in base N
     * 
     * The string is first encrypted into AES than converted to base N
     *
     * @param bVale String is the cleartext string of any length.
     * @param byBase Int is the base to use, between 2 and 36
     * @returns the ciphertext string in base N
     */
    public String ConvertDecToBaseNEncrypt(String bValue, int byBase) throws Exception {

        String sValue = ConvertDecToBaseNClear(cipher.bencrypt(bValue), byBase);

        if (!bValue.equals(ConvertBaseNToDecDecrypt(sValue, byBase)))
            throw new Exception("Encryption check failed for Base N: " + bValue);

        //String sValue = cipher.bencrypt(bValue).toString();
        return sValue;
    }

    /*
     * ConvertDecToBaseNClear makes the string in base N
     * 
     * The reason for calling Clear is because to does not call any encryption
     * routines.  The input string is converted into multiple 8 byte arrays and 
     * converted into int64 which is than converted into the selected base.
     * The routine will add '!' for padding if the returned string is to small
     * so that all the strings are the same length.
     *
     * @param bVale Byte[] is the byte array of any length.
     * @param byBase Int is the base to use, between 2 and 36
     * @returns the base N string
     */
    private String ConvertDecToBaseNClear(byte[] bValue, int byBase) throws Exception {
        double bValueLen = bValue.length;
        double divValue = bValueLen / 8;
        double celing = Math.ceil(divValue);
        int rounds = (int) celing;
        StringBuilder dValue = new StringBuilder(26);
        int count = 0;
        for (int i = 0; i < rounds; i++) {
            int endLen = 8;
            if ((count + 8) > bValue.length)
                endLen = bValue.length - count;
            byte[] b = new byte[8];

            System.arraycopy(bValue, count, b, 0, endLen);

            // this is slow
            UInt64 myGuidInt = BitConverter(b);

            StringBuilder sValue = new StringBuilder();
            sValue.append(ConvertDecToBaseNClear(myGuidInt, 32));
            // Deal with short strings
            if (sValue.length() < 13) {
                int addXes = 13 - sValue.length();
                for (int j = 0; j < addXes; j++) {
                    sValue.append("!");
                }
            }
            dValue.append(sValue);
            count = count + 8;
        }
        return dValue.toString();
    }

    /*
     * ConvertDecToBaseNClear makes the int in base N
     * 
     * The reason for calling Clear is because to does not call any encryption
     * routines.  This is the actual routine that does the conversation into
     * the base N.  The reason for using unsigned is because the conversation
     * using AES would have negative inte values which would get lost when converting
     * into the base representation.
     *
     * @param dValue uint64 is a valid unsigned integer
     * @param byBase Int is the base to use, between 2 and 36
     * @returns the base N string
     */
    private String ConvertDecToBaseNClear(UInt64 dValue, long byBase) throws Exception {
        String BaseNums = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        //String sResult = "";
        StringBuffer sResult = new StringBuffer();
        UInt64 dRemainder;

        //sResult = "";

        if ((byBase >= 2) && (byBase <= 36)) {
            while (dValue.compareTo(0) > 0) // x > 0 
            {
                dRemainder = dValue.divideAndRemainder(byBase);
                //sResult = BaseNums.substring(dRemainder.intValue(), dRemainder.intValue()+1) + sResult;
                sResult.insert(0, BaseNums.substring(dRemainder.intValue(), dRemainder.intValue() + 1));
            }
            return sResult.toString();
        } else {
            throw new Exception("Base should be between 2 and 36.");
        }
    }

    /*
     * ConvertBaseNToDecClear makes the string from base N
     * 
     * The reason for calling Clear is because to does not call any encryption
     * routines.  This is the actual routine that does the conversation from
     * the base N.  The reason for using unsigned is because the conversation
     * using AES would have negative inte values which would get lost when converting
     * into the base representation. The routine will remove any '!' used for padding
     *
     * @param dValue string is a valid base N string of length of a valid int64 base
     * @param byBase Int is the base to use, between 2 and 36
     * @returns the string
     */
    private UInt64 ConvertBaseNToDecClear(int byBase, String origValue) throws Exception {
        // Deal with short strings
        String dValue = origValue;
        while (dValue.endsWith("!"))
            dValue = dValue.substring(0, dValue.length() - 1);

        String BaseNums = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
        UInt64 lReturn = new UInt64(0);
        int n;
        if ((byBase >= 2) && (byBase <= 36)) {
            n = 0;
            while (n != dValue.length()) {
                //lReturn = (long) ((BaseNums.indexOf(dValue.substring(((dValue.length() - n) - 1), dValue.length() - 1))) 
                //      * (Math.pow(byBase,n))) + lReturn;

                //Half working
                //lReturn.add(
                //      new  java.math.BigInteger(Long.toString((BaseNums.indexOf(
                //            dValue.substring(((dValue.length() - n) - 1), dValue.length() - n)))
                //      * (long) (Math.pow(byBase,n)))));

                UInt64 a = new UInt64(Long.toString(
                        (BaseNums.indexOf(dValue.substring(((dValue.length() - n) - 1), dValue.length() - n)))));
                a.multiply((long) (Math.pow(byBase, n)));

                lReturn.add(a.bigIntValue());

                n++;
            }
            return lReturn;
        } else {
            throw new Exception("Base should be between 2 and 36.");
        }
    }

    /*
     * ConvertBaseNToDecDecrypt makes the string from base N into the original string
     * 
     * The input string is split into multiple chuncks.  Each chunck is split into 2
     * sections.  Both are converted back into the original string and appeneded together
     * The new string is decrypted and returned. 
     *
     * @param dValue string is a valid base N string of any length
     * @param byBase Int is the base to use, between 2 and 36
     * @returns the cleartext string in a string.
     */
    public String ConvertBaseNToDecDecrypt(String dValue, int byBase) throws Exception {
        int rounds = dValue.length() / 13;
        StringBuffer sValue = new StringBuffer();
        byte[] cipherB = new byte[16];
        for (int i = 0; i < rounds; i = i + 2) {
            UInt64 myInt = ConvertBaseNToDecClear(32, dValue.substring(i * 13, (i + 1) * 13));
            byte[] b = BitConverter(myInt);

            System.arraycopy(b, 0, cipherB, 0, 8);

            myInt = ConvertBaseNToDecClear(32, dValue.substring((i + 1) * 13, (i + 2) * 13));
            b = BitConverter(myInt);

            System.arraycopy(b, 0, cipherB, 8, 8);
            //String a = new String( cipher.decrypt(cipherB));
            //a = a.substring(0, a.indexOf(0));      

            byte[] ciph = cipher.decrypt(cipherB);
            int len = ciph[15];
            if ((len < 0) || (len > 16))
                throw new Exception("Invalid key");
            sValue.append(new String(ciph, 0, len)); //.trim();
        }
        return sValue.toString();

    }

    //   Converts a double into an array of bytes with length 
    // eight.
    private byte[] BitConverter(UInt64 a) {
        UInt64 value = new UInt64(a.bigIntValue());
        byte[] w = new byte[8];

        w[0] = value.byteValue();
        value.shiftRight(8);
        w[1] = (value.byteValue());

        value = new UInt64(a.bigIntValue());
        value.shiftRight(16);
        w[2] = (value.byteValue());

        value = new UInt64(a.bigIntValue());
        value.shiftRight(24);
        w[3] = (value.byteValue());

        value = new UInt64(a.bigIntValue());
        value.shiftRight(32);
        w[4] = (value.byteValue());

        value = new UInt64(a.bigIntValue());
        value.shiftRight(40);
        w[5] = (value.byteValue());

        value = new UInt64(a.bigIntValue());
        value.shiftRight(48);
        w[6] = (value.byteValue());

        value = new UInt64(a.bigIntValue());
        value.shiftRight(56);
        w[7] = (value.byteValue());
        return w;
    }

    private UInt64 BitConverter(byte[] a) {
        UInt64 accum = new UInt64("0");
        long fff = 0;
        for (int shiftBy = 0; shiftBy < 64; shiftBy += 8) {
            long b = a[shiftBy / 8] & 0xff;
            b = b << shiftBy;
            fff = fff | b;
        }
        if (fff < 0) {
            accum = new UInt64(Long.toString(Long.MAX_VALUE));
            accum.add(new java.math.BigInteger(Long.toString(fff + 2)));
            accum.add(new java.math.BigInteger(Long.toString(Long.MAX_VALUE)));
        } else {
            accum = new UInt64(Long.toString(fff));
        }
        return accum;
    }

    public static void main(String[] args) {
    }

}