![JAR search and dependency download from the Maven repository](/logo.png)
com.dyadicsec.advapi.SDESessionKey Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of unbound-java-provider Show documentation
Show all versions of unbound-java-provider Show documentation
This is a collection of JAVA libraries that implement Unbound cryptographic classes for JAVA provider, PKCS11 wrapper, cryptoki, and advapi
package com.dyadicsec.advapi;
import com.dyadicsec.cryptoki.*;
import com.unbound.client.CipherMode;
import com.unbound.client.CipherOper;
import com.unbound.client.Client;
import com.unbound.client.pkcs11.PKCS11SecretKey;
import com.unbound.client.pkcs11.PKCS11Session;
import com.unbound.common.Converter;
import com.unbound.common.crypto.FPE;
import com.unbound.common.crypto.HMAC;
import com.unbound.common.crypto.SPE;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.ProviderException;
import java.sql.SQLException;
import java.time.*;
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
{
final private int purpose;
final SDEKey sdeKey;
PKCS11SecretKey secretKey = null;
final byte[] rawKey;
SDESessionKey(SDEKey sdeKey, int purpose, PKCS11SecretKey secretKey)
{
this.rawKey = null;
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;
secretKey.delete();
secretKey = null;
}
public byte[] getKeyMaterial()
{
if (rawKey!=null) return rawKey;
PKCS11Session session=null;
try
{
session = (PKCS11Session)sdeKey.prfKey.getPartition().acquireSession();
return secretKey.getValue(session);
}
finally { if (session!=null) session.release(); }
}
/**
* 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");
return HMAC.SHA256.hmac(getKeyMaterial(), in);
}
/**
* 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
{
byte[] encData = encryptPRF(data.getBytes(StandardCharsets.UTF_8));
return SDEUtils.bytesToStringTP(encData);
}
private CipherOper newOperation(CipherMode mode, boolean enc)
{
CipherOper oper = Client.getInstance().newCipherOperation();
oper.encMode = enc;
oper.mode = mode;
oper.keyObject = secretKey;
return oper;
}
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);
CipherOper oper = newOperation(CipherMode.SPE, true);
oper.speBits = bits;
return oper.enc(in);
}
/**
* Encrypt a byte array
*
* @param in The data to encrypt, where the length of the array should be even or at least 16 bytes
* @return The encrypted value, where 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);
CipherOper oper = newOperation(CipherMode.SPE, false);
oper.keyObject = secretKey;
oper.speBits = bits;
return oper.dec(in);
}
/**
* 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. The string must be Unicode (as defined by ISO/IEC 10646).
*
* @param in The data to encrypt
* @param BMPOnly Determines if the plain and cipher text includes only Unicode Basic Multilingual Plane (BMP) codes
* or all Unicode planes. BMP 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);
}
String format = BMPOnly ? "ISO-10646-UCS-2" : "UTF-16BE";
CipherOper oper = newOperation(CipherMode.FPE, true);
oper.fpeFormat = format;
oper.fpeMode = DYCK_FPE_PARAMS.DYCK_FPE_STRING;
byte[] inBuf = in.getBytes(StandardCharsets.UTF_16BE);
byte[] outBuf = oper.enc(inBuf);
return new String(outBuf, StandardCharsets.UTF_16BE);
}
/**
* 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 (BMP) codes
* or all Unicode planes. BMP 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);
}
String format = BMPOnly ? "ISO-10646-UCS-2" : "UTF-16BE";
CipherOper oper = newOperation(CipherMode.FPE, false);
oper.fpeFormat = format;
oper.fpeMode = DYCK_FPE_PARAMS.DYCK_FPE_STRING;
byte[] inBuf = in.getBytes(StandardCharsets.UTF_16BE);
byte[] outBuf = oper.dec(inBuf);
return new String(outBuf, StandardCharsets.UTF_16BE);
}
/**
* 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
{
if (rawKey!=null) throw new ProviderException("Not supported in clientless mode");
byte[] dataBytes = data.getBytes(StandardCharsets.UTF_8);
dataBytes = SDEUtils.addTailing(dataBytes, (byte) 0, size - dataBytes.length);
byte[] encData = encryptOPE(dataBytes);
return SDEUtils.bytesToStringOP(encData);
}
/**
* 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
{
if (rawKey!=null) throw new ProviderException("Not supported in clientless mode");
byte[] encData = SDEUtils.stringToBytesOP(encDataStr);
byte[] data = decryptOPE(encData);
data = SDEUtils.removeTailing(data, (byte) 0);
return new String(data, StandardCharsets.UTF_8);
}
byte[] encryptOPE(byte[] in) throws SecurityException
{
if (rawKey!=null) throw new ProviderException("Not supported in clientless mode");
if (purpose != SDEKey.PURPOSE_OP_ENC) throw new IllegalArgumentException("Invalid purpose");
CipherOper oper = newOperation(CipherMode.OPE, true);
return oper.enc(in);
}
byte[] decryptOPE(byte[] in) throws SecurityException
{
if (rawKey!=null) throw new ProviderException("Not supported in clientless mode");
if (purpose != SDEKey.PURPOSE_OP_ENC) throw new IllegalArgumentException("Invalid purpose");
CipherOper oper = newOperation(CipherMode.OPE, false);
return oper.dec(in);
}
/**
* 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, where 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);
}
static private boolean isValidFloatBin(int u)
{
int man = u & 0x007fffff; // 23 bits
int exp = (u>>23) & 0x000000ff; // 8 bits
int sign = (u>>31) & 0x00000001; // 1 bit
if (exp == 0)
{
if (sign != 0) return false;
if (man == 0) return true; //ZERO;
return false; //SUBNORMAL;
}
if (exp == 0xff)
{
if (u==0x7f800000) return true; //POSITIVE_INFINITY
if (u==0xff800000) return true; //NEGATIVE_INFINITY
if (u==0x7fc00000) return true; //NaN
return false;
}
return true; //NORMAL;
}
static private boolean isValidDoubleBin(long u)
{
long man = u & 0x000fffffffffffffL; // 52 bits
int exp = (int)((u>>52) & 0x000007ff); // 11 bits
int sign = (int)((u>>63) & 0x00000001); // 1 bit
if (exp == 0)
{
if (sign != 0) return false;
if (man == 0) return true; //ZERO;
return false; //SUBNORMAL;
}
if (exp == 0x7ff)
{
if (u==0x7ff0000000000000L) return true; //POSITIVE_INFINITY
if (u==0xfff0000000000000L) return true; //NEGATIVE_INFINITY
if (u==0x7ff8000000000000L) return true; //NaN
return false;
}
return true; //NORMAL;
}
/**
* 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
{
int u = Float.floatToRawIntBits(data);
if (!isValidFloatBin(u)) throw new IllegalArgumentException("Invalid float value");
byte[] b = new byte[4];
Converter.setLE4(b, 0, u);
for (;;)
{
b = encryptTypePreserving(b);
u = Converter.getLE4(b,0);
if (isValidFloatBin(u)) break;
}
return Float.intBitsToFloat(u);
}
/**
* 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
{
int u = Float.floatToRawIntBits(encData);
if (!isValidFloatBin(u)) throw new IllegalArgumentException("Invalid float value");
byte[] b = new byte[4];
Converter.setLE4(b, 0, u);
for (;;)
{
b = decryptTypePreserving(b);
u = Converter.getLE4(b,0);
if (isValidFloatBin(u)) break;
}
return Float.intBitsToFloat(u);
}
/**
* 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
{
long u = Double.doubleToRawLongBits(data);
if (!isValidDoubleBin(u)) throw new IllegalArgumentException("Invalid float value");
byte[] b = new byte[8];
Converter.setLE8(b, 0, u);
for (;;)
{
b = encryptTypePreserving(b);
u = Converter.getLE8(b,0);
if (isValidDoubleBin(u)) break;
}
return Double.longBitsToDouble(u);
}
/**
* 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
{
long u = Double.doubleToRawLongBits(encData);
if (!isValidDoubleBin(u)) throw new IllegalArgumentException("Invalid float value");
byte[] b = new byte[8];
Converter.setLE8(b, 0, u);
for (;;)
{
b = decryptTypePreserving(b);
u = Converter.getLE8(b,0);
if (isValidDoubleBin(u)) break;
}
return Double.longBitsToDouble(u);
}
static long dateToDays(java.sql.Date date)
{
LocalDate local = date.toLocalDate();
Instant instant = local.atStartOfDay().toInstant(ZoneOffset.UTC);
Instant epoch = Instant.ofEpochMilli(0);
Duration duration = Duration.between(epoch, instant);
return duration.toDays();
}
static java.sql.Date daysToDate(long days)
{
Duration duration = Duration.ofDays(days);
Instant inst = Instant.ofEpochMilli(0).plus(duration);
LocalDate local = LocalDateTime.ofInstant(inst, ZoneOffset.UTC).toLocalDate();
return java.sql.Date.valueOf(local);
}
/**
* Encrypt a Date value
*
* @param plain The data to encrypt
* @return Encrypted value
* @throws SecurityException In case of encryption error
*/
public java.sql.Date encryptTypePreserving(java.sql.Date plain) throws SecurityException
{
long d = dateToDays(plain);
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();
return daysToDate(output);
}
/**
* Decrypt an encryptyed Date value
*
* @param enc The encrypted value
* @return Date value in plain
* @throws SecurityException In case of decryption error
*/
public java.sql.Date decryptTypePreserving(java.sql.Date enc) throws SecurityException
{
long d = dateToDays(enc);
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();
return daysToDate(output);
}
static int timeToSeconds(java.sql.Time time)
{
LocalTime local = time.toLocalTime();
return (local.getHour() * 60 + local.getMinute()) * 60 + local.getSecond();
}
static java.sql.Time secondstoTime(int seconds)
{
int hours = seconds / 3600; seconds %= 3600;
int minutes = seconds / 60; seconds %= 60;
LocalTime local = LocalTime.of(hours, minutes, seconds);
return java.sql.Time.valueOf(local);
}
/**
* Encrypt a Time value
*
* @param time The time to encrypt
* @return Encrypted value
* @throws SecurityException In case of encryption error
*/
public java.sql.Time encryptTypePreserving(java.sql.Time time) throws SecurityException
{
int seconds = timeToSeconds(time);
byte[] in = new byte[3];
for (;;)
{
in[0] = (byte)(seconds & 0xff);
in[1] = (byte)((seconds>>8) & 0xff);
in[2] = (byte)((seconds>>16) & 0x03);
byte[] out = encryptTypePreserving(in, 18);
if (out==null) throw new RuntimeException("encryptTime failed");
seconds =
(out[0] & 0xff) |
((out[1] & 0xff)<<8) |
((out[2] & 0x3)<<16);
if (seconds<86400) break;
}
return secondstoTime(seconds);
}
/**
* Decrypt an encryptyed Time value
*
* @param time The encrypted value
* @return Time value in plain
* @throws SecurityException In case of decryption error
*/
public java.sql.Time decryptTypePreserving(java.sql.Time time) throws SecurityException
{
int seconds = timeToSeconds(time);
byte[] in = new byte[3];
for (;;)
{
in[0] = (byte)(seconds & 0xff);
in[1] = (byte)((seconds>>8) & 0xff);
in[2] = (byte)((seconds>>16) & 0x03);
byte[] out = decryptTypePreserving(in, 18);
if (out==null) throw new RuntimeException("decryptTime failed");
seconds =
(out[0] & 0xff) |
((out[1] & 0xff)<<8) |
((out[2] & 0x3)<<16);
if (seconds<86400) break;
}
return secondstoTime(seconds);
}
/**
* 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);
}
}
private static boolean lsb(int x)
{
return (x & 1) != 0;
}
private static boolean xorAllBits(byte[] v)
{
byte x = 0;
for (int i=0; i> i);
return res;
}
/**
* 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);
}
boolean sig = bNegative ^ xorAllBits(biBytes);
byte[] enc = encryptTypePreserving(biBytes);
BigInteger encBi = new BigInteger(sig ? 1 : -1, enc);
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);
}
byte[] data = decryptTypePreserving(biBytes);
boolean sig = bNegative ^ xorAllBits(data);
data = SDEUtils.addLeading(data, (byte) 0, 1); // make it positive for sure
BigInteger dataBi = new BigInteger(sig ? 1 : -1, data);
return new java.math.BigDecimal(dataBi, scale);
}
catch (Exception e)
{
throw new SecurityException(e);
}
}
/**
* Encrypt an email address in format preserving form, where the encrypted value is also a legitimate email address.
* It can contain these characters: A-Z, a-z, 0-9, .!#$%&*+-/={|}~(),:;<>[]
* It must contain an @ as a separator and cannot contain spaces.
*
* @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);
}
byte[] inBuf = in.getBytes(StandardCharsets.UTF_8);
CipherOper oper = newOperation(CipherMode.FPE, true);
oper.fpeMaxLen = maxLen;
oper.fpeMode = DYCK_FPE_PARAMS.DYCK_FPE_EMAIL;
byte[] outBuf = oper.enc(inBuf);
return new String(outBuf, StandardCharsets.UTF_8);
}
/**
* Decrypt an encrypted email address, where 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);
}
byte[] inBuf = in.getBytes(StandardCharsets.UTF_8);
CipherOper oper = newOperation(CipherMode.FPE, false);
oper.fpeMode = DYCK_FPE_PARAMS.DYCK_FPE_EMAIL;
byte[] outBuf = oper.dec(inBuf);
return new String(outBuf, StandardCharsets.UTF_8);
}
/**
* Encrypt a credit card number in format preserving form, where the encrypted value is also a legitimate
* credit card number. Encryption uses a Luhn algorithm to verify valid credit card numbers. The number is
* * between 12 and 19 digits. Any non-digits, such as hyphens, are passed as-is.
*
* @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
{
return encryptCreditCard(in, null);
}
/**
* Encrypt a credit card number in format preserving form, where the encrypted value is also a legitimate
* credit card number. Encryption uses a Luhn algorithm to verify valid credit card numbers. The number is
* * between 12 and 19 digits. Any non-digits, such as hyphens, are passed as-is.
*
* @param in Credit card number to encrypt
* @param format The credit card number, where the # characters get encrypted, the ? characters are passed as plain text, and other characters are passed as-is to the output. For example, for "????-####-####-####", the first 4 numbers are plain and the rest of the credit card number is encrypted.
* @return The encrypted value
* @throws SecurityException In case of encryption error
*/
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);
}
byte[] inBuf = in.getBytes(StandardCharsets.UTF_8);
CipherOper oper = newOperation(CipherMode.FPE, true);
oper.fpeMode = DYCK_FPE_PARAMS.DYCK_FPE_CREDIT_CARD;
oper.fpeFormat = format;
byte[] outBuf = oper.enc(inBuf);
return new String(outBuf, StandardCharsets.UTF_8);
}
/**
* Decrypt a credit card number, where the encrypted value is also a credit card number
*
* @param in The encrypted value
* @return Original plain credit card
* @throws SecurityException In case of decryption error
*/
public String decryptCreditCard(String in) throws SecurityException
{
return decryptCreditCard(in, null);
}
/**
* Decrypt a credit card number, where the encrypted value is also a credit card number
*
* @param in The encrypted value
* @param format The credit card number, where the # characters get decrypted, the ? characters are passed as plain text, and other characters are passed as-is to the output. For example, for "????-####-####-####", the first 4 numbers are plain and the rest of the credit card number is decrypted.
* @return Original plain credit card
* @throws SecurityException In case of decryption error
*/
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);
}
byte[] inBuf = in.getBytes(StandardCharsets.UTF_8);
CipherOper oper = newOperation(CipherMode.FPE, false);
oper.fpeMode = DYCK_FPE_PARAMS.DYCK_FPE_CREDIT_CARD;
oper.fpeFormat = format;
byte[] outBuf = oper.dec(inBuf);
return new String(outBuf, StandardCharsets.UTF_8);
}
/**
* Encrypt a US phone in format preserving form, where the encrypted value is also a legitimate US phone number.
* The number is 10 digits. Any non-digits, such as hyphens, are passed as-is. It is validated by checking the
* format aaa-bcc-dddd, where aaa > 200, b >= 2, and cc is not 11.
*
* @param in Phone number to encrypt
* @param format The output format, where the # characters get encrypted and other characters are passed as-is to the output. For example, the format could be "###-###-####".
* @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);
}
byte[] inBuf = in.getBytes(StandardCharsets.UTF_8);
CipherOper oper = newOperation(CipherMode.FPE, true);
oper.fpeMode = DYCK_FPE_PARAMS.DYCK_FPE_US_PHONE;
oper.fpeFormat = format;
byte[] outBuf = oper.enc(inBuf);
return new String(outBuf, StandardCharsets.UTF_8);
}
/**
* Decrypt an encrypted US phone number, where the encrypted value is also a US phone number
*
* @param in The encrypted value
* @param format The output format, where the # characters get decrypted and other characters are passed as-is to the output. For example, the format could be "###-###-####".
* @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);
}
byte[] inBuf = in.getBytes(StandardCharsets.UTF_8);
CipherOper oper = newOperation(CipherMode.FPE, false);
oper.fpeMode = DYCK_FPE_PARAMS.DYCK_FPE_US_PHONE;
oper.fpeFormat = format;
byte[] outBuf = oper.dec(inBuf);
return new String(outBuf, StandardCharsets.UTF_8);
}
/**
* Encrypt an SSN in format preserving form, where the encrypted value is also a legitimate SSN.
* The SSN is a 9 digit number. Any non-digits, such as hyphens, are passed as-is. The SSN can be all
* numbers except:
* - Numbers with all zeros in any digit group (000-##-####, ###-00-####, ###-##-0000).
* - Numbers with 666 or 900-999 (Individual Taxpayer Identification Number) in the first digit group.
*
* @param in SSN to encrypt
* @param format The output format, where the # characters get encrypted, the ? characters are passed as plain text, and other characters are passed as-is to the output. Note that only the last 4 numbers can be plain text, so only "###-##-####" and "###-##-????" are acceptable formats (with or without the hyphen delimiters).
* @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);
}
byte[] inBuf = in.getBytes(StandardCharsets.UTF_8);
CipherOper oper = newOperation(CipherMode.FPE, true);
oper.fpeMode = DYCK_FPE_PARAMS.DYCK_FPE_SSN;
oper.fpeFormat = format;
byte[] outBuf = oper.enc(inBuf);
return new String(outBuf, StandardCharsets.UTF_8);
}
/**
* Decrypt an encrypted SSN, where the encrypted value is also SSN
*
* @param in The encrypted value
* @param format The output format, where the # characters get decrypted, the ? characters are passed as plain text, and other characters are passed as-is to the output. Note that only the last 4 numbers can be plain text, so only "###-##-####" and "###-##-????" are acceptable formats (with or without the hyphen delimiters).
* @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);
}
byte[] inBuf = in.getBytes(StandardCharsets.UTF_8);
CipherOper oper = newOperation(CipherMode.FPE, false);
oper.fpeMode = DYCK_FPE_PARAMS.DYCK_FPE_SSN;
oper.fpeFormat = format;
byte[] outBuf = oper.dec(inBuf);
return new String(outBuf, StandardCharsets.UTF_8);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy