Trivial secret sharing with authentication, support for M-of-N splits, and paper backups.
Project description
Triss
TRIvial Secret Sharing with authentication, support for M-of-N splits, and paper backups.
Triss is a command line tool used to split secrets into multiple shares and
recover them from split shares. Data is split such that no fewer than the
required number of shares reveal anything about the secret. Triss uses message
authentication codes (MACs) to ensure the recovered secret is identical to the
original input. It supports N-of-N and M-of-N splits, 2-of-2
or 3-of-5
for example. Formally:
Split a secret into N
shares, such that every subset of M
shares contains
the information needed to reconstruct the secret. N >= M
and M >= 2
. No
subset smaller than M
reveals any information about the secret, but see
cryptography below.
Triss supports two output modes: DATA
and QRCODE
. In DATA
mode, it writes
shares as plain binary files without any special encoding. In QRCODE
mode, it
generates QR codes as PNG images that can be printed onto paper.
It's pretty hard to reliably read QR codes from photos, unless they are of very high quality: sharp, high contrast, and not at all warped. Decoding from video is much easier, so triss supports that too using a webcam as a QR code scanner. Video input is probably more reliable because the decoder can make hundreds of attempts per scan, one for each frame of video.
Contents
Rationale
Use triss
to make encrypted backups without having to remember an encryption
key or password. Trivial secret sharing is handy when you want high confidence
your data will be recoverable far into the future: decryption is a
straightforward XOR of the shares, and easy to re-implement
from scratch should this software disappear or become unusable some day.
Say you split a secret into N = 3
shares, requiring M = 2
shares to recover
it. Give one share to your best friend, another to your lawyer, and keep the
third one. You trust your lawyer not to collude with your friend, and if you
ever need access to your secret, you can recover it as long as you can obtain 2
of the 3 shares. When you die, your friend and lawyer can discover what you've
been hiding all these years.
How it works
Trivial secret sharing is quite simple and works by combining the secret with a random number using the exclusive or (XOR) operation. This is the same idea as a stream cipher or one-time pad, depending on the source of the randomness.
For a 2-of-2 split:
- Represent your secret as a binary number
P
. - Generate a random number
K
of the same length asP
. - Combine
P
andK
to makeC = P xor K
. - Distribute
C
andK
as the 2 shares of the secret. - Recover the secret by combining them:
C xor K = P
.
Proof:
Given P your Plaintext data (the "secret")
Generate K, |K| = |P| a random Key, same length as P
C = P xor K produce Ciphertext by encrypting Plaintext with Key
C xor K = (P xor K) xor K xor Key on both sides
C xor K = P xor (K xor K) xor is associative
C xor K = P xor 0 simplify: K xor K = 0
C xor K = P simplify: P xor 0 = P. Recover Plaintext data.
For N of N
splits with more shares, generate additional keys K2
, K3
, etc
and XOR them all into P
to make C
. The shares are C
and all keys K
,
K2
, K3
, etc.
For M of N
splits where M < N
, make a separate M of M
split for each
of the $\binom{N}{M}$ subsets.
See also implementation details below.
Installation
Prerequisites
Triss requires python 3.11
or newer. There are no additional prerequisites for
DATA
file mode, but QRCODE
support depends on 3rd party libraries and
external programs.
Dependency | Type | Feature | Minimum Version | Released |
---|---|---|---|---|
python | 3.11 | 2022-10-24 | ||
pillow |
Python Library | QRCODE split | 10.4.0 | 2024-07-01 |
qrencode |
External Program | QRCODE split | 4.1.1 | 2020-09-28 |
zbarimg /zbarcam |
External Program | QRCODE combine | 0.23.1 | 2020-04-20 |
Note the minimum version of zbarimg
is a hard requirement, because support for
binary data was added in 0.23.1
. Older versions of qrencode
and pillow
may
work, but haven't been tested.
Python is available at https://www.python.org/downloads, and you may need to
install it manually. triss
and pillow
are installed by pip
, see
below, and external programs can be installed as follows:
Debian / Ubuntu
sudo apt install qrencode zbar-tools
Redhat / Fedora
sudo dnf install qrencode zbar
macOS
brew install qrencode zbar
Windows
qrencode
See https://fukuchi.org/works/qrencode/ or https://github.com/fukuchi/libqrencode.
zbarimg
Either download from https://linuxtv.org/downloads/zbar/binaries/ or to build from source, see https://github.com/mchehab/zbar.
triss
dist package
Install triss
itself, along with its python library dependencies.
The following steps usually happen in a python virtual environment. Set one up like this:
# E.g. in a bash shell:
$(command -v python3 || command -v python) -m venv venv
source venv/bin/activate
Direct pip install
Then either install triss
from PyPI
directly without verification:
pip install triss
Or install with verification
Or download, verify, and install:
# Download
pip download triss
# Import my gpg key
gpg --keyserver keyserver.ubuntu.com --recv-keys 219E9F62C560C55D2AFA44AEE970EC6EC2E57448
# Download SHA256SUMS and SHA256SUMS.asc
wget https://github.com/pdbrown/triss/releases/download/v2.4/SHA256SUMS
wget https://github.com/pdbrown/triss/releases/download/v2.4/SHA256SUMS.asc
# Verify the package
gpg --verify SHA256SUMS.asc
sha256sum --check --ignore-missing SHA256SUMS
# Install triss and its 3rd party dependency "pillow"
pip install *.whl
# Or, if you don't want to install pillow, you can install only the triss
# package. Triss will still be able to split and combine DATA in format, and
# combine from QRCODE inputs, but won't be able to produce new QRCODE outputs.
pip install triss-*.whl
Usage
The dist package installs the triss
wrapper script into the PATH of your venv.
Split secret
triss split [-h] [-k] [-c {DATA,QRCODE}] [-t SECRET_NAME] [-i IN_FILE] [-m M] N OUT_DIR
positional arguments:
N number of shares
OUT_DIR destination directory path
options:
-h, --help show this help message and exit
-k skip combine check after splitting
-c {DATA,QRCODE} output file format, defaults to DATA
-t SECRET_NAME name of secret to include on QRCODE images
-i IN_FILE path to input file, read from stdin if omitted
-m M number of required shares for M-of-N split, do N-of-N split if omitted
Recover secret
triss combine [-h] [--DANGER-invalid-ok] [-c {DATA,QRCODE}] [-s] [-o OUT_FILE] [DIR ...]
positional arguments:
DIR zero or more directories containing input files to combine
options:
-h, --help show this help message and exit
--DANGER-invalid-ok don't stop decoding on message authentication error. WARNING! There is no guarantee the decoded output matches the original input.
-c {DATA,QRCODE} input file format, will guess if omitted
-s scan QR codes using default video camera. Implies '-c QRCODE'.
-o OUT_FILE write secret to output file, or stdout if omitted
Identify share parts
Use triss identify
to show details of shares of a split secret without
revealing the secret. Also verify the integrity of any share parts for which the
MAC key is present.
triss identify [-h] [-c {DATA,QRCODE}] [-s] [DIR ...]
positional arguments:
DIR zero or more directories containing input files to identify
options:
-h, --help show this help message and exit
-c {DATA,QRCODE} input file format, will guess if omitted
-s scan QR codes using default video camera. Implies '-c QRCODE'.
Merge images
Use triss n_up
to merge multiple images into fewer, larger PNG images. The
idea is to tile multiple QRCODEs (from the same share, never mix shares!)
onto each page so you can print fewer pages. This does not decode or decrypt
anything.
triss n_up [-h] N IMAGE [IMAGE ...] OUTPUT_NAME
positional arguments:
N number of images per page of output
IMAGE one or more input image files
OUTPUT_NAME output image name, n_up adds page numbers and a .png suffix
options:
-h, --help show this help message and exit
Examples
Prepare a demo secret for the following examples.
echo "Hello there." > secret.txt
Split secret in DATA mode
Shares of the secret are stored in plain binary files. This handy when the secret is large and you don't care about making paper copies.
# Make 2-of-4 split
OUT_DIR=data-shares
M=2
N=4
triss split -i secret.txt -m "$M" "$N" "$OUT_DIR"
tree
# .
# ├── data-shares
# │ ├── share-0
# │ │ ├── share-0_part-1_of_6.dat
# │ │ ├── share-0_part-2_of_6.dat
# │ │ ├── share-0_part-3_of_6.dat
# │ │ ├── share-0_part-4_of_6.dat
# │ │ ├── share-0_part-5_of_6.dat
# │ │ └── share-0_part-6_of_6.dat
# │ ├── share-1
# │ │ ├── share-1_part-1_of_6.dat
# │ │ ├── share-1_part-2_of_6.dat
# │ │ ├── share-1_part-3_of_6.dat
# │ │ ├── share-1_part-4_of_6.dat
# │ │ ├── share-1_part-5_of_6.dat
# │ │ └── share-1_part-6_of_6.dat
# │ ├── share-2
# │ │ ├── share-2_part-1_of_6.dat
# │ │ ├── share-2_part-2_of_6.dat
# │ │ ├── share-2_part-3_of_6.dat
# │ │ ├── share-2_part-4_of_6.dat
# │ │ ├── share-2_part-5_of_6.dat
# │ │ └── share-2_part-6_of_6.dat
# │ └── share-3
# │ ├── share-3_part-1_of_6.dat
# │ ├── share-3_part-2_of_6.dat
# │ ├── share-3_part-3_of_6.dat
# │ ├── share-3_part-4_of_6.dat
# │ ├── share-3_part-5_of_6.dat
# │ └── share-3_part-6_of_6.dat
# └── secret.txt
Split secret in QRCODE mode
Shares of the secret are produced the same way as in DATA mode, then encoded as QR codes. This allows you to make paper copies, but can be slow and cumbersome for large inputs. Each QR code stores up to 1370 bytes.
# Make a 2-of-4 split in QRCODE mode.
triss split -i secret.txt -c QRCODE -t mysecret -m 2 4 qr-shares
# Stitch components of each output share into larger images
# (into a single 2x3 image for this example).
for share in $(find qr-shares -type d -name 'share-*'); do
triss n_up 6 "$share/"*.png "${share}-6up.png"
done
Recover secret
# Recover from any 2 shares.
triss combine -o output.txt data-shares/share-0 data-shares/share-3
# Recover from original QR code images.
triss combine -o output_qr.txt qr-shares/share-1 qr-shares/share-2
# Recover QR codes scanned by your webcam.
triss combine -o output_qrscanner.txt -s
# Recover from both QR images on disk and QR codes scanned by your webcam.
triss combine -o output_qr.txt -s shares/share-1
Distribute shares
Each share is in a separate subdirectory and consists of all files within it. Make sure you distribute complete shares with all their parts. If any part is missing, the share is useless.
For example: Make a 2-of-3 split
triss split -i input.txt -c DATA -m 2 3 shares
and give 3 participants, A, B, and C, one share each. Each participant must keep all 4 parts of their share.
Participant A gets all of:
share-0
├── share-0_part-1_of_4.dat
├── share-0_part-2_of_4.dat
├── share-0_part-3_of_4.dat
└── share-0_part-4_of_4.dat
Participant B gets all of:
share-1
├── share-1_part-1_of_4.dat
├── share-1_part-2_of_4.dat
├── share-1_part-3_of_4.dat
└── share-1_part-4_of_4.dat
Participant C gets all of:
share-2
├── share-2_part-1_of_4.dat
├── share-2_part-2_of_4.dat
├── share-2_part-3_of_4.dat
└── share-2_part-4_of_4.dat
Development
Install From Source
git clone https://github.com/pdbrown/triss && cd triss
# Enable development mode: Create venv at ./venv, install python dependencies,
# and create an "editable install".
make dev
# Activate venv
source venv/bin/activate
Test
The make test
recipe tests whatever package is currently installed. Install
either from local sources with make dev
, from a local dist package with make
, or
from PYPI with make upstream
, then run tests with:
make test
make stress
Build
Dist package
# Build dist package.
make
# Or build and sign it. The sign recipe invokes gpg and passes extra GPG_OPTS
# you can set on the commandline.
make sign
# or e.g.
make sign GPG_OPTS='--default-key me@example.com'
Note that make
and make sign
replace any "editable install" created by make dev
with a non-editable install. You need to re-run make dev
to switch back
to an "editable install".
Container image
Build an OCI image containing a signed dist of triss and its python, qrencode, and zbarimg dependencies. You can run it in a container or a chroot environment, but connecting to a host webcam from within a container can be tricky and is outside the scope of this guide.
# Build the container
make docker
# or if you use podman, do
make docker DOCKER=podman
To run the container with docker
, do:
# The container entrypoint is the triss cli, and the image contains an /app
# directory, so you can do:
echo "General Kenobi." > secret.txt
VERSION=$(awk -F\" '/^version/ { print $2 }' pyproject.toml)
docker run --rm -v .:/app triss:"$VERSION" \
triss split -i /app/secret.txt -c QRCODE -m 2 3 /app/shares
# And find the shares here:
find ./shares
Extract the root file system image for a chroot
environment or systemd-nspawn
container:
VERSION=$(awk -F\" '/^version/ { print $2 }' pyproject.toml)
docker create --name "triss_$VERSION" "triss:$VERSION"
docker export -o "triss_${VERSION}.tar" "triss_$VERSION"
mkdir rootfs
tar xf "triss_${VERSION}.tar" -C rootfs
Run a systemd-nspawn
container with:
echo "You are a bold one." > rootfs/app/input.dat
sudo systemd-nspawn --quiet --directory rootfs \
/venv/bin/triss split -i /app/input.dat -c QRCODE -m 2 3 /app/shares
# And find the shares here:
find rootfs/app/shares
Run triss
in a chroot environment (with access to a host webcam and display)
with:
sudo mount --rbind --make-rslave /dev rootfs/dev
sudo mount --rbind --make-rslave /run rootfs/run
sudo chroot rootfs /venv/bin/triss combine -c QRCODE -s \
/app/shares/share-0 /app/shares/share-1 \
> output.dat
sudo umount -R rootfs/dev rootfs/run
LiveCD bundle
A "LiveCD bundle" is the collection of packages needed to get triss
running on
a clean LiveCD system. The following example uses a Debian
LiveCD, but the method works for any LiveCD:
Download all required packages and dependencies onto a clean LiveCD system, then
save them for subsequent use with offline instances of the same system.
Create LiveCD Bundle
# Boot a Debian LiveCD image, see https://www.debian.org/CD/live/ (can use a VM
# for this step)
# 1) Make working directory
VERSION=2.4
mkdir "triss-v${VERSION}-livecd-bundle" &&
pushd "triss-v${VERSION}-livecd-bundle"
# 2) Install triss deps
sudo apt update
sudo apt install -y python3-venv qrencode zbar-tools
# 3) Then list installed and upgraded packages from last stanza in log with:
tac /var/log/apt/history.log |
sed -n '1,/^Start-Date:/p' |
grep -E 'Install|Upgrade' |
perl -p \
-e 's/\(.*?\)//g;' \
-e 's/^(Install|Upgrade): //;' \
-e 's/,/\n/g;' |
perl -p \
-e 's/:.*//g;' \
-e 's/ //g' \
> packages.txt
# 4) Fetch them
mkdir debs && pushd debs
apt-get download $(cat ../packages.txt)
# 5) Compute and sign checksums
sha256sum * > SHA256SUMS
gpg --detach-sign --armor SHA256SUMS
popd # out of debs
# 6) Create and activate a python virtual env
$(command -v python3 || command -v python) -m venv venv
source venv/bin/activate
# 7) Download and install triss
mkdir wheel && pushd wheel
pip download "triss==$VERSION"
gpg --keyserver keyserver.ubuntu.com --recv-keys 219E9F62C560C55D2AFA44AEE970EC6EC2E57448
curl -L -O https://github.com/pdbrown/triss/releases/download/v${VERSION}/SHA256SUMS
curl -L -O https://github.com/pdbrown/triss/releases/download/v${VERSION}/SHA256SUMS.asc
gpg --verify SHA256SUMS.asc
sha256sum --ignore-missing --check SHA256SUMS
# 8) Save the bundle to a DESTINATION directory
popd # out of wheel
deactivate # the venv
rm -r venv
popd # out of triss-v${VERSION}-livecd-bundle
tar czf "triss-v${VERSION}-livecd-bundle.tar.gz" \
"triss-v${VERSION}-livecd-bundle"
cp -r "triss-v${VERSION}-livecd-bundle.tar.gz" "$DESTINATION"
Use LiveCD Bundle
# Boot a Debian LiveCD image, see https://www.debian.org/CD/live/
# Obtain and extract the bundle
VERSION=2.4
tar xf "triss-v${VERSION}-livecd-bundle.tar.gz"
cd "triss-v${VERSION}-livecd-bundle"
# 1) Verify and install debs
pushd debs
gpg --verify SHA256SUMS.asc
sha256sum --ignore-missing --check SHA256SUMS
sudo dpkg -i *.deb
popd
# 2) Verify and install triss
$(command -v python3 || command -v python) -m venv venv
source venv/bin/activate
pushd wheel
gpg --verify SHA256SUMS.asc
sha256sum --ignore-missing --check SHA256SUMS
pip install *.whl
popd
# 3) Ready!
triss -h
Publish
Publish a dist package to PyPI with:
make publish
# Or to the test instance at test.pypi.org:
make publish PYPI=testpypi
And test it with:
make upstream
make test
Implementation Details
Important modules are:
triss.crypto
triss.codec
triss.codec.data_file
triss.codec.qrcode
And the entrypoint is in triss.cli which calls triss.core.
Fragments and Segments
When splitting a secret, triss
breaks input data into segments, then splits
each segment into encrypted fragments via trivial secret
sharing, and finally assigns fragments of segments to
shares, such that a share has a fragment of each segment.
A 3-of-3 split of 2 segments results in the following fragment-to-share assignment:
share 1:
- segment1_fragment1
- segment2_fragment1
share 2:
- segment1_fragment2
- segment2_fragment2
share 3:
- segment1_fragment3
- segment2_fragment3
To recover the secret, triss
combines the fragments of each segment, then
concatenates the segments in order to reproduce the original input.
M-of-N shared secrets
To make M-of-N
shared secrets, triss
performs $\binom{N}{M}$ M-of-M
splits. One such M
-way split is called an "authorized set", and the secret is
recoverable given all elements of any one authorized set. The elements are
bundled into N
shares, such that every subset of shares of size M
has
exactly one complete authorized set. For example, a 2-of-4
split requires
$\binom{4}{2} = 6$ authorized sets, any $2$ shares have one element each of the
same authorized set, and each share ends up with elements from $3$ different
authorized sets.
2 elements of each authorized set are assigned to 2 of 4 shares.
Authorized set: A B C D E F
share 1: A1 B1 C1
share 2: A2 D1 E1
share 3: B2 D2 F1
share 4: C2 E2 F2
In this example, each authorized set element is a fragment of the only segment of the input.
File format
When splitting a secret, triss
creates a top-level output directory with one
subdirectory per share, and multiple files per share subdirectory. Each output
file consists of a fixed size header followed by data. There are 2 output modes,
DATA
and QRCODE
. DATA
file size is unlimited, but QR codes have a
relatively low maximum capacity, so larger input is broken up into multiple
segments.
Header format
Headers are defined in the triss.header module.
The FragmentHeader
describes a file that contains a fragment of a split
segment of a secret. The header contains, among other things:
- An authorized set ID, used to identify which of the authorized sets the fragment belongs to.
- A fragment ID, used to differentiate fragments (elements of a single authorized set), and to determine whether an authorized set is complete, and thus can be combined to produce a decrypted result.
- A segment ID, used to position the decrypted result in the final output.
The MacHeader
describes a file that contains MACs (message authentication
codes) of fragments. It describes the MAC algorithm and key size, so triss
can
parse the file's payload into a key and MAC digests.
MAC payload layout
Consider an authorized set A
of 3 elements A1
, A2
, A3
, each of which
contains a fragment of 2 segments.
A1s0
means authorized set A
, fragment 1
, segment 0
. The 6 fragments are
assigned to 3 shares as follows:
share 0: A1s0, A1s1
share 1: A2s0, A2s1
share 2: A3s0, A3s1
Each share receives MAC digests of all fragments in segment-major order, but
note that each share only has the MAC key for its own fragments. A1_key
is the
MAC key for fragment A1
, used to compute the MAC digests for both segments
A1s0
and A1s1
: A1s0_MAC = MAC(A1_key, A1s0)
and A1s1_MAC = MAC(A1_key, A1s1)
. The payload consists of key bytes and digest bytes concatenated without
padding.
share 0: A1_key, A1s0_MAC, A2s0_MAC, A3s0_MAC, A1s1_MAC, A2s1_MAC, A3s1_MAC
share 1: A2_key, A1s0_MAC, A2s0_MAC, A3s0_MAC, A1s1_MAC, A2s1_MAC, A3s1_MAC
share 2: A3_key, A1s0_MAC, A2s0_MAC, A3s0_MAC, A1s1_MAC, A2s1_MAC, A3s1_MAC
^-- segment 0 ^-- segment 1
About
Motivation
There exist other tools that do secret sharing, so why build triss
?
- https://iancoleman.io/shamir/
- https://github.com/jesseduffield/horcrux
- http://point-at-infinity.org/ssss/
- https://github.com/cyphar/paperback
- ... and more
These all implement a form of Shamir's Secret
Sharing or similar. A
major advantage of Shamir's method is that the size of each share is linear in
the size of the secret, whereas trivial secret shares grow as
$O(\binom{N}{M})$ because they include a fragment of the secret from every
subset of N
elements of size M
.
While Shamir's secret sharing has its advantages, it's also harder to understand, and so it's harder to verify an implementation is correct.
Additionally, the secret sharing system should authenticate shares, since secret sharing is malleable: a flipped bit in the ciphertext (i.e. in any of the shares) leads to a flipped bit in the decoded plaintext. The system should also support digital and paper output formats.
So triss
:
- Is an implementation of trivial secret sharing: easy to use, understand, and reproduce.
- Tags shares of secrets with message authentication codes.
- Produces either data file or printable QR code output.
Cryptography
Randomness
Secret sharing schemes are often described as having information-theoretic
security aka
perfect secrecy, because an attacker with M-1
shares knows no more about the
secret than someone no shares at all. That is, even with knowledge of up to
M-1
of the shares, all secrets remain equally likely, and an attacker would
still be left guessing at random.
Perfect secrecy depends on the key being truly random, however. In this
case, the key is the K
as described above, but this key
is only pseudorandom, since it's generated by the operating system's
cryptographically secure pseudorandom number generator
(CSPRNG).
Instead of an infinite number of possible random key streams (sequences of
random 1s and 0s) there are "only" as many pseudorandom keystreams as can be
enumerated by the internal states of the CSPRNG. For example, recent versions of
linux use
a ChaCha based CSPRNG
with a 256 bit key size. Thus while there are no less than $2^{256}$ different key
streams, there are not infinitely many.
So given a triss
share C
, if an attacker attempts to brute force a key K
to
recover the plaintext with P = C xor K
, they can narrow their search from the
space of all possible keystreams to that of the no less than $2^{256}$ keystreams
generated by the CSPRNG.
While no longer perfect secrecy, this degree of security is good enough, computationally infeasible to crack, and on par with modern cryptography.
Footnotes
Triss uses python's secrets.token_bytes
method to generate keys. That calls
os.urandom
, which uses the getrandom(2)
system call in blocking mode on
linux (kernel version >= 3.17
).
On linux, see also man 7 random
, man 2 getrandom
, and the legacy random
device interface manual at man 4 random
.
Authentication
Malleablility
A problem with trivial secret sharing is that it does nothing to authenticate messages. An attacker or dishonest participant can corrupt their share such that the combined result no longer matches the original input. Even worse, trivial secret sharing is malleable, which means an attacker can alter the reconstructed output in a predictable way. Flipping any bit of an encrypted share causes the corresponding bit of the combined result to become flipped too. This can be disastrous if the secret is an instruction (or a file or computer program with a predictable format). Say a dishonest participant knows a message is either "attack" or "defend". They can corrupt their share such that the combined result always becomes the opposite of the original input, without ever knowing the original input in the first place.
# Demonstrate 2-of-2 trivial secret split malleability. In a python shell, do:
import secrets
def xor(xs, ys):
return bytes(x ^ y for x, y in zip(xs, ys))
# Split secret
plaintext = b"attack"
share_1 = secrets.token_bytes(len(plaintext)) # give to honest participant
share_2 = xor(plaintext, share_1) # give to dishonest participant
# Corrupt share
corruption = xor(b"attack", b"defend")
share_2_corrupted = xor(share_2, corruption)
# Attempt recovery of secret
xor(share_1, share_2_corrupted)
# => b"defend"
And if the original input had been b"defend"
, the recovered data would become
b"attack"
instead.
Message authentication codes
Triss uses HMAC-SHA-384 hash-based message authentication codes (MACs) to validate the authenticity of shares in an encrypt then mac fashion as follows.
For each share i
of the split (encrypted) secret:
- Generate a random 384 bit key
Ki
and - Given its split (encrypted) data
Si
, - Compute a
MACi = HMAC-SHA-384(Si, Ki)
Then include with each share the MACs of all shares. Also give each share its
own key Ki
, but no keys of any other share. When combining, reveal data and
keys of all shares, recompute MACs of each share, and verify they match the
original MACs distributed with your share.
It may seem unnecessary to use HMACs: wouldn't plain (secure) hash functions, say SHA384, suffice? While a hash digest proves authenticity, it also allows an attacker, another participant in this case, to guess your share by brute force. They enumerate and test all bit strings until they find a matching digest and thus your share. This is quite easy for a short secret, say a password or PIN number. By using a keyed hash function like HMAC, the attacker must also guess your (384 bit) key which is computationally infeasible.
Encryption vs Trivial Secret Sharing
Another way to do 2-of-2 trivial secret sharing is to use standard symmetric encryption (ChaCha20 or AES256 for example):
To split the secret:
- Generate a random key
k
, at least 256 bits long. - Encrypt the plaintext with
k
to produce ciphertextc
. - Distribute
k
andc
as the 2 shares.
To combine the shares:
- Decrypt
c
withk
to recover the input.
To extend to 3-of-3 secret sharing, encrypt the first key k
with another key
k2
to produce ciphertext c2
, and distribute k2
, c2
, and the original
input's ciphertext c
.
Advantages of symmetric encryption
Possible space savings. With triss
, each share is the same size as the
original input. With symmetric encryption only the ciphertext c
is, while the
other shares have a fixed size, typically 256-512 bits depending on the chosen
key size.
Advantages of triss
Decryption is simpler, an XOR of the shares vs a more complicated symmetric decryption process.
Comparison of security properties: ChaCha-20 vs triss
on linux
Consider ChaCha20, a modern stream cipher and symmetric encryption algorithm. It generates a pseudorandom keystream from a 256 bit key and other fixed size input, then XORs that stream with the plaintext to produce ciphertext.
And consider triss
running on linux, for which shares of the secret are
generated by a ChaCha based CSPRNG. The shares resemble keystreams as generated
by ChaCha20, see also randomness above. Then triss
does the
XORing of plaintext with keystream shares to produce the final ciphertext share.
If we assume the linux CSPRNG keystream is as secure as ChaCha20's, then then we
can assume triss
is as secure as a ChaCha20 based symmetric encryption secret
sharing scheme. The essential difference is that triss
saves the entire
keystreams (the CSPRNG outputs) instead of just the 256 bit keys.
In this context, "secure" means that it is computationally infeasible for an attacker with partial knowledge of the keystream to determine more of it.
License
GNU General Public License v3.0 or later
See COPYING for the full text.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file triss-2.4.tar.gz
.
File metadata
- Download URL: triss-2.4.tar.gz
- Upload date:
- Size: 73.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.0.1 CPython/3.12.3
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 |
75c9d6e9153af9941fc7eb176ebfb8526b7f643a77499d66b577d395c63cdfb5
|
|
MD5 |
8741f677a24ff68daf3ab0b8b1ae9cb6
|
|
BLAKE2b-256 |
27d2621734162b95ef5e78519216b951853b7d4494ebfa53e58d9aa0288df8a1
|
File details
Details for the file triss-2.4-py3-none-any.whl
.
File metadata
- Download URL: triss-2.4-py3-none-any.whl
- Upload date:
- Size: 57.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.0.1 CPython/3.12.3
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 |
7ac83588439f6abe1c87be0d45753acbdea2a9ed96a30decac7016c11865cb0a
|
|
MD5 |
37e698d37df3d1855bdcb57da4f2e54a
|
|
BLAKE2b-256 |
85e0e3898090bbe908d1e65b13d9950f4641183cadb7b18dfd2a948e7c640e12
|