A Ruby gem for sharing secrets in an information-theoretically secure way.
It uses Shamir's secret sharing to enable sharing a (random) secret between n persons where k <= n shares are enough to recover the secret.
k-1 secret share holders learn nothing about the secret when they combine their shares.
Learn More about Shamir's Secret Sharing
This library is based on the OpenXPKI::Crypto::Secret::Split Perl module used in the open source PKI software OpenXPKI, which was written by Alexander Klink for the OpenXPKI project in 2006.
The original source code for Alexander Klink's 'secretsharing' gem can be found at http://repo.or.cz/w/secretsharing.git
It has been further enhanced, modularized, and a full test suite has been added by Glenn Rempe ([email protected]) and can be found at https://github.com/grempe/secretsharing which is the new canonical repository for the gem.
WARNING : The public API and the Share String format of the current version of the Gem are not backwards compatible with 'secretsharing' versions <= '0.3'.
This code has not yet been tested in production. It is seemingly well tested though with a full Minitest suite and 100% test code coverage and appears to be working well for what it was designed to do. The code also undergoes a continuous integration test run on many different Ruby runtimes upon every push.
The mathematics of the code, which is critical to its operation, and its suitability for use as a security product have not yet been tested or verified by security minded folks. Yet
. If you are one of those strongly mathematically or security minded folks please do get in touch if you think you can help validate the current implementation. Suggestions or concerns welcome.
Add this line to your application's Gemfile:
gem 'secretsharing'
And then execute:
$ bundle
Or install it yourself as:
$ gem install secretsharing
require 'secretsharing'
# create an object for 3 out of 5 secret sharing
c1 = SecretSharing::Shamir::Container.new(5,3)
# create a random secret (returns the secret)
c1.secret = SecretSharing::Shamir::Secret.new
# (or create a fixed secret of your choice by passing in an OpenSSL::BN object in the :secret arg)
c1.secret = SecretSharing::Shamir::Secret.new(:secret => OpenSSL::BN.new('123456789'))
# show secret
puts c1.secret
# show shares
c1.shares.each { |share| puts share }
# recover secret from shares by using a new Container
# where the number of Shares expected is the same.
c2 = SecretSharing::Shamir::Container.new(3)
# Accepts SecretSharing::Shamir::Share objects or
# string representations thereof
c2 << c1.shares[0]
c2 << c1.shares[2]
c2 << c1.shares[4]
c2.secret? #=> true
puts c2.secret
# Test that the secret used to generate the HMAC
# matches the HMAC of the secret that was re-constructed
c2.secret.valid_hmac? #=> true
First, use the secretsharing
program to generate a set of Shares from a Secret
➜ secretsharing git:(master) ✗ secretsharing
Shamir's Secret Sharing
Would you like to 'encode' a new secret as shares, or 'decode' one from existing shares?
1. encode
2. decode
Action? 1
Would you like to create a 'random' secret, or will you provide a 'fixed' one?
1. random
2. fixed
Type? 1
How many total shares (n) do you want to distribute? 5
How many of the total shares (k) are required to reveal the secret? 3
========================================
Encoded Secret:
(k) Value: 3
(n) Value: 5
Secret (Bignum):
179040077567401061920833455639501686558874997550289562553628622313673068089718
Secret (Base64 Compacted & URL Safe):
OXY1eHdod3N0NXJ1MWEzZXBuMjgxZnN1Y2Y4dXI1bWRyNG40dTl2Zmk1MG16OXM4emE=
Secret has valid_hmac?
true
Shares:
2gEqeyJobWFjIjoiMDVkNWNlOTIyNjk5ZTUxNzY4ODU2MmJlYjJiZDUzMTI4OTAyYTYzMjAxMjIxMjdjZTVhZjhlMmRiMmY2MmNkMiIsImsiOjMsIm4iOjUsInByaW1lIjozNzA1MzQ2ODU1NTk0MTE4MjUzNTU0MjcxNTIwMjc4MDEzMDUxMzA0NjM5NTA5MzAwNDk4MDQ5MjYyNjQyNjg4MjUzMjIwMTQ4NDc4MDU5LCJwcmltZV9iaXRsZW5ndGgiOjI2MSwidmVyc2lvbiI6MSwieCI6MSwieSI6OTE5NjU5ODE1Njg0MzAwODU5Mjg2OTU1ODMxMzg0NzA2NDQ1NTMyMzQxNDE5ODAyOTA5NzEwMDcxODU1MTgwMjUyMTYxMjk4Nzg0MzE2fQ==
2gEreyJobWFjIjoiMDVkNWNlOTIyNjk5ZTUxNzY4ODU2MmJlYjJiZDUzMTI4OTAyYTYzMjAxMjIxMjdjZTVhZjhlMmRiMmY2MmNkMiIsImsiOjMsIm4iOjUsInByaW1lIjozNzA1MzQ2ODU1NTk0MTE4MjUzNTU0MjcxNTIwMjc4MDEzMDUxMzA0NjM5NTA5MzAwNDk4MDQ5MjYyNjQyNjg4MjUzMjIwMTQ4NDc4MDU5LCJwcmltZV9iaXRsZW5ndGgiOjI2MSwidmVyc2lvbiI6MSwieCI6MiwieSI6MjI4MDcyMTc2NjA0NjUwODgwODE1ODY0MTc2ODQyOTY5NDkwODgyODY1OTY4Mzg4MzYyODAyNTE0NTI5MzI4NTE1NDI3Njg3NjM0ODkyNn0=
2gEqeyJobWFjIjoiMDVkNWNlOTIyNjk5ZTUxNzY4ODU2MmJlYjJiZDUzMTI4OTAyYTYzMjAxMjIxMjdjZTVhZjhlMmRiMmY2MmNkMiIsImsiOjMsIm4iOjUsInByaW1lIjozNzA1MzQ2ODU1NTk0MTE4MjUzNTU0MjcxNTIwMjc4MDEzMDUxMzA0NjM5NTA5MzAwNDk4MDQ5MjYyNjQyNjg4MjUzMjIwMTQ4NDc4MDU5LCJwcmltZV9iaXRsZW5ndGgiOjI2MSwidmVyc2lvbiI6MSwieCI6MywieSI6NTU2ODc5MDczMDU5OTA2NjU0OTgxNjE5NzQ2NDk2NDU0MDI1MTQzMTkwMjgwNDkxOTQ2NDU4NTExMzAwMjQ4NzY2Nzk5NjUyMzA1NDg5fQ==
2gEreyJobWFjIjoiMDVkNWNlOTIyNjk5ZTUxNzY4ODU2MmJlYjJiZDUzMTI4OTAyYTYzMjAxMjIxMjdjZTVhZjhlMmRiMmY2MmNkMiIsImsiOjMsIm4iOjUsInByaW1lIjozNzA1MzQ2ODU1NTk0MTE4MjUzNTU0MjcxNTIwMjc4MDEzMDUxMzA0NjM5NTA5MzAwNDk4MDQ5MjYyNjQyNjg4MjUzMjIwMTQ4NDc4MDU5LCJwcmltZV9iaXRsZW5ndGgiOjI2MSwidmVyc2lvbiI6MSwieCI6NCwieSI6MzE1ODgyNTQ0NzkxMjczMDkwNjg2NDQzMjgwNjE0MTAwOTg5NzA4NTIxMjIyODIyODg2MTEwODY5NTE2MTQ0NzU5NjE2OTkyMzYxMDEyM30=
2gEreyJobWFjIjoiMDVkNWNlOTIyNjk5ZTUxNzY4ODU2MmJlYjJiZDUzMTI4OTAyYTYzMjAxMjIxMjdjZTVhZjhlMmRiMmY2MmNkMiIsImsiOjMsIm4iOjUsInByaW1lIjozNzA1MzQ2ODU1NTk0MTE4MjUzNTU0MjcxNTIwMjc4MDEzMDUxMzA0NjM5NTA5MzAwNDk4MDQ5MjYyNjQyNjg4MjUzMjIwMTQ4NDc4MDU5LCJwcmltZV9iaXRsZW5ndGgiOjI2MSwidmVyc2lvbiI6MSwieCI6NSwieSI6MjY3NTg2NzE3OTQxNjc0NTA1NjY5ODUzNzkwNjgwNzMzNjQyMjA0NTQ0NjUwODQ5MzM3NTg3NzE3MTU5MTUwNTEzNTk0NzM5MzMwNjcxMH0=
========================================
➜ secretsharing git:(master) ✗
Once that is done you can re-hydrate your Secret using any 3 out of the 5 Shares originally generated:
➜ secretsharing git:(master) ✗ secretsharing
Shamir's Secret Sharing
Would you like to 'encode' a new secret as shares, or 'decode' one from existing shares?
1. encode
2. decode
Action? 2
How many of shares (k) are required to reveal this secret? 3
Enter the '3' shares one at a time with a RETURN after each:
2gEqeyJobWFjIjoiMDVkNWNlOTIyNjk5ZTUxNzY4ODU2MmJlYjJiZDUzMTI4OTAyYTYzMjAxMjIxMjdjZTVhZjhlMmRiMmY2MmNkMiIsImsiOjMsIm4iOjUsInByaW1lIjozNzA1MzQ2ODU1NTk0MTE4MjUzNTU0MjcxNTIwMjc4MDEzMDUxMzA0NjM5NTA5MzAwNDk4MDQ5MjYyNjQyNjg4MjUzMjIwMTQ4NDc4MDU5LCJwcmltZV9iaXRsZW5ndGgiOjI2MSwidmVyc2lvbiI6MSwieCI6MSwieSI6OTE5NjU5ODE1Njg0MzAwODU5Mjg2OTU1ODMxMzg0NzA2NDQ1NTMyMzQxNDE5ODAyOTA5NzEwMDcxODU1MTgwMjUyMTYxMjk4Nzg0MzE2fQ==
2gEreyJobWFjIjoiMDVkNWNlOTIyNjk5ZTUxNzY4ODU2MmJlYjJiZDUzMTI4OTAyYTYzMjAxMjIxMjdjZTVhZjhlMmRiMmY2MmNkMiIsImsiOjMsIm4iOjUsInByaW1lIjozNzA1MzQ2ODU1NTk0MTE4MjUzNTU0MjcxNTIwMjc4MDEzMDUxMzA0NjM5NTA5MzAwNDk4MDQ5MjYyNjQyNjg4MjUzMjIwMTQ4NDc4MDU5LCJwcmltZV9iaXRsZW5ndGgiOjI2MSwidmVyc2lvbiI6MSwieCI6MiwieSI6MjI4MDcyMTc2NjA0NjUwODgwODE1ODY0MTc2ODQyOTY5NDkwODgyODY1OTY4Mzg4MzYyODAyNTE0NTI5MzI4NTE1NDI3Njg3NjM0ODkyNn0=
2gEqeyJobWFjIjoiMDVkNWNlOTIyNjk5ZTUxNzY4ODU2MmJlYjJiZDUzMTI4OTAyYTYzMjAxMjIxMjdjZTVhZjhlMmRiMmY2MmNkMiIsImsiOjMsIm4iOjUsInByaW1lIjozNzA1MzQ2ODU1NTk0MTE4MjUzNTU0MjcxNTIwMjc4MDEzMDUxMzA0NjM5NTA5MzAwNDk4MDQ5MjYyNjQyNjg4MjUzMjIwMTQ4NDc4MDU5LCJwcmltZV9iaXRsZW5ndGgiOjI2MSwidmVyc2lvbiI6MSwieCI6MywieSI6NTU2ODc5MDczMDU5OTA2NjU0OTgxNjE5NzQ2NDk2NDU0MDI1MTQzMTkwMjgwNDkxOTQ2NDU4NTExMzAwMjQ4NzY2Nzk5NjUyMzA1NDg5fQ==
========================================
Decoded Secret:
(k) Value: 3
Secret (Bignum):
179040077567401061920833455639501686558874997550289562553628622313673068089718
Secret (Base64 Compacted & URL Safe):
OXY1eHdod3N0NXJ1MWEzZXBuMjgxZnN1Y2Y4dXI1bWRyNG40dTl2Zmk1MG16OXM4emE=
========================================
➜ secretsharing git:(master) ✗
Easy!
Install the gemfile dependencies:
bundle install
Run the test suite:
rake test
Or run the test suite continuously upon watched file changes:
bundle exec rerun -x rake test
Build and Install the gem to your local system from the cloned repository:
rake install
Run the secretsharing
binary without installing the Gem locally:
ruby -I./lib bin/secretsharing
We love bug reports and pull requests.
https://github.com/grempe/secretsharing/issues
This gem is tested after each git push to the master branch using the Travis CI automated build and test service against several versions of a the most popular Ruby runtimes (MRI 1.8.7, 1.9.3, 2.0.0, JRuby, REE, Rubinious). A build must be green on all of them to be considered for release.
A .travis.yml
file has been added to this project to define which Ruby versions will be tested. Additionally a gemfiles/Gemfile.ci
file has been created to specify a custom minimal Gemspec to be run on the test hosts. Contributors are not to modify these files.
Code quality and metrics over time are being monitored courtesy of Code Climate.
https://codeclimate.com/github/grempe/secretsharing
RuboCop is a Ruby static code analyzer. Out of the box it will enforce many of the guidelines outlined in the community Ruby Style Guide. A clean rubocop
run against all lib
and spec
code is necessary for a build to be considered for release.
A .rubocop.yml
file has been added to this project to define any style exceptions. Contributors are not to modify this file.
The COCO gem provides automatic test code coverage analysis for ruby 1.9.2, 1.9.3 and 2.0. It will be run every time rake test
is run. If there are any files that are not 100% covered an output report will be generated in coverage/index.html' and a summary line will be added at the end of the
rake test` output. It is expected that 100% test coverage will be maintained.
A .coco.yml
file has been added to this project to define any coverage exceptions. Contributors are not to modify this file.
This Gem, and its version number, tries its best to adhere to the 'Semantic Versioning' strategy espoused at : http://semver.org
IMPORTANT
Please do not change the VERSION number within your commits.
Please include tests that are passing 100% within your commits.
Please ensure that you maintain 100% test code coverage as reported by 'coco' which is run after every `rake test` automatically.
Please run the `rubocop` tool to ensure you are consistent with Ruby style guidelines for this project.
- Fork it
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request
(c) 2010-2014 Alexander Klink and Glenn Rempe
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the LICENSE.txt file for the specific language governing permissions and limitations under the License.
Alexander Klink
[email protected]
http://www.alech.de
@alech on Twitter
Glenn Rempe
[email protected]
http://www.rempe.us
@grempe on Twitter