edu.harvard.i2b2.im.util.HighEncryption.java Source code

Java tutorial

Introduction

Here is the source code for edu.harvard.i2b2.im.util.HighEncryption.java

Source

/*
 * Copyright (c) 2006-2009 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.im.util;

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 key) throws Exception {
        cipher = new RijndaelAlgorithm(key, 128); // , "AES"); //long
    }

    /*
    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");
        }
    }

    /**
     * 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) {
    }

}