This is an example Java/Maven project demonstrating the use of Voltage SimpleAPI to perform fast and efficient data protection with Format Preserving Encryption (NIST FF1).
See your Voltage Professional Services representative to obtain the SimpleAPI binaries. The following items are not published to public repos, but are needed for execution:
- cache/ — directory to hold the policy cache
- libs/ — external libraries
- libvibesimplejava.dylib — native dynamic library
- vibesimplejava.jar — Java archive (import com.voltage.securedata.enterprise)
- trustStore/ — certificates for your Voltage appliance
You can build this project with the following commands (builds a single fat-jar):
# Installs the Voltage Simple API jar (import com.voltage.securedata.enterprise)
mvn install:install-file -Dfile=libs/vibesimplejava.jar -DgroupId=com.voltage -DartifactId=vibesimplejava -Dversion=1.0 -Dpackaging=jar
# Clean build
mvn clean packageThe Java is setup so that passwords and other sensitive info are contained in a ".env" file within the project root (create it; excluded with .gitignore):
ora.user="VOLTAGE"
ora.password="password"
ora.host="hostname.oraclecloud.com"
ora.service="oracle19c.adb.oraclecloud.com"
voltage.secret="sharedsecret"
voltage.host="appliance.voltage.com"
voltage.id="identity"And run with these commands:
# Run against data.csv as a source
java -Djava.library.path=libs -jar target/protection-1.0.jar "data.csv"
# Run against Oracle as a source
java -Djava.library.path=libs -jar target/protection-1.0.jar --oracleOptionally use these commands to run without a fat-jar:
java -cp "target/protection-1.0.jar:libs/*" -Djava.library.path=libs com.opentext.voltage.Protection "data.csv"
java --enable-native-access=ALL-UNNAMED -cp "target/protection-1.0.jar:libs/*" -Djava.library.path=libs com.opentext.voltage.Protection "../data.csv"The command line will output:
root@localhost protection % java -Djava.library.path=libs -jar target/protection-1.0.jar --oracle
Exports will save to: "/Voltage/Java/protection/"
Jdbc Url: "jdbc:oracle:thin:@(description= (retry_count=20)(retry_delay=3)(address=(protocol=tcps)(port=1521)(host=<host>))(connect_data=(service_name=<service>))(security=(ssl_server_dn_match=yes)))"
Query: "SELECT * FROM data ORDER BY id"
Total rows ingested = 5000
API Version: Simple API Java 6.22.0.5
Identity: "sampleidentity:070101000000Z:dataprotection.voltage.com#1188515279:data:FPE:256::"
FPE test -->
Cleartext: "Hello World"
Ciphertext: "Eujne Ootlc"
Cleartext: "123-45-6789"
Ciphertext: "762-48-6789"
Cleartext: "01-01-2026"
Ciphertext: "03-23-2007"
Cleartext: "1111-2222-3333-4444"
Ciphertext: "1111-22T5-CFBD-4444"
Cleartext: "02/2027"
Ciphertext: "07/2067"
Dummy enumerator block executed in 3.520125 ms
Empty enumerator block executed in 0.373375 ms
Protect block executed in 26.304667 ms
CSV exported to "/Voltage/Java/protection/protected-ORACLE.data.csv"
Unprotect block executed in 25.874417 ms
CSV exported to "/Voltage/Java/protection/unprotected-ORACLE.data.csv"The code uses a Timer class to calculate code execution time to the nano-second precision. As you can see from above, BLAZING FAST speed.
Timer timer = new Timer(); // Stopwatch instance
timer.reset(); // reset the counter
out("Elapsed time = " + timer.elapsed() + " ms"); // print elapsed time
static class Timer { // Stopwatch-timer class
private long start; // holds the start time in nanoseconds
public Timer() { start = System.nanoTime(); }
public double elapsed() { // milliseconds w/nano decimal part
return (System.nanoTime() - start) / 1_000_000.0;
}
public void reset() { start = System.nanoTime(); }
}The DDL to make an Oracle data source:
CREATE USER VOLTAGE IDENTIFIED BY "password";
GRANT CREATE SESSION TO VOLTAGE;
GRANT CREATE TABLE TO VOLTAGE;
GRANT UNLIMITED TABLESPACE TO VOLTAGE;
CREATE TABLE VOLTAGE.data (
id NUMBER PRIMARY KEY,
name VARCHAR2(75),
ssn VARCHAR2(11),
dob VARCHAR2(10),
card VARCHAR2(19),
exp VARCHAR2(7)
);
GRANT SELECT, INSERT ON VOLTAGE.data TO VOLTAGE;
SELECT * from VOLTAGE.DATA ORDER BY idA "data.csv" is provided in this example. It is also the default value should you not provide any argument to the command at runtime.
| id | name | ssn | dob | card | exp |
|---|---|---|---|---|---|
| 1 | Amy Nelson | 360-26-1232 | 09-21-1979 | 1969-8999-6827-5777 | 04/2026 |
| 2 | Betty Hernandez | 745-46-3763 | 09-18-2011 | 4807-9987-5584-9969 | 09/2027 |
| 3 | Fiona Cook | 762-85-6426 | 03-21-1977 | 5957-4081-1071-9407 | 07/2026 |
| 4 | Aiden Martin | 895-61-3408 | 11-02-2018 | 2905-2293-7691-6411 | 06/2026 |
| 5 | Arthur Walker | 586-89-8812 | 08-03-1964 | 7925-4193-6516-6129 | 06/2026 |
After protection, the data will appear as:
| id | name | ssn | dob | card | exp |
|---|---|---|---|---|---|
| 1 | Nzr Dtcmsq | 328-52-1232 | 12-29-1963 | 1969-89LE-K89T-5777 | 08/1976 |
| 2 | Pdrfn Tubklaipy | 463-57-3763 | 09-27-1984 | 4807-99AU-EEYF-9969 | 08/2066 |
| 3 | Ziltt Lgkg | 119-25-6426 | 08-26-1981 | 5957-40EE-V5VL-9407 | 10/1994 |
| 4 | Tuucj Vubmhq | 531-45-3408 | 08-01-1953 | 2905-22KJ-Q4VL-6411 | 10/2130 |
| 5 | Cppbvb Dstldn | 456-76-8812 | 02-19-2029 | 7925-41N7-02GF-6129 | 10/2130 |
This data can be re-created by running:
# Generates 5,000 rows of sample data
python3 data-generate.pyAnd then pushed up to Oracle by:
# Pushes to the DSN in your ".env" file
python3 data-oraclepush.py