Java bindings for Daan Sprenkels's Shamir secret sharing library
- Simple, stateless API
- Self-contained: All native dependencies are included, so there is no need to deploy DLLs, dylibs or shared objects separately.
- Lightweight: Only one Maven dependency, no transitive dependencies.
- These bindings have not been reviewed by experts. This is an experimental project and should not be used in production without further review and risk assessment.
- Since this project uses sss under the hood, the maximum amount of shares is 255. Additionally, sss only supports non-proactive secret sharing. Be sure to read the documentation of sss to decide whether it fits your needs.
- Only works on Linux, macOS and Windows right now.
- While Daan Sprenkels's sss library is resistant against side-channel attacks, this library is not.
- Due to technical limitations of the Java runtime, this library needs to create a temporary file on application startup to load the native wrapper for sss. This may lead to a security vulnerability (see below).
- The native DLL for Windows and the dynamic library for macOS are currently not signed.
- Possible elevation of privilege vulnerability: This library uses
com.github.ramanrajarathinam:native-utils:1.0.0
to load a JNI wrapper for sss.native-utils
works by first extracting the DLL, dylib or shared object file to a temp directory and then usingSystem.load()
to load it. If an adversary manages to replace the temporary file on disk beforeSystem.load
is called, they may be able to execute arbitrary code. To mitigate this vulnerability, make sure that your temp directorySystem.getProperty("java.io.tmpdir")
has appropriate file-system permissions. To learn more about how the JNI wrapper is loaded, please refer to NativeUtils.java ofnative-utils
.
to be updated once the artifacts are published to a Maven repository
// Create an instance of Shamir's Secret Sharing scheme.
// This object is stateless and can be reused for subsequent sharing and reconstruction operations.
ShamirsSecretSharing secretSharing = ShamirsSecretSharing.create();
// The secret to share must be a byte array. If you want to share e.g. a string, you need to convert it to a byte array first.
byte[] secret = "Hello world!".getBytes(StandardCharsets.UTF_8);
// Number of shares to generate. Must be in the range 0 < n < 256
int n = 19;
// Minimum number of shares required to reconstruct the secret. Must be in the range 0 < t <= n
int t = 10;
// Create the shares, which results in an array of length n.
// Each element of this array is a byte array that represents a single share.
byte[][] shares = secretSharing.share(n, t, secret);
// Send the shares to shareholders
for (int i = 0; i < shares.length; i++) {
YourCode.sendShareToShareholder(i, shares[i]);
}
// This library never modifies input parameters.
// You are responsible for clearing the secret from memory once you no longer need it!
// Beware of possible compiler and runtime optimizations that may prevent the following lines from taking effect.
Arrays.fill(secret, (byte)0);
for (byte[] share : shares) {
Arrays.fill(share, (byte)0);
}
// To reconstruct the secret, at least t shares are needed.
// The order of the shares in the array does not matter.
// Each element of the array should contain an actual share. Null values are not allowed.
byte[][] shares = YourCode.fetchSharesFromShareholders();
byte[] secret = null;
try {
// Reconstruct the secret
secret = secretSharing.reconstruct(shares);
System.out.println(new String(reconstructedSecret, StandardCharsets.UTF_8));
YourCode.doSomethingWith(secret);
}
catch (InvalidSharesException exc) {
// If the reconstruction fails, an InvalidSharesException is thrown.
System.out.println("Reconstructing the secret failed: " + exc.getMessage());
}
finally {
// Clear the secret from memory
if (secret != null) {
Arrays.fill(secret, (byte)0);
}
for (byte[] share : shares) {
Arrays.fill(share, (byte)0);
}
}
-
Download and install gcc and GNU Make (the make command).
Ubuntu:
sudo apt update && sudo apt install build-essential
macOS:
xcode-select --install
On Windows, you can use MinGW and GNU Make for Win32. If you use Chocolatey, you can install it using these commands:
# Run as Administrator: choco install mingw choco install make
-
Clone the project from GitHub with submodules:
git clone --recurse-submodules https://github.com/juliushardt/sss-java.git
-
Fix symlinks: If you use Windows and git is not configured to create symlinks correctly, you need to fix the broken symlinks in the sss submodule:
- By default, creating symbolic links requires administrative privileges. You can opt out of this by enabling developer mode on your machine. To do so, type Win+R, open
ms-settings:developers
and switch on "Developer Mode". - Open a PowerShell console and create the symbolic links:
cd \path\to\sss-java\ cd .\native\sss\ Remove-Item -Path randombytes.h Remove-Item -Path randombytes.c New-Item -ItemType SymbolicLink -Path randombytes.h -Target .\randombytes\randombytes.h New-Item -ItemType SymbolicLink -Path randombytes.c -Target .\randombytes\randombytes.c
- By default, creating symbolic links requires administrative privileges. You can opt out of this by enabling developer mode on your machine. To do so, type Win+R, open
-
Export an environment variable named
CC
which contains the path to your gcc binary:# Bash export CC="gcc"
# Powershell $env:CC="gcc"
-
Make sure that the environment variable
JAVA_HOME
is set and points to the JDK you want to use:# Bash # Check if JAVA_HOME is set: echo $JAVA_HOME # If JAVA_HOME is not set, update it. For example: export JAVA_HOME=/Library/Java/JavaVirtualMachines/zulu-8.jdk/Contents/Home
# Powershell # Check if JAVA_HOME is set: $env:JAVA_HOME # If JAVA_HOME is not set, update it. For example: $env:JAVA_HOME = "C:\Program Files\AdoptOpenJDK\jdk-8.0.222.10-hotspot\"
cd /path/to/sss-java
# Build the native wrapper library for your platform
cd native
make
cd ..
# Build the Java library
./gradlew build
On Windows, you may get an error like this while running make
:
process_begin: CreateProcess(NULL, uname -s, ...) failed.
Makefile:7: pipe: No error
This is because the makefile of sss tries to execute the command uname -s
, which does not exist on Windows. However, the build works anyway, so you can simply ignore the error. In the future, we should contribute proper Windows support back to sss and randombytes.