All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.dyadicsec.advapi.SDESessionKey Maven / Gradle / Ivy

Go to download

This is a collection of JAVA libraries that implement Unbound cryptographic classes for JAVA provider, PKCS11 wrapper, cryptoki, and advapi

There is a newer version: 42761
Show newest version
package com.dyadicsec.advapi;

import com.dyadicsec.pkcs11.CKException;
import com.dyadicsec.pkcs11.CKSecretKey;
import com.dyadicsec.pkcs11.DYCK_FPE_PARAMS;
import com.unbound.common.crypto.FPE;
import com.unbound.common.crypto.HMAC;
import com.unbound.common.crypto.SPE;

import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Calendar;
import java.util.TimeZone;

/**
 * This class includes methods for application level encryption using a derived data encryption key (DEK), see Application-Level Encryption in the UKC Developers Guide for more information.
 */
public class SDESessionKey
{
  private int purpose;
  SDEKey sdeKey = null;
  CKSecretKey secretKey = null;
  byte[] rawKey = null;

  SDESessionKey(SDEKey sdeKey, int purpose, CKSecretKey secretKey)
  {
    this.secretKey = secretKey;
    this.sdeKey = sdeKey;
    this.purpose = purpose;
  }

  SDESessionKey(SDEKey sdeKey, int purpose, byte[] rawKey)
  {
    this.rawKey = rawKey;
    this.sdeKey = sdeKey;
    this.purpose = purpose;
  }

  @Override
  protected void finalize()
  {
    destroy();
  }

  public void destroy()
  {
    if (secretKey == null) return;
    try
    {
      secretKey.destroy();
    }
    catch (CKException e)
    {
    }
    secretKey = null;
  }

  public byte[] getKeyMaterial()
  {
    if (rawKey!=null) return rawKey;

    try
    {
      return secretKey.getValue();
    }
    catch (CKException e)
    {
      return null;
    }
  }

  /**
   * Get the SDEKey used to derive this date encryption key
   *
   * @return The SDEKey used for this data encryption key derivation
   */
  public SDEKey getSDEKey()
  {
    return sdeKey;
  }

  private static final int ONEWAY_TOKEN_SIZE = 16;

  /**
   * Creates a unique searchable token from a byte array
   *
   * @param in The input data
   * @return Searchable token of size 16 bytes
   * @throws SecurityException In case of encryption error
   */
  public byte[] encryptPRF(byte[] in) throws SecurityException
  {
    if (purpose != SDEKey.PURPOSE_ONE_WAY) throw new IllegalArgumentException("Invalid purpose");

    if (rawKey!=null)
    {
      return HMAC.SHA256.hmac(rawKey, in);
    }

    try
    {
      return secretKey.hmacSha256(in);
    }
    catch (CKException e)
    {
      throw new SecurityException(e);
    }
  }

  /**
   * Creates a unique searchable token from a byte array
   *
   * @param data The input data
   * @return Searchable token of size 16 bytes
   * @throws SecurityException In case of encryption error
   */
  public String encryptPRF(final String data) throws SecurityException
  {
    try
    {
      byte[] encData = encryptPRF(data.getBytes("UTF8"));
      return SDEUtils.bytesToStringTP(encData);
    }
    catch (UnsupportedEncodingException e)
    {
      throw new SecurityException(e);
    }
  }

  private byte[] encryptTypePreserving(byte[] in, int bits) throws SecurityException
  {
    if (purpose != SDEKey.PURPOSE_SP_ENC) throw new IllegalArgumentException("Invalid purpose");
    if ((in.length < 16) && ((bits % 2) != 0) && bits != 1)
      throw new IllegalArgumentException("Byte array input for type preserving encryption cannot be odd and less then 16 bytes");

    if (rawKey!=null)
    {
      return SPE.encrypt(rawKey, in, bits);
    }

    try
    {
      return secretKey.encryptSPE(in, bits);
    }
    catch (CKException e)
    {
      throw new SecurityException(e);
    }
  }

  /**
   * Encrypt a byte array
   *
   * @param in The data to encrypt, the length of the array should be even or at least 16 bytes
   * @return The encrypted value, the size of the encrypted data equals to the size of the input
   * @throws SecurityException In case of encryption error
   */
  public byte[] encryptTypePreserving(byte[] in) throws SecurityException
  {
    return encryptTypePreserving(in, in.length * 8);
  }

  private byte[] decryptTypePreserving(byte[] in, int bits) throws SecurityException
  {
    if (purpose != SDEKey.PURPOSE_SP_ENC) throw new IllegalArgumentException("Invalid purpose");
    if ((in.length < 16) && ((bits % 2) != 0) && bits != 1)
      throw new IllegalArgumentException("Byte array input for type preserving decryption cannot be odd and less then 16 bytes");

    if (rawKey!=null)
    {
      return SPE.decrypt(rawKey, in, bits);
    }

    try
    {
      return secretKey.decryptSPE(in, bits);
    }
    catch (CKException e)
    {
      throw new SecurityException(e);
    }
  }

  /**
   * Decrypt a byte array
   *
   * @param in The encrypted data
   * @return Decrryped byte array
   * @throws SecurityException In case of decryption error
   */
  public byte[] decryptTypePreserving(byte[] in) throws SecurityException
  {
    return decryptTypePreserving(in, in.length * 8);
  }


  /**
   * Encrypt a string value
   *
   * @param in      The data to encrypt
   * @param BMPOnly Determines if the plain and cipher text includes only Unicode Basic Multilingual Plane codes
   *                or all Unicode planes. BMP plain should be suitable for most of the use cases and
   *                has a more compact byte representation. Set to false if the full set of Unicode codes is
   *                required. For more information on Unicode planes,
   *                see https://en.wikipedia.org/wiki/Plane_(Unicode)
   * @return Encrypted value
   * @throws SecurityException In case of encryption error
   */
  public String encryptTypePreserving(String in, boolean BMPOnly) throws SecurityException
  {
    if (purpose != SDEKey.PURPOSE_STRING_ENC) throw new IllegalArgumentException("Invalid purpose");

    if (rawKey!=null)
    {
      return FPE.STR.encrypt(rawKey, in, BMPOnly);
    }

    try
    {
      String format = BMPOnly ? "ISO-10646-UCS-2" : "UTF-16BE";
      return secretKey.encryptStringFPE(in, format);
    }
    catch (CKException e)
    {
      throw new SecurityException(e);
    }
  }

  /**
   * DEcrypt a string value
   *
   * @param in      The data to decrypt
   * @param BMPOnly Determines if the plain and cipher text includes only Unicode Basic Multilingual Plane codes
   *                or all Unicode planes. BMP plain should be suitable for most of the use cases and
   *                has a more compact byte representation. Set to false if the full set of Unicode codes is
   *                required. For more information on Unicode planes,
   *                see https://en.wikipedia.org/wiki/Plane_(Unicode)
   * @return Plain value
   * @throws SecurityException In case of encryption error
   */
  public String decryptTypePreserving(String in, boolean BMPOnly) throws SecurityException
  {
    if (purpose != SDEKey.PURPOSE_STRING_ENC) throw new IllegalArgumentException("Invalid purpose");

    if (rawKey!=null)
    {
      return FPE.STR.decrypt(rawKey, in, BMPOnly);
    }

    try
    {
      String format = BMPOnly ? "ISO-10646-UCS-2" : "UTF-16BE";
      return secretKey.decryptStringFPE(in, format);
    }
    catch (CKException e)
    {
      throw new SecurityException(e);
    }
  }

  /**
   * Encrypt a string value in order preserving form
   *
   * @param data The data to encrypt
   * @param size Maximum size of values that should be compared with this value
   * @return Encrypted value
   * @throws SecurityException In case of encryption error
   */
  public String encryptOrderPreserving(String data, int size) throws SecurityException
  {
    try
    {
      byte[] dataBytes = data.getBytes("UTF8");
      dataBytes = SDEUtils.addTailing(dataBytes, (byte) 0, size - dataBytes.length);
      byte[] encData = encryptOPE(dataBytes);
      return SDEUtils.bytesToStringOP(encData);
    }
    catch (UnsupportedEncodingException e)
    {
      throw new SecurityException(e);
    }
  }

  /**
   * Decrypt a string value encrypted with order preserving encryption
   *
   * @param encDataStr The encrypted value
   * @return String value in plain
   * @throws SecurityException In case of decryption error
   */
  public String decryptOrderPreserving(String encDataStr) throws SecurityException
  {
    try
    {
      byte[] encData = SDEUtils.stringToBytesOP(encDataStr);
      byte[] data = decryptOPE(encData);
      data = SDEUtils.removeTailing(data, (byte) 0);
      return new String(data, "UTF8");
    }
    catch (UnsupportedEncodingException e)
    {
      throw new SecurityException(e);
    }
  }


  byte[] encryptOPE(byte[] in) throws SecurityException
  {
    if (purpose != SDEKey.PURPOSE_OP_ENC) throw new IllegalArgumentException("Invalid purpose");
    try
    {
      return secretKey.encryptOPE(in);
    }
    catch (CKException e)
    {
      throw new SecurityException(e);
    }
  }

  byte[] decryptOPE(byte[] in) throws SecurityException
  {
    if (purpose != SDEKey.PURPOSE_OP_ENC) throw new IllegalArgumentException("Invalid purpose");
    try
    {
      return secretKey.decryptOPE(in);
    }
    catch (CKException e)
    {
      throw new SecurityException(e);
    }
  }

  /**
   * Encrypt a long value
   *
   * @param data The data to encrypt
   * @return Encrypted value
   * @throws SecurityException In case of encryption error
   */
  public long encryptTypePreserving(long data) throws SecurityException
  {
    byte[] dataBytes = ByteBuffer.allocate(Long.SIZE / Byte.SIZE).putLong(data).array();
    byte[] encData = encryptTypePreserving(dataBytes);
    ByteBuffer wrapped = ByteBuffer.wrap(encData); // big-endian by default
    return wrapped.getLong();
  }

  /**
   * Decrypt an encryptyed long value
   *
   * @param encData The encrypted value
   * @return long value in plain
   * @throws SecurityException In case of decryption error
   */
  public long decryptTypePreserving(long encData) throws SecurityException
  {
    byte[] encDataBytes = ByteBuffer.allocate(Long.SIZE / Byte.SIZE).putLong(encData).array();
    byte[] data = decryptTypePreserving(encDataBytes);
    ByteBuffer wrapped = ByteBuffer.wrap(data);
    return wrapped.getLong();
  }

  /**
   * Encrypt a integer value
   *
   * @param data The data to encrypt
   * @return Encrypted value
   * @throws SecurityException In case of encryption error
   */
  public int encryptTypePreserving(int data) throws SecurityException
  {
    byte[] dataBytes = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE).putInt(data).array();
    byte[] encData = encryptTypePreserving(dataBytes);
    ByteBuffer wrapped = ByteBuffer.wrap(encData); // big-endian by default
    return wrapped.getInt();
  }

  /**
   * Decrypt an encryptyed integer value
   *
   * @param encData The encrypted value
   * @return long value in plain
   * @throws SecurityException In case of decryption error
   */
  public int decryptTypePreserving(int encData) throws SecurityException
  {
    byte[] encDataBytes = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE).putInt(encData).array();
    byte[] data = decryptTypePreserving(encDataBytes);
    ByteBuffer wrapped = ByteBuffer.wrap(data);
    return wrapped.getInt();
  }

  /**
   * Encrypt an integer value in order preserving form, encrypted value is of type long
   *
   * @param data The data to encrypt
   * @return Encrypted value
   * @throws SecurityException In case of encryption error
   */
  public long encryptOrderPreserving(int data) throws SecurityException
  {
    byte[] dataBytes = ByteBuffer.allocate(Integer.SIZE / Byte.SIZE).putInt(data).array();
    byte[] encData = encryptOPE(dataBytes);
    ByteBuffer wrapped = ByteBuffer.wrap(encData); // big-endian by default
    return wrapped.getLong();
  }

  /**
   * Decrypt an integer value encrypted with order preserving encryption
   *
   * @param encData The encrypted value
   * @return Integer value in plain
   * @throws SecurityException In case of decryption error
   */
  public int decryptOrderPreserving(long encData) throws SecurityException
  {
    byte[] encDataBytes = ByteBuffer.allocate(Long.SIZE / Byte.SIZE).putLong(encData).array();
    byte[] data = decryptOPE(encDataBytes);
    ByteBuffer wrapped = ByteBuffer.wrap(data); // big-endian by default
    return wrapped.getInt();
  }

  /**
   * Encrypt a short value
   *
   * @param data The data to encrypt
   * @return Encrypted value
   * @throws SecurityException In case of encryption error
   */
  public short encryptTypePreserving(short data) throws SecurityException
  {
    byte[] dataBytes = ByteBuffer.allocate(Short.SIZE / Byte.SIZE).putShort(data).array();
    byte[] encData = encryptTypePreserving(dataBytes);
    ByteBuffer wrapped = ByteBuffer.wrap(encData); // big-endian by default
    return wrapped.getShort();
  }

  /**
   * Decrypt an encryptyed short value
   *
   * @param encData The encrypted value
   * @return String value in plain
   * @throws SecurityException In case of decryption error
   */
  public short decryptTypePreserving(short encData) throws SecurityException
  {
    byte[] encDataBytes = ByteBuffer.allocate(Short.SIZE / Byte.SIZE).putShort(encData).array();
    byte[] data = decryptTypePreserving(encDataBytes);
    ByteBuffer wrapped = ByteBuffer.wrap(data);
    return wrapped.getShort();
  }

  /**
   * Encrypt a short value in order preserving form, the return value is of type long
   *
   * @param data The value to encrypt
   * @return Encrypted value
   * @throws SecurityException In case of encryption error
   */
  public long encryptOrderPreserving(short data) throws SecurityException
  {
    return encryptOrderPreserving((int) data);
  }

  /**
   * Encrypt a float value
   *
   * @param data The value to encrypt
   * @return Encrypted value
   * @throws SecurityException In case of encryption error
   */
  public float encryptTypePreserving(float data) throws SecurityException
  {
    byte[] dataBytes = ByteBuffer.allocate(Float.SIZE / Byte.SIZE).putFloat(data).array();
    byte[] encData = encryptTypePreserving(dataBytes);
    ByteBuffer wrapped = ByteBuffer.wrap(encData);
    return wrapped.getFloat();
  }

  /**
   * Decrypt an encryptyed float value
   *
   * @param encData The encrypted value
   * @return Float value in plain
   * @throws SecurityException In case of decryption error
   */
  public float decryptTypePreserving(float encData) throws SecurityException
  {
    byte[] encDataBytes = ByteBuffer.allocate(Float.SIZE / Byte.SIZE).putFloat(encData).array();
    byte[] data = decryptTypePreserving(encDataBytes);
    ByteBuffer wrapped = ByteBuffer.wrap(data);
    return wrapped.getFloat();
  }

  /**
   * Encrypt a double value
   *
   * @param data The value to encrypt
   * @return Encrypted value
   * @throws SecurityException In case of encryption error
   */
  public double encryptTypePreserving(double data) throws SecurityException
  {
    byte[] dataBytes = ByteBuffer.allocate(Double.SIZE / Byte.SIZE).putDouble(data).array();
    byte[] encData = encryptTypePreserving(dataBytes);
    ByteBuffer wrapped = ByteBuffer.wrap(encData);
    return wrapped.getDouble();
  }

  /**
   * Decrypt an encryptyed double value
   *
   * @param encData The encrypted value
   * @return Double value in plain
   * @throws SecurityException In case of decryption error
   */
  public double decryptTypePreserving(double encData) throws SecurityException
  {
    byte[] encDataBytes = ByteBuffer.allocate(Double.SIZE / Byte.SIZE).putDouble(encData).array();
    byte[] data = decryptTypePreserving(encDataBytes);
    ByteBuffer wrapped = ByteBuffer.wrap(data);
    return wrapped.getDouble();
  }

  private static final int MS_PER_DAY = (1000 * 60 * 60 * 24);

  /**
   * Encrypt a Date value
   *
   * @param data The data to encrypt
   * @return Encrypted value
   * @throws SecurityException In case of encryption error
   */
  public java.sql.Date encryptTypePreserving(java.sql.Date data) throws SecurityException
  {
    Calendar calendar = Calendar.getInstance();
    calendar.setTime(data);

    Calendar utcCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));

    utcCal.set(Calendar.YEAR, calendar.get(Calendar.YEAR));
    utcCal.set(Calendar.MONTH, calendar.get(Calendar.MONTH));
    utcCal.set(Calendar.DAY_OF_MONTH, calendar.get(Calendar.DAY_OF_MONTH));
    utcCal.set(Calendar.MILLISECOND, 0);
    utcCal.set(Calendar.SECOND, 0);
    utcCal.set(Calendar.MINUTE, 0);
    utcCal.set(Calendar.HOUR_OF_DAY, 0);

    long dateAsLongUTC = utcCal.getTimeInMillis();
    long d = dateAsLongUTC / MS_PER_DAY;
    //long e = d * MS_PER_DAY;

    byte[] dataBytes = ByteBuffer.allocate(Long.SIZE / Byte.SIZE).putLong(d).array();

    SDEUtils.reverseBytes(dataBytes);
    dataBytes = Arrays.copyOf(dataBytes, 3); // we need only 3 bytes

    byte[] encData = encryptTypePreserving(dataBytes, 20);

    SDEUtils.reverseBytes(encData);
    byte[] longData = new byte[8];
    System.arraycopy(encData, 0, longData, 5, 3);

    ByteBuffer wrapped = ByteBuffer.wrap(longData);
    long output = wrapped.getLong() * MS_PER_DAY;
    return new java.sql.Date(output);
  }

  /**
   * Decrypt an encryptyed Date value
   *
   * @param encData The encrypted value
   * @return Date value in plain
   * @throws SecurityException In case of decryption error
   */
  public java.sql.Date decryptTypePreserving(java.sql.Date encData) throws SecurityException
  {
    long dateAsLong = encData.getTime();
    long d = dateAsLong / MS_PER_DAY;
    byte[] encDataBytes = ByteBuffer.allocate(Long.SIZE / Byte.SIZE).putLong(d).array();

    SDEUtils.reverseBytes(encDataBytes);
    encDataBytes = Arrays.copyOf(encDataBytes, 3); // we need only 3 bytes

    byte[] data = decryptTypePreserving(encDataBytes, 20);

    SDEUtils.reverseBytes(data);

    byte[] longData = new byte[8];
    System.arraycopy(data, 0, longData, 5, 3);
    ByteBuffer wrapped = ByteBuffer.wrap(longData);

    long output = wrapped.getLong();

    Calendar localCal = Calendar.getInstance();
    Calendar utcCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));

    utcCal.setTimeInMillis(output * MS_PER_DAY);
    localCal.setTimeInMillis(0); // Epoch
    localCal.set(Calendar.MILLISECOND, utcCal.get(Calendar.MILLISECOND));
    localCal.set(Calendar.SECOND, utcCal.get(Calendar.SECOND));
    localCal.set(Calendar.MINUTE, utcCal.get(Calendar.MINUTE));
    localCal.set(Calendar.HOUR_OF_DAY, utcCal.get(Calendar.HOUR_OF_DAY));
    localCal.set(Calendar.DAY_OF_MONTH, utcCal.get(Calendar.DAY_OF_MONTH));
    localCal.set(Calendar.MONTH, utcCal.get(Calendar.MONTH));
    localCal.set(Calendar.YEAR, utcCal.get(Calendar.YEAR));

    return new java.sql.Date(localCal.getTimeInMillis());
  }

  /**
   * Encrypt a Time value
   *
   * @param data The data to encrypt
   * @return Encrypted value
   * @throws SecurityException In case of encryption error
   */
  public java.sql.Time encryptTypePreserving(java.sql.Time data) throws SecurityException
  {
    Calendar localCal = Calendar.getInstance();
    localCal.setTime(data);

    Calendar utcCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
    utcCal.setTimeInMillis(0); // Epoch
    utcCal.set(Calendar.MILLISECOND, 0);
    utcCal.set(Calendar.SECOND, 0);
    utcCal.set(Calendar.MINUTE, localCal.get(Calendar.MINUTE));
    utcCal.set(Calendar.HOUR_OF_DAY, localCal.get(Calendar.HOUR_OF_DAY));

    //long timeAsLong = Math.round(cal.getTimeInMillis()/10f);
    long timeAsLong = utcCal.getTimeInMillis() / 1000 / 60;


    byte[] dataBytes = ByteBuffer.allocate(Long.SIZE / Byte.SIZE).putLong(timeAsLong).array();

    SDEUtils.reverseBytes(dataBytes);
    dataBytes = Arrays.copyOf(dataBytes, 2); // we need only 3 bytes

    byte[] encData = encryptTypePreserving(dataBytes, 12);

    SDEUtils.reverseBytes(encData);
    byte[] longData = new byte[8];
    System.arraycopy(encData, 0, longData, 6, 2);

    ByteBuffer wrapped = ByteBuffer.wrap(longData);
    long output = wrapped.getLong() * 1000;
    return new java.sql.Time(output);
  }

  /**
   * Decrypt an encryptyed Time value
   *
   * @param encData The encrypted value
   * @return Time value in plain
   * @throws SecurityException In case of decryption error
   */
  public java.sql.Time decryptTypePreserving(java.sql.Time encData) throws SecurityException
  {
    long timeAsLong = encData.getTime() / 1000;
    byte[] encDataBytes = ByteBuffer.allocate(Long.SIZE / Byte.SIZE).putLong(timeAsLong).array();

    byte[] data = new byte[Long.SIZE / Byte.SIZE];
    SDEUtils.reverseBytes(encDataBytes);
    encDataBytes = Arrays.copyOf(encDataBytes, 2); // we need only 3 bytes

    data = decryptTypePreserving(encDataBytes, 12);

    SDEUtils.reverseBytes(data);
    byte[] longData = new byte[8];
    System.arraycopy(data, 0, longData, 6, 2);
    ByteBuffer wrapped = ByteBuffer.wrap(longData);

    long output = wrapped.getLong();
    //java.sql.Time time1 = new java.sql.Time(output * 100);


    Calendar localCal = Calendar.getInstance();
    Calendar utcCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));

    utcCal.setTimeInMillis(output * 1000 * 60);
    localCal.setTimeInMillis(0); // Epoch
    localCal.set(Calendar.MILLISECOND, 0);
    localCal.set(Calendar.SECOND, 0);
    localCal.set(Calendar.MINUTE, utcCal.get(Calendar.MINUTE));
    localCal.set(Calendar.HOUR_OF_DAY, utcCal.get(Calendar.HOUR_OF_DAY));

    java.sql.Time time = new java.sql.Time(localCal.getTime().getTime());
    return time;
  }

  /**
   * Encrypt a Timestamp value
   *
   * @param data The data to encrypt
   * @return Encrypted value
   * @throws SecurityException In case of encryption error
   */
  public java.sql.Timestamp encryptTypePreserving(java.sql.Timestamp data) throws SecurityException
  {
    Calendar calendar = Calendar.getInstance();
    calendar.setTime(data);

    Calendar utcCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));

    utcCal.set(Calendar.YEAR, calendar.get(Calendar.YEAR));
    utcCal.set(Calendar.MONTH, calendar.get(Calendar.MONTH));
    utcCal.set(Calendar.DAY_OF_MONTH, calendar.get(Calendar.DAY_OF_MONTH));
    utcCal.set(Calendar.MILLISECOND, calendar.get(Calendar.MILLISECOND));
    utcCal.set(Calendar.SECOND, calendar.get(Calendar.SECOND));
    utcCal.set(Calendar.MINUTE, calendar.get(Calendar.MINUTE));
    utcCal.set(Calendar.HOUR_OF_DAY, calendar.get(Calendar.HOUR_OF_DAY));

    long dateAsLongUTC = utcCal.getTimeInMillis();

    byte[] dataBytes = ByteBuffer.allocate(Long.SIZE / Byte.SIZE).putLong(dateAsLongUTC).array();


    SDEUtils.reverseBytes(dataBytes);
    dataBytes = Arrays.copyOf(dataBytes, 6);

    byte[] encData = encryptTypePreserving(dataBytes, 46);

    SDEUtils.reverseBytes(encData);
    byte[] longData = new byte[8];
    System.arraycopy(encData, 0, longData, 2, 6);
    ByteBuffer wrapped = ByteBuffer.wrap(longData);

    long output = wrapped.getLong();
    java.sql.Timestamp date = new java.sql.Timestamp(output);

    return date;
  }

  /**
   * Decrypt an encryptyed Timestamp value
   *
   * @param encData The encrypted value
   * @return Timestamp value in plain
   * @throws SecurityException In case of decryption error
   */
  public java.sql.Timestamp decryptTypePreserving(java.sql.Timestamp encData) throws SecurityException
  {
    long dateAsLong = encData.getTime();
    byte[] encDataBytes = ByteBuffer.allocate(Long.SIZE / Byte.SIZE).putLong(dateAsLong).array();

    SDEUtils.reverseBytes(encDataBytes);
    encDataBytes = Arrays.copyOf(encDataBytes, 6);

    byte[] data = decryptTypePreserving(encDataBytes, 46);

    SDEUtils.reverseBytes(data);
    byte[] longData = new byte[8];
    System.arraycopy(data, 0, longData, 2, 6);

    ByteBuffer wrapped = ByteBuffer.wrap(longData);

    long output = wrapped.getLong();

    Calendar localCal = Calendar.getInstance();
    Calendar utcCal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));

    utcCal.setTimeInMillis(output);
    localCal.setTimeInMillis(0); // Epoch
    localCal.set(Calendar.MILLISECOND, utcCal.get(Calendar.MILLISECOND));
    localCal.set(Calendar.SECOND, utcCal.get(Calendar.SECOND));
    localCal.set(Calendar.MINUTE, utcCal.get(Calendar.MINUTE));
    localCal.set(Calendar.HOUR_OF_DAY, utcCal.get(Calendar.HOUR_OF_DAY));
    localCal.set(Calendar.DAY_OF_MONTH, utcCal.get(Calendar.DAY_OF_MONTH));
    localCal.set(Calendar.MONTH, utcCal.get(Calendar.MONTH));
    localCal.set(Calendar.YEAR, utcCal.get(Calendar.YEAR));

    java.sql.Timestamp date = new java.sql.Timestamp(localCal.getTimeInMillis());
    return date;
  }

  /**
   * Encrypt a Timestamp value in order preserving form, encrypted value is of string type
   *
   * @param data The data to encrypt
   * @return Encrypted value
   * @throws SecurityException In case of encryption error
   */
  public String encryptOrderPreserving(java.sql.Timestamp data) throws SecurityException
  {
    long time = data.getTime();
    int nanos = data.getNanos();

    ByteBuffer encDataBytesBuffer = ByteBuffer.allocate(Long.SIZE / Byte.SIZE + Integer.SIZE / Byte.SIZE);

    encDataBytesBuffer.putLong(0, time);
    encDataBytesBuffer.putInt(Long.SIZE / Byte.SIZE, nanos);

    byte[] dataBytes = encDataBytesBuffer.array();
    byte[] encData = encryptOPE(dataBytes);

    return SDEUtils.bytesToStringOP(encData);
  }

  /**
   * Decrypt a Timestamp value encrypted with order preserving encryption
   *
   * @param encDataStr The encrypted value
   * @return Timestamp value in plain
   * @throws SecurityException In case of decryption error
   */
  public java.sql.Timestamp decryptOrderPreservingTS(String encDataStr) throws SecurityException
  {
    byte[] encData = SDEUtils.stringToBytesOP(encDataStr);

    byte[] data = decryptOPE(encData);

    ByteBuffer wrapped = ByteBuffer.wrap(data); // big-endian by default

    long time = wrapped.getLong(0);
    int nanos = wrapped.getInt(Long.SIZE / Byte.SIZE);
    java.sql.Timestamp ts = new java.sql.Timestamp(time);
    ts.setNanos(nanos);

    return ts;
  }

  /**
   * Encrypt a boolean value
   *
   * @param data The data to encrypt
   * @return Encrypted value
   * @throws SecurityException In case of encryption error
   */
  public boolean encryptTypePreserving(boolean data) throws SecurityException
  {
    byte[] in = new byte[1];
    in[0] = data ? (byte) 1 : (byte) 0;
    return encryptTypePreserving(in, 1)[0] != 0;
  }

  /**
   * Decrypt an encryptyed boolean value
   *
   * @param encData The encrypted value
   * @return Boolean value in plain
   * @throws SecurityException In case of decryption error
   */
  public boolean decryptTypePreserving(boolean encData) throws SecurityException
  {
    byte[] in = new byte[1];
    in[0] = encData ? (byte) 1 : (byte) 0;
    return decryptTypePreserving(in, 1)[0] != 0;
  }

  /**
   * Encrypt a Blob value
   *
   * @param data The data to encrypt
   * @return Encrypted value
   * @throws SecurityException In case of encryption error
   */
  public java.sql.Blob encryptTypePreserving(java.sql.Blob data) throws SecurityException
  {
    try
    {
      byte[] enc = encryptTypePreserving(data.getBytes(1, (int) data.length()));
      return new javax.sql.rowset.serial.SerialBlob(enc);
    }
    catch (SQLException e)
    {
      throw new SecurityException(e);
    }
  }

  /**
   * Decrypt an encryptyed Blob value
   *
   * @param encData The encrypted value
   * @return Blob value in plain
   * @throws SecurityException In case of decryption error
   */
  public java.sql.Blob decryptTypePreserving(java.sql.Blob encData) throws SecurityException
  {
    try
    {
      byte[] data = decryptTypePreserving(encData.getBytes(1, (int) encData.length()));
      return new javax.sql.rowset.serial.SerialBlob(data);
    }
    catch (SQLException e)
    {
      throw new SecurityException(e);
    }
  }

  /**
   * Encrypt a Clob value
   *
   * @param data The data to encrypt
   * @return Encrypted value
   * @throws SecurityException In case of encryption error
   */
  public java.sql.Clob encryptTypePreserving(java.sql.Clob data) throws SecurityException
  {
    try
    {
      String enc = encryptTypePreserving(data.getSubString(1, (int) data.length()), true);
      return new javax.sql.rowset.serial.SerialClob(enc.toCharArray());
    }
    catch (SQLException e)
    {
      throw new SecurityException(e);
    }
  }

  /**
   * Decrypt an encryptyed Clob value
   *
   * @param encData The encrypted value
   * @return Clob value in plain
   * @throws SecurityException In case of decryption error
   */
  public java.sql.Clob decryptTypePreserving(java.sql.Clob encData) throws SecurityException
  {
    try
    {
      String data = decryptTypePreserving(encData.getSubString(1, (int) encData.length()), true);
      return new javax.sql.rowset.serial.SerialClob(data.toCharArray());
    }
    catch (SQLException e)
    {
      throw new SecurityException(e);
    }
  }

  /**
   * Encrypt a BigDecimal value
   *
   * @param data The data to encrypt
   * @return Encrypted value
   * @throws SecurityException In case of encryption error
   */
  public java.math.BigDecimal encryptTypePreserving(java.math.BigDecimal data) throws SecurityException
  {
    try
    {
      int scale = data.scale();
      BigInteger bi = data.unscaledValue();
      boolean bNegative = bi.signum() == -1;
      bi = bi.abs();
      byte[] biBytes = bi.toByteArray();

      int biBytesLength = biBytes.length;
      if (biBytesLength > 12)
      {
        if ((biBytesLength == 13) && (biBytes[0] == 0))
        {
          // ok, ignore that
          byte[] newBytes = new byte[12];
          System.arraycopy(biBytes, 1, newBytes, 0, 12);
          biBytes = newBytes;
        }
        else
        {
          throw new IllegalArgumentException("Value encryption is not supported");
        }
      }
      else
      {
        biBytes = SDEUtils.addLeading(biBytes, (byte) 0, 12 - biBytesLength);
      }
//            if ((biBytesLength < 16) && ((biBytesLength % 2) != 0)) {
//                if (biBytes[0] < 0) {
//                    biBytes = addLeading(biBytes, (byte) -1, 1);
//                } else {
//                    biBytes = addLeading(biBytes, (byte) 0, 1);
//                }
//            }
      byte[] enc = encryptTypePreserving(biBytes);


//            enc = addLeading(enc, (byte) 1, 1); // make sure we wont have leading 0 on the byte array

      enc = SDEUtils.addLeading(enc, (byte) 0, 1);  // make it positive for sure
      BigInteger encBi = new BigInteger(enc);
      if (bNegative)
      {
        encBi = encBi.negate();
      }
      return new java.math.BigDecimal(encBi, scale);
    }
    catch (Exception e)
    {
      throw new SecurityException(e);
    }
  }

  /**
   * Decrypt an encryptyed BigDecimal value
   *
   * @param encData The encrypted value
   * @return BigDecimal value in plain
   * @throws SecurityException In case of decryption error
   */
  public java.math.BigDecimal decryptTypePreserving(java.math.BigDecimal encData) throws SecurityException
  {
    try
    {
      int scale = encData.scale();
      BigInteger bi = encData.unscaledValue();
      boolean bNegative = bi.signum() == -1;
      bi = bi.abs();

      byte[] biBytes = bi.toByteArray();

      int biBytesLength = biBytes.length;
      if (biBytesLength > 12)
      {
        if ((biBytesLength == 13) && (biBytes[0] == 0))
        {
          // ok, ignore that
          byte[] newBytes = new byte[12];
          System.arraycopy(biBytes, 1, newBytes, 0, 12);
          biBytes = newBytes;
        }
        else
        {
          throw new IllegalArgumentException("Value encryption is not supported");
        }
      }
      else
      {
        biBytes = SDEUtils.addLeading(biBytes, (byte) 0, 12 - biBytesLength);
      }

//            if (biBytes[0] != 1) {
//                throw new IllegalArgumentException("Value was not decrypted with type preserving");
//            }
//            biBytes = removeLeading(biBytes, (byte) 1, true);

      byte[] data = decryptTypePreserving(biBytes);

      data = SDEUtils.addLeading(data, (byte) 0, 1);  // make it positive for sure
      BigInteger dataBi = new BigInteger(data);
      if (bNegative)
      {
        dataBi = dataBi.negate();
      }

//            BigInteger dataBi = new BigInteger(data);
      return new java.math.BigDecimal(dataBi, scale);
    }
    catch (Exception e)
    {
      throw new SecurityException(e);
    }
  }

  /**
   * Encrypt an email address in format preserving form, the encrypted value is also a legitimate email address
   *
   * @param in     Email address to encrypt
   * @param maxLen Maximum size of all email addresses encrypted
   * @return The encrypted value
   * @throws SecurityException In case of encryption error
   */
  public String encryptEMailAddress(String in, int maxLen) throws SecurityException
  {
    if (purpose != SDEKey.PURPOSE_EMAIL_ENC) throw new IllegalArgumentException("Invalid purpose");

    if (rawKey!=null)
    {
      return FPE.EMail.encrypt(rawKey, in, maxLen);
    }

    try
    {
      byte[] inBuf = in.getBytes("UTF-8");
      byte[] outBuf = secretKey.encryptFPE(DYCK_FPE_PARAMS.DYCK_FPE_EMAIL, null, maxLen, inBuf);
      return new String(outBuf, "UTF-8");
    }
    catch (UnsupportedEncodingException e)
    {
      throw new SecurityException(e);
    }
    catch (CKException e)
    {
      throw new SecurityException(e);
    }
  }

  /**
   * Decrypt an encrypted email address, the encrypted value is also an email address
   *
   * @param in The encrypted value
   * @return Original plain email address
   * @throws SecurityException In case of decryption error
   */
  public String decryptEMailAddress(String in) throws SecurityException
  {
    if (purpose != SDEKey.PURPOSE_EMAIL_ENC) throw new IllegalArgumentException("Invalid purpose");

    if (rawKey!=null)
    {
      return FPE.EMail.decrypt(rawKey, in);
    }

    try
    {
      byte[] inBuf = in.getBytes("UTF-8");
      byte[] outBuf = secretKey.decryptFPE(DYCK_FPE_PARAMS.DYCK_FPE_EMAIL, null, inBuf);
      return new String(outBuf, "UTF-8");
    }
    catch (UnsupportedEncodingException e)
    {
      throw new SecurityException(e);
    }
    catch (CKException e)
    {
      throw new SecurityException(e);
    }
  }

  /**
   * Encrypt a credit card number in format preserving form, the encrypted value is also a legitimate
   * credit card number
   *
   * @param in Credit card number to encrypt
   * @return The encrypted value
   * @throws SecurityException In case of encryption error
   */
  public String encryptCreditCard(String in) throws SecurityException
  {
    if (purpose != SDEKey.PURPOSE_CREDIT_CARD_ENC) throw new IllegalArgumentException("Invalid purpose");

    if (rawKey!=null)
    {
      return FPE.CreditCard.encrypt(rawKey, in, null);
    }

    try
    {
      byte[] inBuf = in.getBytes("UTF-8");
      byte[] outBuf = secretKey.encryptFPE(DYCK_FPE_PARAMS.DYCK_FPE_CREDIT_CARD, null, 0, inBuf);
      if (outBuf == null) throw new SecurityException("encryptCreditCard failed");
      return new String(outBuf, "UTF-8");
    }
    catch (UnsupportedEncodingException e)
    {
      throw new SecurityException(e);
    }
    catch (CKException e)
    {
      throw new SecurityException(e);
    }
  }

  public String encryptCreditCard(String in, String format) throws SecurityException
  {
    if (purpose != SDEKey.PURPOSE_CREDIT_CARD_ENC) throw new IllegalArgumentException("Invalid purpose");

    if (rawKey!=null)
    {
      return FPE.CreditCard.encrypt(rawKey, in, format);
    }

    try
    {
      byte[] inBuf = in.getBytes("UTF-8");
      byte[] outBuf = secretKey.encryptFPE(DYCK_FPE_PARAMS.DYCK_FPE_CREDIT_CARD, format.toCharArray(), 0, inBuf);
      if (outBuf == null) throw new SecurityException("encryptCreditCard failed");
      return new String(outBuf, "UTF-8");
    }
    catch (UnsupportedEncodingException e)
    {
      throw new SecurityException(e);
    }
    catch (CKException e)
    {
      throw new SecurityException(e);
    }
  }

  /**
   * Decrypt a credit card number, the encrypted value is also a credit card number
   *
   * @param in The encrypted value
   * @return Original plain email address
   * @throws SecurityException In case of decryption error
   */
  public String decryptCreditCard(String in) throws SecurityException
  {
    if (purpose != SDEKey.PURPOSE_CREDIT_CARD_ENC) throw new IllegalArgumentException("Invalid purpose");

    if (rawKey!=null)
    {
      return FPE.CreditCard.decrypt(rawKey, in, null);
    }

    try
    {
      byte[] inBuf = in.getBytes("UTF-8");
      byte[] outBuf = secretKey.decryptFPE(DYCK_FPE_PARAMS.DYCK_FPE_CREDIT_CARD, null, inBuf);
      return new String(outBuf, "UTF-8");
    }
    catch (UnsupportedEncodingException e)
    {
      throw new SecurityException(e);
    }
    catch (CKException e)
    {
      throw new SecurityException(e);
    }
  }

  public String decryptCreditCard(String in, String format) throws SecurityException
  {
    if (purpose != SDEKey.PURPOSE_CREDIT_CARD_ENC) throw new IllegalArgumentException("Invalid purpose");

    if (rawKey!=null)
    {
      return FPE.CreditCard.decrypt(rawKey, in, format);
    }

    try
    {
      byte[] inBuf = in.getBytes("UTF-8");
      byte[] outBuf = secretKey.decryptFPE(DYCK_FPE_PARAMS.DYCK_FPE_CREDIT_CARD, format.toCharArray(), inBuf);
      return new String(outBuf, "UTF-8");
    }
    catch (UnsupportedEncodingException e)
    {
      throw new SecurityException(e);
    }
    catch (CKException e)
    {
      throw new SecurityException(e);
    }
  }

  /**
   * Encrypt a US phone in format preserving form, the encrypted value is also a legitimate US phone number
   *
   * @param in     Email address to encrypt
   * @param format The output format, e.g. "###-###-####"
   * @return The encrypted value
   * @throws SecurityException In case of encryption error
   */
  public String encryptUSPhone(String in, String format) throws SecurityException
  {
    if (purpose != SDEKey.PURPOSE_US_PHONE_ENC) throw new IllegalArgumentException("Invalid purpose");

    if (rawKey!=null)
    {
      return FPE.USPhone.encrypt(rawKey, in, format);
    }

    try
    {
      char[] formatChars = format == null ? null : format.toCharArray();
      byte[] inBuf = in.getBytes("UTF-8");
      byte[] outBuf = secretKey.encryptFPE(DYCK_FPE_PARAMS.DYCK_FPE_US_PHONE, formatChars, 0, inBuf);
      return new String(outBuf, "UTF-8");
    }
    catch (UnsupportedEncodingException e)
    {
      throw new SecurityException(e);
    }
    catch (CKException e)
    {
      throw new SecurityException(e);
    }
  }

  /**
   * Decrypt an encrypted US phone number, the encrypted value is also a US phone number
   *
   * @param in     The encrypted value
   * @param format The output format, e.g. "###-###-####"
   * @return Original plain US phone number
   * @throws SecurityException In case of decryption error
   */
  public String decryptUSPhone(String in, String format) throws SecurityException
  {
    if (purpose != SDEKey.PURPOSE_US_PHONE_ENC) throw new IllegalArgumentException("Invalid purpose");

    if (rawKey!=null)
    {
      return FPE.USPhone.decrypt(rawKey, in, format);
    }

    try
    {
      char[] formatChars = format == null ? null : format.toCharArray();
      byte[] inBuf = in.getBytes("UTF-8");
      byte[] outBuf = secretKey.decryptFPE(DYCK_FPE_PARAMS.DYCK_FPE_US_PHONE, formatChars, inBuf);
      return new String(outBuf, "UTF-8");
    }
    catch (UnsupportedEncodingException e)
    {
      throw new SecurityException(e);
    }
    catch (CKException e)
    {
      throw new SecurityException(e);
    }
  }

  /**
   * Encrypt a SSN in format preserving form, the encrypted value is also a legitimate SSN
   *
   * @param in     SSN to encrypt
   * @param format The output format, e.g. "###-##-####"
   * @return The encrypted value
   * @throws SecurityException In case of encryption error
   */
  public String encryptSSN(String in, String format) throws SecurityException
  {
    if (purpose != SDEKey.PURPOSE_SSN_ENC) throw new IllegalArgumentException("Invalid purpose");

    if (rawKey!=null)
    {
      return FPE.SSN.encrypt(rawKey, in, format);
    }

    try
    {
      char[] formatChars = format == null ? null : format.toCharArray();
      byte[] inBuf = in.getBytes("UTF-8");
      byte[] outBuf = secretKey.encryptFPE(DYCK_FPE_PARAMS.DYCK_FPE_SSN, formatChars, 0, inBuf);
      return new String(outBuf, "UTF-8");
    }
    catch (UnsupportedEncodingException e)
    {
      throw new SecurityException(e);
    }
    catch (CKException e)
    {
      throw new SecurityException(e);
    }
  }

  /**
   * Decrypt an encrypted SSN, the encrypted value is also SSN
   *
   * @param in     The encrypted value
   * @param format The output format, e.g. "###-##-####"
   * @return Original plain SSN
   * @throws SecurityException In case of decryption error
   */
  public String decryptSSN(String in, String format) throws SecurityException
  {
    if (purpose != SDEKey.PURPOSE_SSN_ENC) throw new IllegalArgumentException("Invalid purpose");

    if (rawKey!=null)
    {
      return FPE.SSN.decrypt(rawKey, in, format);
    }

    try
    {
      char[] formatChars = format == null ? null : format.toCharArray();
      byte[] inBuf = in.getBytes("UTF-8");
      byte[] outBuf = secretKey.decryptFPE(DYCK_FPE_PARAMS.DYCK_FPE_SSN, formatChars, inBuf);
      return new String(outBuf, "UTF-8");
    }
    catch (UnsupportedEncodingException e)
    {
      throw new SecurityException(e);
    }
    catch (CKException e)
    {
      throw new SecurityException(e);
    }
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy