/****************************************************************************** * The following is part of the KeySupport.org PIV API * * https://github.com/grandamp/KSJavaAPI/ * * @author Todd E. Johnson (tejohnson@yahoo.com) *****************************************************************************/ package org.keysupport.util; import java.math.BigInteger; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.Locale; import java.util.UUID; /** * Provides utility methods to perform common operations. * @author tejohnson */ public class DataUtil { private static final String numbers = "0123456789ABCDEF"; // TODO: Security consideration, ensure input value is only a hex string as // defined // if ([^0-9a-f]) { throw exception } /** * Convert a byte array to a Hex String * * The following method converts a byte[] object to a String object, where * the only output characters are "0123456789ABCDEF". * * @param ba * A byte array * @return String Hexidecimal String object which represents the contents of * the byte array */ public static String byteArrayToString(byte[] ba) { if (ba == null) { return ""; } StringBuffer hex = new StringBuffer(ba.length * 2); for (int i = 0; i < ba.length; i++) { hex.append(Integer.toString((ba[i] & 0xff) + 0x100, 16) .substring(1)); } return hex.toString().toUpperCase(Locale.US); } /** * Method byteArrayToUUID. * @param uuidBytes byte[] * @return UUID */ public static UUID byteArrayToUUID(byte[] uuidBytes) { // uuidBytes is expected to be 16 bytes long byte[] ba_msb = new byte[8]; System.arraycopy(uuidBytes, 0, ba_msb, 0, 8); byte[] ba_lsb = new byte[8]; System.arraycopy(uuidBytes, 8, ba_lsb, 0, 8); BigInteger msb = new BigInteger(ba_msb); BigInteger lsb = new BigInteger(ba_lsb); return new UUID(msb.longValue(), lsb.longValue()); } /** * Convert a byte to a Hex String * * The following method converts a byte[] object to a String object, where * the only output characters are "0123456789ABCDEF". * * @param ba * A single byte * @return String Hexidecimal String object which represents the contents of * the byte */ public static String byteToString(byte ba) { byte[] nba = { ba }; return byteArrayToString(nba); } /** * Method dateToString. * @param date Date * @return String */ public static String dateToString(Date date) { Calendar expireCa = new GregorianCalendar(); // Use the incoming Date object to set the Year, Month, and Day expireCa.setTime(date); int year = expireCa.get(Calendar.YEAR); int month = expireCa.get(Calendar.MONTH); int day = expireCa.get(Calendar.DAY_OF_MONTH); StringBuffer sb = new StringBuffer(); // I think we can trust we are working with 4 digit years sb.append(year); // Increment the month due to Jan = 0 with Calendar.MONTH month++; // Zeropad Month if needed if (month < 10) { sb.append('0'); } sb.append(month); // Zeropad Day if needed if (day < 10) { sb.append('0'); } sb.append(day); return sb.toString(); } /** * Convert a large byte array into multiple smaller byte arrays, with the * output size determined by the caller * * @param inputArray * An array of bytes * @param arraySize * The size of each array object returned in the Enumeration * @param zeroPad * Add a padding of zeros if the last array returned is shorter * than arraySize * @return Enumeration An Enumeration of byte arrays of the size specified * by the caller */ public static byte[][] getArrays(byte[] inputArray, int arraySize, boolean zeroPad) { byte[][] tdba = new byte[(int) Math.ceil(inputArray.length / (double) arraySize)][arraySize]; int start = 0; for (int i = 0; i < tdba.length; i++) { if (start + arraySize > inputArray.length) { byte[] lastArray; if (zeroPad) { lastArray = new byte[arraySize]; Arrays.fill(lastArray, (byte) 0x00); } else { lastArray = new byte[inputArray.length - start]; } System.arraycopy(inputArray, start, lastArray, 0, inputArray.length - start); tdba[i] = lastArray; } else { System.arraycopy(inputArray, start, tdba[i], 0, arraySize); } start += arraySize; } return tdba; } /** * Method getByteArray. * @param st String * @return byte[] */ public static byte[] getByteArray(String st) { byte[] ba = null; try { ba = new String(st).getBytes("UTF-8"); } catch (Exception e) { e.printStackTrace(); } return ba; } /** * Convert a byte array of UTF-8 Characters to String * * The following method converts a byte[] object to a String object, where * the only output characters are "0123456789ABCDEF". * * @param ba * A single byte * @return String Hexidecimal String object which represents the contents of * the byte */ public static String getString(byte[] ba) { String baSt = ""; if (ba == null) { return baSt; } try { baSt = new String(ba, "UTF-8"); } catch (Exception e) { e.printStackTrace(); } return baSt; } /** * Method pad. * @param inputArray byte[] * @param padByte byte * @param paddedArrayLen int * @return byte[] */ public static byte[] pad(byte[] inputArray, byte padByte, int paddedArrayLen) { byte[] padArray = new byte[paddedArrayLen]; Arrays.fill(padArray, padByte); System.arraycopy(inputArray, 0, padArray, 0, inputArray.length); return padArray; } /** * Convert a Hex String to a byte array * * The following method converts a String object to a byte[] object, where * the only valid input characters is "0123456789ABCDEF". * * @param s * Hexidecimal String object to convert to a byte array * @return byte[] A byte array */ public static byte[] stringToByteArray(String s) { if (s == null) return null; byte[] result = new byte[s.length() / 2]; for (int i = 0; i < s.length(); i += 2) { int i1 = numbers.indexOf(s.charAt(i)); int i2 = numbers.indexOf(s.charAt(i + 1)); result[i / 2] = (byte) ((i1 << 4) | i2); } return result; } /** * Method stringtoDate. * @param date String * @return Date */ public static Date stringtoDate(String date) { Calendar expireCa = new GregorianCalendar(); int year = Integer.parseInt(date.substring(0, 4)); int month = (Integer.parseInt(date.substring(4, 6)) - 1); int day = Integer.parseInt(date.substring(6, 8)); expireCa.set(Calendar.YEAR, year); expireCa.set(Calendar.MONTH, month); expireCa.set(Calendar.DAY_OF_MONTH, day); // We set the remainder of the fields to Zero since the CHUID is only // "YYYYMMDD" expireCa.set(Calendar.HOUR, 0); expireCa.set(Calendar.HOUR_OF_DAY, 0); expireCa.set(Calendar.MINUTE, 0); expireCa.set(Calendar.SECOND, 0); expireCa.set(Calendar.MILLISECOND, 0); return expireCa.getTime(); } /** * Method uuidToByteArray. * @param id UUID * @return byte[] */ public static byte[] uuidToByteArray(UUID id) { ByteBuffer buffer = ByteBuffer.allocate(16); buffer.putLong(id.getMostSignificantBits()); buffer.putLong(id.getLeastSignificantBits()); return buffer.array(); } /** * XOR two byte arrays * * The following method is used to XOR two byte array objects * * @param array1 * A byte array * @param array2 * A byte array * @return byte[] The result of array1^array2 */ public static byte[] XOR(byte[] array1, byte[] array2) { byte[] result = new byte[array1.length]; for (int i = 0; i < array1.length; i++) { result[i] = (byte) (array1[i] ^ array2[i]); } return result; } /************************************************************************** * PIN Prompting method * * This is a utility method that makes use of Java Swing components to * obtain a PIV PIN. *************************************************************************/ /* * public static byte[] getPIVPIN(String dialog_label) { char[] pin = * getPIN(dialog_label); byte[] pinbytes = new byte[pin.length]; for (int i * = 0; i < pinbytes.length; i++) { pinbytes[i] = (byte)pin[i]; pin[i] = * (char)0x00; } return pad(pinbytes, (byte)0xff, 8); } */ /************************************************************************** * PIN/Password Prompting method * * This is a utility method that makes use of Java Swing components to * obtain general token activation data. (PIN or Password) *************************************************************************/ /* * public static char[] getPIN(String dialog_label) { char[] pin = null; * while (pin == null) { final JPasswordField jpf = new JPasswordField(); * JOptionPane jop = new JOptionPane(jpf, JOptionPane.PLAIN_MESSAGE, * JOptionPane.OK_CANCEL_OPTION); JDialog dialog = * jop.createDialog(dialog_label); dialog.setVisible(true); int result = * (Integer)jop.getValue(); dialog.dispose(); if(result == * JOptionPane.OK_OPTION){ pin = jpf.getPassword(); } } return pin; } */ }