tss 0.4.2 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.rubocop.yml +1 -1
- data/.ruby-version +1 -1
- data/.travis.yml +1 -0
- data/CHANGELOG.md +8 -0
- data/README.md +70 -99
- data/lib/custom_contracts.rb +3 -4
- data/lib/tss/cli_combine.rb +8 -1
- data/lib/tss/cli_split.rb +14 -13
- data/lib/tss/combiner.rb +9 -14
- data/lib/tss/splitter.rb +18 -14
- data/lib/tss/tss.rb +14 -15
- data/lib/tss/util.rb +33 -11
- data/lib/tss/version.rb +1 -1
- data/tss.gemspec +3 -1
- metadata +7 -6
- metadata.gz.sig +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3597bdbe0559f746e7f6b44c9e15b493cf48d92e
|
4
|
+
data.tar.gz: b049be29b2c0f1a1360e3114133f0524ad361562
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 37dc3d8473236a57165d3e12c2accd5e66b9dd769ad80c6e401f73e261227ac3b3db93749f3188878a77b65512fc3d011384f4e07f37f177e13490a41ab5bd28
|
7
|
+
data.tar.gz: 3a6842d643b9ccb6121bcef80d15453ae26a5ea3fd8db926d9d1a0384008e7089dd5ed232ecc2bc4df74b18c5fc6e2b460a4b9fca85f1421ad27a3c046d555d3
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
Binary file
|
data/.rubocop.yml
CHANGED
@@ -743,7 +743,7 @@ Style/LineEndConcatenation:
|
|
743
743
|
line end.
|
744
744
|
Enabled: false
|
745
745
|
|
746
|
-
Style/
|
746
|
+
Style/MethodCallWithoutArgsParentheses:
|
747
747
|
Description: 'Do not use parentheses for method calls with no arguments.'
|
748
748
|
StyleGuide: 'https://github.com/bbatsov/ruby-style-guide#no-args-no-parens'
|
749
749
|
Enabled: false
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.4.0
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
## v0.5.0 (1/28/2017)
|
4
|
+
|
5
|
+
* Breaking refactor to use automatic PKCS#7 padding on secrets w/ 16 byte block size.
|
6
|
+
* Update Copyright year
|
7
|
+
* Ruby 2.4.0 testing
|
8
|
+
* Update version of sysrandom gem
|
9
|
+
* Fixed minitest spec warning
|
10
|
+
|
3
11
|
## v0.4.2 (10/12/2016)
|
4
12
|
|
5
13
|
* Sign the gem with a new cert that expires in 10 years.
|
data/README.md
CHANGED
@@ -74,29 +74,29 @@ secret unicode characters ½ ♥ 💩
|
|
74
74
|
|
75
75
|
```ruby
|
76
76
|
$ bundle exec bin/console
|
77
|
-
|
77
|
+
> require 'tss'
|
78
78
|
=> false
|
79
|
-
|
80
|
-
=> ["tss~v1~
|
81
|
-
"tss~v1~
|
82
|
-
"tss~v1~
|
83
|
-
"tss~v1~
|
84
|
-
"tss~v1~
|
85
|
-
|
79
|
+
> shares = TSS.split(secret: 'my deep dark secret')
|
80
|
+
=> ["tss~v1~506168fade769236~3~NTA2MTY4ZmFkZTc2OTIzNgIDAEEBIM39jPGXFz4zKCObWgp2zQmCuUx92-VUf48FWQFqnLF3bw6VtVjYK7JRfESZIREdzhWcQuTQVuGKazxWRK27Tg==",
|
81
|
+
"tss~v1~506168fade769236~3~NTA2MTY4ZmFkZTc2OTIzNgIDAEEC1E8YyDhp5NeZvF6vHeUT6HoiU0AgoF69jyjNRbtcIi1YoymJTau1rJP-3nQXOofaB2LgnAhJpbB8vrID9WTKgQ==",
|
82
|
+
"tss~v1~506168fade769236~3~NTA2MTY4ZmFkZTc2OTIzNgIDAEEDmfvFIKybg8nO9Q9fZ5wARgHFngFQdrbk_arFEbc7s5HedTjzkoZYLlV8xnywt4AVAHAO0nSLY3C7iJPifH5VYA==",
|
83
|
+
"tss~v1~506168fade769236~3~NTA2MTY4ZmFkZTc2OTIzNgIDAEEEiBoCoHycMNTS5yQEU8_Sc7eVlIZOJP1-ka_7MPTlC1p2DyNdGvQxy3pBFZyH8WXAY9ICBxiZRDCJisFrebviAg==",
|
84
|
+
"tss~v1~506168fade769236~3~NTA2MTY4ZmFkZTc2OTIzNgIDAEEFxa7fSOhuV8qFrnX0KbbB3cxyWcc-8hUn4y3zZPiCmubw2TInxdncSbzDDZQgfGIPZMDsSWRbgvBOvOCK8KF94w=="]
|
85
|
+
> secret = TSS.combine(shares: shares)
|
86
86
|
=> {:hash=>"f1b91fef6a7535a974d3644c3eac16d2c907720c981290214d5d1db7cdb724af",
|
87
87
|
:hash_alg=>"SHA256",
|
88
|
-
:identifier=>"
|
89
|
-
:process_time=>0.
|
88
|
+
:identifier=>"506168fade769236",
|
89
|
+
:process_time=>0.94,
|
90
90
|
:secret=>"my deep dark secret",
|
91
91
|
:threshold=>3}
|
92
|
-
|
92
|
+
> puts secret[:secret]
|
93
93
|
my deep dark secret
|
94
94
|
=> nil
|
95
95
|
```
|
96
96
|
|
97
97
|
## Is it any good?
|
98
98
|
|
99
|
-
While this implementation has not had a formal security review, the cryptographic
|
99
|
+
While this implementation has not yet had a formal security review, the cryptographic
|
100
100
|
underpinnings were carefully specified in an IETF draft document authored by a
|
101
101
|
noted cryptographer. I have reached out to individuals respected in the field
|
102
102
|
for their work in implementing cryptographic solutions to help review this code.
|
@@ -128,13 +128,14 @@ nothing to slow down an attacker if they have access to enough shares.
|
|
128
128
|
|
129
129
|
* If you send keys by email, or some other insecure channel, then your email
|
130
130
|
provider, or any entity with access to their data, now also has the keys to
|
131
|
-
your data. They just need to collect enough keys to meet the threshold.
|
131
|
+
your data. They just need to collect enough keys to meet the threshold. Sending
|
132
|
+
enough shares to recreate a secret through any single provider offers no
|
133
|
+
more security than sending the key itself.
|
132
134
|
|
133
135
|
* Use public key cryptography to encrypt secret shares with the public key of
|
134
136
|
each individual recipient. This can protect the share data from unwanted use while
|
135
|
-
in transit or at rest.
|
136
|
-
|
137
|
-
or [TweetNaCl.js](https://github.com/dchest/tweetnacl-js).
|
137
|
+
in transit or at rest. OpenPGP would be one such tool for encrypting shares to
|
138
|
+
send safely.
|
138
139
|
|
139
140
|
* Put careful thought into how you want to distribute shares. It often makes
|
140
141
|
sense to give individuals more than one share.
|
@@ -144,15 +145,10 @@ sense to give individuals more than one share.
|
|
144
145
|
There is pretty extensive inline documentation. You can view the latest
|
145
146
|
auto-generated docs at [http://www.rubydoc.info/gems/tss](http://www.rubydoc.info/gems/tss)
|
146
147
|
|
147
|
-
## Supported
|
148
|
+
## Supported Ruby Versions
|
148
149
|
|
149
|
-
TSS is continuously integration tested on
|
150
|
-
|
151
|
-
* MRI 2.2.5
|
152
|
-
* MRI 2.3.1
|
153
|
-
* jruby-9.0.5.0
|
154
|
-
|
155
|
-
It may work on others as well.
|
150
|
+
TSS is continuously integration tested on a number of Ruby versions. See the file
|
151
|
+
`.travis.yml` in the root of this repository for the currently tested versions.
|
156
152
|
|
157
153
|
## Installation
|
158
154
|
|
@@ -261,12 +257,14 @@ cautioned that storing the secret on a filesystem may expose you to certain
|
|
261
257
|
attacks since it can be hard to fully erase files once written.
|
262
258
|
|
263
259
|
```text
|
260
|
+
$ cat /tmp/secret.txt
|
261
|
+
my secret
|
264
262
|
$ tss split -I /tmp/secret.txt
|
265
|
-
tss~v1~
|
266
|
-
tss~v1~
|
267
|
-
tss~v1~
|
268
|
-
tss~v1~
|
269
|
-
tss~v1~
|
263
|
+
tss~v1~8b66eb89ee25a46c~3~OGI2NmViODllZTI1YTQ2YwIDACsBqgQvwFhKboLMAmYwF5_CvaUwM8pmqUipbMRzakdbP53WJa-E6tf2nl2M
|
264
|
+
tss~v1~8b66eb89ee25a46c~3~OGI2NmViODllZTI1YTQ2YwIDACsCk1EU-HwvC6pjvQ5wDas221Qs4A7TtJNpi-Su8hxOqrsCSQ8t11aiQUpm
|
265
|
+
tss~v1~8b66eb89ee25a46c~3~OGI2NmViODllZTI1YTQ2YwIDACsDVCwbS0EGF03btYwqqVuk7S0z-nSinHtPpsFaFm5dys85j3JlK-yCVNyP
|
266
|
+
tss~v1~8b66eb89ee25a46c~3~OGI2NmViODllZTI1YTQ2YwIDACsEPUzgi8CDn4ix1dLQTQDj2yTdeeQcZAvGuMyQ_H7EepN6WO_KB1DuqTxm
|
267
|
+
tss~v1~8b66eb89ee25a46c~3~OGI2NmViODllZTI1YTQ2YwIDACsF-jHvOP2qg28J3VCK6fBx7V3CY55tTOPglelkGAzXGudBnpKC--rOvKqP
|
270
268
|
```
|
271
269
|
|
272
270
|
**Example : `interactive`**
|
@@ -282,11 +280,11 @@ Enter your secret, enter a dot (.) on a line by itself to finish :
|
|
282
280
|
secret > the vault password is:
|
283
281
|
secret > V0ulT!
|
284
282
|
secret > .
|
285
|
-
tss~v1~
|
286
|
-
tss~v1~
|
287
|
-
tss~v1~
|
288
|
-
tss~v1~
|
289
|
-
tss~v1~
|
283
|
+
tss~v1~1f8532a9d185efc4~3~MWY4NTMyYTlkMTg1ZWZjNAIDAD8BJkMvkHUGPQk1HQr_jVj9JkhavJVkdeFDEtRAf8O6vjksCjMMjiyuUL0bOD7vDnmdrzHK8QVymXU5vnjAREs=
|
284
|
+
tss~v1~1f8532a9d185efc4~3~MWY4NTMyYTlkMTg1ZWZjNAIDAD8CJpiKCEtSfmugr_gbvEIBs2M2sZfHxuZsBuPpB35OGeyWmGZCyJCNu0W2z3abkV1Q8uTPvT75YYRpw6BcdvQ=
|
285
|
+
tss~v1~1f8532a9d185efc4~3~MWY4NTMyYTlkMTg1ZWZjNAIDAD8DdLPAuEg1Ng7hkoKFQmmL-lkILWvQiQ15JELFLJz-PvdZucDCqS-X6QAIbwWE3u2XrTgsH1kmIvpMeZhzfPk=
|
286
|
+
tss~v1~1f8532a9d185efc4~3~MWY4NTMyYTlkMTg1ZWZjNAIDAD8EJT1XJ-DeOXuE3JD6VpZk79945_peSk1ij1Mk5ql-l2jkv85yGBbyH0VIBmJp2WsEMmESZqTsQ9kKB-0Ljq8=
|
287
|
+
tss~v1~1f8532a9d185efc4~3~MWY4NTMyYTlkMTg1ZWZjNAIDAD8FdxYdl-O5cR7F4epkqL3upuVGewZJBaZ3rfIIzUvOsHMrnmjyeanoTQD2phF2ltvDbb3xxMMzAKcvvdUkhKI=
|
290
288
|
```
|
291
289
|
|
292
290
|
### CLI Share Combining
|
@@ -339,29 +337,29 @@ a secret
|
|
339
337
|
```text
|
340
338
|
$ cat /tmp/shares.txt
|
341
339
|
# THRESHOLD SECRET SHARING SHARES
|
342
|
-
#
|
340
|
+
# 2017-01-29T02:01:00Z
|
343
341
|
# https://github.com/grempe/tss-rb
|
344
342
|
|
345
343
|
|
346
|
-
tss~v1~
|
347
|
-
tss~v1~
|
348
|
-
tss~v1~
|
349
|
-
tss~v1~
|
350
|
-
tss~v1~
|
344
|
+
tss~v1~b9f7f87bc83fd89b~3~YjlmN2Y4N2JjODNmZDg5YgIDACoBbga2N__A9QOleLhC5R5b7stJ26iMPNpQ95YpmK-tWIrd-CYcrXGmcys=
|
345
|
+
tss~v1~b9f7f87bc83fd89b~3~YjlmN2Y4N2JjODNmZDg5YgIDACoCGXsZkLOG7uDOVN1Zn46pqftX4noA8LfXugg14KBfSggYP9fw4Ce10YA=
|
346
|
+
tss~v1~b9f7f87bc83fd89b~3~YjlmN2Y4N2JjODNmZDg5YgIDACoDFl3cwi80fpdh-I9eK3kNa8V9OlXX1Wx8y5a6bk2S0TDJzocr-1C3TWs=
|
347
|
+
tss~v1~b9f7f87bc83fd89b~3~YjlmN2Y4N2JjODNmZDg5YgIDACoEEspmyzmbnrSr7v41FFlHVTqQ6dx4aho8q5T1CBHQbNimdCv3gVXS50I=
|
348
|
+
tss~v1~b9f7f87bc83fd89b~3~YjlmN2Y4N2JjODNmZDg5YgIDACoFHeyjmaUpDsMEQqwyoK7jlwS6MfOvT8GX2gp6hvwd9-B3hXssmiLQe6k=
|
351
349
|
|
352
350
|
$ tss combine
|
353
351
|
Enter shares, one per line, and a dot (.) on a line by itself to finish :
|
354
|
-
share> tss~v1~
|
355
|
-
share> tss~v1~
|
356
|
-
share> tss~v1~
|
352
|
+
share> tss~v1~b9f7f87bc83fd89b~3~YjlmN2Y4N2JjODNmZDg5YgIDACoBbga2N__A9QOleLhC5R5b7stJ26iMPNpQ95YpmK-tWIrd-CYcrXGmcys=
|
353
|
+
share> tss~v1~b9f7f87bc83fd89b~3~YjlmN2Y4N2JjODNmZDg5YgIDACoCGXsZkLOG7uDOVN1Zn46pqftX4noA8LfXugg14KBfSggYP9fw4Ce10YA=
|
354
|
+
share> tss~v1~b9f7f87bc83fd89b~3~YjlmN2Y4N2JjODNmZDg5YgIDACoDFl3cwi80fpdh-I9eK3kNa8V9OlXX1Wx8y5a6bk2S0TDJzocr-1C3TWs=
|
357
355
|
share> .
|
358
356
|
|
359
357
|
RECOVERED SECRET METADATA
|
360
358
|
*************************
|
361
359
|
hash : d4ea4551e9ff2cf56303875b1901fb8608a6164260c3b20c0976c7b606a4efc0
|
362
360
|
hash_alg : SHA256
|
363
|
-
identifier :
|
364
|
-
process_time :
|
361
|
+
identifier : b9f7f87bc83fd89b
|
362
|
+
process_time : 1.22ms
|
365
363
|
threshold : 3
|
366
364
|
secret :
|
367
365
|
a secret
|
@@ -373,11 +371,11 @@ The basic usage is as follows using the arguments described below.
|
|
373
371
|
|
374
372
|
```ruby
|
375
373
|
shares = TSS.split(secret: secret,
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
374
|
+
threshold: threshold,
|
375
|
+
num_shares: num_shares,
|
376
|
+
identifier: identifier,
|
377
|
+
hash_alg: hash_alg,
|
378
|
+
padding: true)
|
381
379
|
```
|
382
380
|
|
383
381
|
### Arguments
|
@@ -385,7 +383,7 @@ shares = TSS.split(secret: secret,
|
|
385
383
|
All arguments are passed as keys in a single Hash.
|
386
384
|
|
387
385
|
The `secret` (required) value must be provided as a String with either
|
388
|
-
a `UTF-8` or `US-ASCII` encoding. The Byte length must be `<= 65,
|
386
|
+
a `UTF-8` or `US-ASCII` encoding. The Byte length must be `<= 65,486`. You can
|
389
387
|
test this beforehand with `'my string secret'.bytes.to_a.length`. Keep in mind
|
390
388
|
that this length also includes padding and the verification hash so your
|
391
389
|
secret may need to be shorter depending on the settings you choose.
|
@@ -426,44 +424,17 @@ The `HUMAN` format can be easily shared in a tweet, email, or even a URL. The
|
|
426
424
|
easier to visually compare shares and see if they have matching identifiers and
|
427
425
|
if you have enough shares to reach the threshold.
|
428
426
|
|
429
|
-
The `
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
`pad_blocksize` defaults to no padding (0). For example:
|
435
|
-
|
436
|
-
```ruby
|
437
|
-
padding_blocksize: 8
|
438
|
-
(padded with zeros for illustration purposes)
|
439
|
-
|
440
|
-
# a single char, padded up to 8
|
441
|
-
'a' -> "0000000a"
|
442
|
-
|
443
|
-
# 8 chars, no padding needed to get to 8
|
444
|
-
'aaaaaaaa' -> "aaaaaaaa"
|
445
|
-
|
446
|
-
# 9 chars, bumps blocksize up to 16 and pads
|
447
|
-
'aaaaaaaaa' -> "0000000aaaaaaaaa"
|
448
|
-
```
|
427
|
+
The `padding` arg accepts a Boolean to indicate whether to apply PKCS#7
|
428
|
+
padding to the secret string. This is applied and removed automatically
|
429
|
+
by default and padding defaults to a block size of 16 bytes. You probably
|
430
|
+
never need to use this option to turn it off unless you are trying to
|
431
|
+
trade shares with the Python implementation.
|
449
432
|
|
450
433
|
Since TSS share data is essentially the same size as the original secret
|
451
|
-
(with a known size header), padding smaller secrets may help
|
452
|
-
of the secret itself from an attacker. Padding is not part of
|
453
|
-
so other TSS clients won't strip off the padding and may fail
|
454
|
-
shares.
|
455
|
-
the `pad_blocksize` padding and just pad the secret yourself prior to splitting
|
456
|
-
it. You need to pad using a character other than `"\u001F"`.
|
457
|
-
|
458
|
-
If you want to do padding this way, there is a utility method you can use
|
459
|
-
to do that. This is the same method used internally.
|
460
|
-
|
461
|
-
```ruby
|
462
|
-
# Util.left_pad(byte_multiple, input_string, pad_char = "\u001F")
|
463
|
-
|
464
|
-
> Util.left_pad(16, 'abc', "0")
|
465
|
-
=> "0000000000000abc"
|
466
|
-
```
|
434
|
+
(with a known size header), the padding applied to smaller secrets may help
|
435
|
+
mask the exact size of the secret itself from an attacker. Padding is not part of
|
436
|
+
the RTSS spec so other TSS clients won't strip off the padding and may fail
|
437
|
+
when recombining shares.
|
467
438
|
|
468
439
|
### Example Usage
|
469
440
|
|
@@ -475,20 +446,20 @@ identifier = SecureRandom.hex(8)
|
|
475
446
|
hash_alg = 'SHA256'
|
476
447
|
format = 'HUMAN'
|
477
448
|
|
478
|
-
s = TSS.split(secret: secret, threshold: threshold, num_shares: num_shares, identifier: identifier, hash_alg: 'SHA256',
|
449
|
+
s = TSS.split(secret: secret, threshold: threshold, num_shares: num_shares, identifier: identifier, hash_alg: 'SHA256', format: format)
|
479
450
|
|
480
|
-
=> ["tss~v1~
|
481
|
-
"tss~v1~
|
482
|
-
"tss~v1~
|
483
|
-
"tss~v1~
|
484
|
-
"tss~v1~
|
451
|
+
=> ["tss~v1~79923b087dab7fa2~3~Nzk5MjNiMDg3ZGFiN2ZhMgIDADEB2qA6IYq8yOGlPAl0B4MgRsVazZMWGLwRNgGMPKutOYbB0gjkVHNqbNYl-0l1f98W",
|
452
|
+
"tss~v1~79923b087dab7fa2~3~Nzk5MjNiMDg3ZGFiN2ZhMgIDADECvjwdUHc8MzqvIllR2Rj9TnnlN_2eRUzH6MUsd8ncua4jpXQ3FgM1hUmLHmrgHq0u",
|
453
|
+
"tss~v1~79923b087dab7fa2~3~Nzk5MjNiMDg3ZGFiN2ZhMgIDADEDAvNIUZ_hiftofyog257YDWds4q9MP14-rDCxQsauUyxqBtzur6Ch5-rSCHRPt4Dv",
|
454
|
+
"tss~v1~79923b087dab7fa2~3~Nzk5MjNiMDg3ZGFiN2ZhMgIDADEEF7zGEx0GSC6YLgVD6xcQispDCO_JTUSDFbsbpalopakh0FmTfmO-JJKGQSlJb1il",
|
455
|
+
"tss~v1~79923b087dab7fa2~3~Nzk5MjNiMDg3ZGFiN2ZhMgIDADEFq3OTEvXb8u9fc3Yy6ZE1ydTK3b0bN1Z6UU6GkKYaTytoc_FKx8AqRjHfVzfmxnVk"]
|
485
456
|
|
486
|
-
|
457
|
+
secret = TSS.combine(shares: s)
|
487
458
|
|
488
|
-
|
459
|
+
=> {:hash=>"dbd318c1c462aee872f41109a4dfd3048871a03dedd0fe0e757ced57dad6f2d7",
|
489
460
|
:hash_alg=>"SHA256",
|
490
|
-
:identifier=>"
|
491
|
-
:process_time=>0.
|
461
|
+
:identifier=>"79923b087dab7fa2",
|
462
|
+
:process_time=>0.92,
|
492
463
|
:secret=>"foo bar baz",
|
493
464
|
:threshold=>3}
|
494
465
|
```
|
@@ -558,7 +529,7 @@ many combinations (`2.88 * 10^75`) as there are Atoms in the Universe (`10^80`).
|
|
558
529
|
If the combine operation does not result in a secret being successfully
|
559
530
|
extracted, then a `TSS::Error` exception will be raised.
|
560
531
|
|
561
|
-
A great short read on
|
532
|
+
A great short read on big numbers is
|
562
533
|
[On the (Small) Number of Atoms in the Universe](http://norvig.com/atoms.html)
|
563
534
|
|
564
535
|
### Exception Handling
|
@@ -702,7 +673,7 @@ contributors are expected to adhere to the
|
|
702
673
|
|
703
674
|
### Copyright
|
704
675
|
|
705
|
-
(c) 2016 Glenn Rempe <[glenn@rempe.us](mailto:glenn@rempe.us)> ([https://www.rempe.us/](https://www.rempe.us/))
|
676
|
+
(c) 2016-2017 Glenn Rempe <[glenn@rempe.us](mailto:glenn@rempe.us)> ([https://www.rempe.us/](https://www.rempe.us/))
|
706
677
|
|
707
678
|
### License
|
708
679
|
|
data/lib/custom_contracts.rb
CHANGED
@@ -18,13 +18,12 @@ module Contracts
|
|
18
18
|
class SecretArg
|
19
19
|
def self.valid? val
|
20
20
|
val.is_a?(String) &&
|
21
|
-
val.length.between?(1,
|
22
|
-
['UTF-8', 'US-ASCII'].include?(val.encoding.name)
|
23
|
-
val.slice(0) != "\u001F"
|
21
|
+
val.length.between?(1,TSS::MAX_UNPADDED_SECRET_SIZE) &&
|
22
|
+
['UTF-8', 'US-ASCII'].include?(val.encoding.name)
|
24
23
|
end
|
25
24
|
|
26
25
|
def self.to_s
|
27
|
-
|
26
|
+
"must be a UTF-8 or US-ASCII String between 1 and #{TSS::MAX_UNPADDED_SECRET_SIZE} characters in length"
|
28
27
|
end
|
29
28
|
end
|
30
29
|
|
data/lib/tss/cli_combine.rb
CHANGED
@@ -6,6 +6,7 @@ module TSS
|
|
6
6
|
|
7
7
|
method_option :input_file, :aliases => '-I', :banner => 'input_file', :type => :string, :desc => 'A filename to read shares from'
|
8
8
|
method_option :output_file, :aliases => '-O', :banner => 'output_file', :type => :string, :desc => 'A filename to write the recovered secret to'
|
9
|
+
method_option :padding, :type => :boolean, :default => true, :desc => 'Whether PKCS#7 padding is expected in the secret and should be removed'
|
9
10
|
|
10
11
|
desc 'combine', 'Enter shares to recover a split secret'
|
11
12
|
|
@@ -35,6 +36,12 @@ module TSS
|
|
35
36
|
on the output file should provide a digest matching that of the secret
|
36
37
|
when it was originally split.
|
37
38
|
|
39
|
+
padding/no-padding :
|
40
|
+
Whether or not PKCS#7 padding should be removed from secret data. By
|
41
|
+
default padding is applied to shared secrets when created. Turning this
|
42
|
+
off may be helpful if you need to combine shares created with a third-party
|
43
|
+
library.
|
44
|
+
|
38
45
|
Example w/ options:
|
39
46
|
|
40
47
|
$ tss combine -I shares.txt -O secret.txt
|
@@ -104,7 +111,7 @@ module TSS
|
|
104
111
|
end
|
105
112
|
|
106
113
|
begin
|
107
|
-
sec = TSS.combine(shares: shares)
|
114
|
+
sec = TSS.combine(shares: shares, padding: options[:padding])
|
108
115
|
|
109
116
|
say('')
|
110
117
|
say('RECOVERED SECRET METADATA')
|
data/lib/tss/cli_split.rb
CHANGED
@@ -9,7 +9,7 @@ module TSS
|
|
9
9
|
method_option :identifier, :aliases => '-i', :banner => 'identifier', :type => :string, :desc => 'A unique identifier string, 0-16 Bytes, [a-zA-Z0-9.-_]'
|
10
10
|
method_option :hash_alg, :aliases => '-h', :banner => 'hash_alg', :type => :string, :desc => 'A hash type for verification, NONE, SHA1, SHA256'
|
11
11
|
method_option :format, :aliases => '-f', :banner => 'format', :type => :string, :default => 'HUMAN', :desc => 'Share output format, BINARY or HUMAN'
|
12
|
-
method_option :
|
12
|
+
method_option :padding, :type => :boolean, :default => true, :desc => 'Whether to apply PKCS#7 padding to the secret'
|
13
13
|
method_option :input_file, :aliases => '-I', :banner => 'input_file', :type => :string, :desc => 'A filename to read the secret from'
|
14
14
|
method_option :output_file, :aliases => '-O', :banner => 'output_file', :type => :string, :desc => 'A filename to write the shares to'
|
15
15
|
|
@@ -20,8 +20,8 @@ module TSS
|
|
20
20
|
a SECRET provided. A secret to be split can be provided using one of three
|
21
21
|
different input methods; STDIN, a path to a file, or when prompted
|
22
22
|
for it interactively. In all cases the secret should be UTF-8 or
|
23
|
-
US-ASCII encoded text and be no larger than
|
24
|
-
|
23
|
+
US-ASCII encoded text and be no larger than #{TSS::MAX_UNPADDED_SECRET_SIZE}
|
24
|
+
bytes.
|
25
25
|
|
26
26
|
Optional Params:
|
27
27
|
|
@@ -41,8 +41,8 @@ module TSS
|
|
41
41
|
hash_alg :
|
42
42
|
One of NONE, SHA1, SHA256. The algorithm to use for a one-way hash of the secret that will be split along with the secret.
|
43
43
|
|
44
|
-
|
45
|
-
|
44
|
+
padding/no-padding :
|
45
|
+
Whether to apply PKCS#7 padding to secret. By default padding is applied. Turning this off may be helpful if you need to interoperate with a third party library.
|
46
46
|
|
47
47
|
format :
|
48
48
|
Whether to output the shares as a binary octet string (RTSS), or as more human friendly URL safe Base 64 encoded text with some metadata.
|
@@ -55,18 +55,19 @@ module TSS
|
|
55
55
|
|
56
56
|
Example w/ options:
|
57
57
|
|
58
|
-
$ tss split -t 3 -n 6 -i abc123 -h SHA256 -
|
58
|
+
$ tss split -t 3 -n 6 -i abc123 -h SHA256 -f HUMAN
|
59
59
|
|
60
60
|
Enter your secret:
|
61
61
|
|
62
62
|
secret > my secret
|
63
63
|
|
64
|
-
tss~v1~abc123~3~
|
65
|
-
tss~v1~abc123~3~
|
66
|
-
tss~v1~abc123~3~
|
67
|
-
tss~v1~abc123~3~
|
68
|
-
tss~v1~abc123~3~
|
69
|
-
tss~v1~abc123~3~
|
64
|
+
tss~v1~abc123~3~YWJjMTIzAAAAAAAAAAAAAAIDADEB113xpF37jGHm5QGhXKD8mgK2897MIQkSWri6ksNnAODn0efXznuBsSUnhlDIqQFU
|
65
|
+
tss~v1~abc123~3~YWJjMTIzAAAAAAAAAAAAAAIDADEC4tZegQrC3z6-02er3FZaWMadtlvxPb1EI_FNjG0dFrcdEDj4V7Cmcw___SesJHHP
|
66
|
+
tss~v1~abc123~3~YWJjMTIzAAAAAAAAAAAAAAIDADEDWPKPVjJaITosPGAMhvCgxCBB9uptl2h5UPngnw71V7Z9T-pnxiLKIfgUbRqyBrv-
|
67
|
+
tss~v1~abc123~3~YWJjMTIzAAAAAAAAAAAAAAIDADEExY3ti8ckAIQC02OKCrpEVVnUmyg3NXO9oG3PNw3PlgbbKdFRi9gBCNN_tjkhT3An
|
68
|
+
tss~v1~abc123~3~YWJjMTIzAAAAAAAAAAAAAAIDADEFf6k8XP-8_oCQPGQtUBy-yb8I25mrn6aA02ViJG4n1we7dgPOGkptWiSUJgQ_bboW
|
69
|
+
tss~v1~abc123~3~YWJjMTIzAAAAAAAAAAAAAAIDADEGSiKTeaiFrd_ICgIn0OoYC3sjnhyWgxLWqiyVOsBdwVBBt9zhg4FKmA5MXXNb4MqN
|
70
|
+
|
70
71
|
LONGDESC
|
71
72
|
|
72
73
|
# rubocop:disable CyclomaticComplexity
|
@@ -124,8 +125,8 @@ module TSS
|
|
124
125
|
args[:num_shares] = options[:num_shares] if options[:num_shares]
|
125
126
|
args[:identifier] = options[:identifier] if options[:identifier]
|
126
127
|
args[:hash_alg] = options[:hash_alg] if options[:hash_alg]
|
127
|
-
args[:pad_blocksize] = options[:pad_blocksize] if options[:pad_blocksize]
|
128
128
|
args[:format] = options[:format] if options[:format]
|
129
|
+
args[:padding] = options[:padding]
|
129
130
|
|
130
131
|
begin
|
131
132
|
log("Calling : TSS.split(#{args.inspect})")
|
data/lib/tss/combiner.rb
CHANGED
@@ -12,14 +12,15 @@ module TSS
|
|
12
12
|
|
13
13
|
C = Contracts
|
14
14
|
|
15
|
-
attr_reader :shares, :select_by
|
15
|
+
attr_reader :shares, :select_by, :padding
|
16
16
|
|
17
|
-
Contract ({ :shares => C::ArrayOfShares, :select_by => C::Maybe[C::SelectByArg] }) => C::Any
|
17
|
+
Contract ({ :shares => C::ArrayOfShares, :select_by => C::Maybe[C::SelectByArg], :padding => C::Maybe[C::Bool] }) => C::Any
|
18
18
|
def initialize(opts = {})
|
19
19
|
# clone the incoming shares so the object passed to this
|
20
20
|
# function doesn't get modified.
|
21
21
|
@shares = opts.fetch(:shares).clone
|
22
22
|
@select_by = opts.fetch(:select_by, 'FIRST')
|
23
|
+
@padding = opts.fetch(:padding, true)
|
23
24
|
end
|
24
25
|
|
25
26
|
# Warning, you probably don't want to use this directly. Instead
|
@@ -150,8 +151,6 @@ module TSS
|
|
150
151
|
secret << Util.lagrange_interpolation(u, v)
|
151
152
|
end
|
152
153
|
|
153
|
-
strip_left_pad(secret)
|
154
|
-
|
155
154
|
hash_alg = Hasher.key_from_code(hash_id)
|
156
155
|
|
157
156
|
# Run the hash digest checks if the shares were created with a digest
|
@@ -161,6 +160,10 @@ module TSS
|
|
161
160
|
orig_hash_bytes = secret.pop(Hasher.bytesize(hash_alg))
|
162
161
|
orig_hash_hex = Util.bytes_to_hex(orig_hash_bytes)
|
163
162
|
|
163
|
+
# Remove PKCS#7 padding from the secret now that the hash
|
164
|
+
# has been extracted from the data
|
165
|
+
secret = Util.unpad(secret) if padding
|
166
|
+
|
164
167
|
# RTSS : verify that the recombined secret computes the same hash
|
165
168
|
# digest now as when it was originally created.
|
166
169
|
new_hash_bytes = Hasher.byte_array(hash_alg, Util.bytes_to_utf8(secret))
|
@@ -169,6 +172,8 @@ module TSS
|
|
169
172
|
unless Util.secure_compare(orig_hash_hex, new_hash_hex)
|
170
173
|
raise TSS::InvalidSecretHashError, 'invalid shares, hash of secret does not equal embedded hash'
|
171
174
|
end
|
175
|
+
else
|
176
|
+
secret = Util.unpad(secret) if padding
|
172
177
|
end
|
173
178
|
|
174
179
|
if secret.present?
|
@@ -178,16 +183,6 @@ module TSS
|
|
178
183
|
end
|
179
184
|
end
|
180
185
|
|
181
|
-
# Strip off leading padding chars ("\u001F", decimal 31)
|
182
|
-
#
|
183
|
-
# @param secret the secret to be stripped
|
184
|
-
# @return returns the secret, stripped of the leading padding char
|
185
|
-
# @raise [ParamContractError] if secret appears invalid
|
186
|
-
Contract C::ArrayOf[C::Num] => C::Maybe[Array]
|
187
|
-
def strip_left_pad(secret)
|
188
|
-
secret.shift while secret.first == 31
|
189
|
-
end
|
190
|
-
|
191
186
|
# Do all of the shares match the pattern expected of human style shares?
|
192
187
|
#
|
193
188
|
# @param shares the shares to be evaluated
|
data/lib/tss/splitter.rb
CHANGED
@@ -9,9 +9,9 @@ module TSS
|
|
9
9
|
|
10
10
|
C = Contracts
|
11
11
|
|
12
|
-
attr_reader :secret, :threshold, :num_shares, :identifier, :hash_alg, :format, :
|
12
|
+
attr_reader :secret, :threshold, :num_shares, :identifier, :hash_alg, :format, :padding
|
13
13
|
|
14
|
-
Contract ({ :secret => C::SecretArg, :threshold => C::Maybe[C::ThresholdArg], :num_shares => C::Maybe[C::NumSharesArg], :identifier => C::Maybe[C::IdentifierArg], :hash_alg => C::Maybe[C::HashAlgArg], :format => C::Maybe[C::FormatArg], :
|
14
|
+
Contract ({ :secret => C::SecretArg, :threshold => C::Maybe[C::ThresholdArg], :num_shares => C::Maybe[C::NumSharesArg], :identifier => C::Maybe[C::IdentifierArg], :hash_alg => C::Maybe[C::HashAlgArg], :format => C::Maybe[C::FormatArg], :padding => C::Maybe[C::Bool] }) => C::Any
|
15
15
|
def initialize(opts = {})
|
16
16
|
@secret = opts.fetch(:secret)
|
17
17
|
@threshold = opts.fetch(:threshold, 3)
|
@@ -19,7 +19,7 @@ module TSS
|
|
19
19
|
@identifier = opts.fetch(:identifier, SecureRandom.hex(8))
|
20
20
|
@hash_alg = opts.fetch(:hash_alg, 'SHA256')
|
21
21
|
@format = opts.fetch(:format, 'HUMAN')
|
22
|
-
@
|
22
|
+
@padding = opts.fetch(:padding, true)
|
23
23
|
end
|
24
24
|
|
25
25
|
SHARE_HEADER_STRUCT = BinaryStruct.new([
|
@@ -61,15 +61,19 @@ module TSS
|
|
61
61
|
def split
|
62
62
|
num_shares_not_less_than_threshold!(threshold, num_shares)
|
63
63
|
|
64
|
-
#
|
65
|
-
|
66
|
-
# correct secret was returned. secret || hash(secret). You can also
|
67
|
-
# optionally pad the secret first.
|
68
|
-
padded_secret = Util.left_pad(pad_blocksize, secret)
|
69
|
-
hashed_secret = Hasher.byte_array(hash_alg, secret)
|
70
|
-
secret_bytes = Util.utf8_to_bytes(padded_secret) + hashed_secret
|
64
|
+
# Append needed PKCS#7 padding to the string
|
65
|
+
secret_padded = padding ? Util.pad(secret) : secret
|
71
66
|
|
72
|
-
|
67
|
+
# Calculate the cryptographic hash of the secret string
|
68
|
+
secret_hash = Hasher.byte_array(hash_alg, secret)
|
69
|
+
|
70
|
+
# RTSS : Combine the secret with a hash digest before splitting. When
|
71
|
+
# recombine the two will be separated again and the hash will be used
|
72
|
+
# to validate the correct secret was returned.
|
73
|
+
# secret || padding || hash(secret)
|
74
|
+
secret_pad_hash_bytes = Util.utf8_to_bytes(secret_padded) + secret_hash
|
75
|
+
|
76
|
+
secret_bytes_is_smaller_than_max_size!(secret_pad_hash_bytes)
|
73
77
|
|
74
78
|
# For each share, a distinct Share Index is generated. Each Share
|
75
79
|
# Index is an octet other than the all-zero octet. All of the Share
|
@@ -101,7 +105,7 @@ module TSS
|
|
101
105
|
# of M octets; A[0] is equal to the first octet of the secret, B[0] is
|
102
106
|
# equal to the second octet of the secret, and so on.
|
103
107
|
#
|
104
|
-
|
108
|
+
secret_pad_hash_bytes.each do |byte|
|
105
109
|
# Unpack random Byte String into Byte Array of 8 bit unsigned Integers
|
106
110
|
r = SecureRandom.random_bytes(threshold - 1).unpack('C*')
|
107
111
|
|
@@ -148,8 +152,8 @@ module TSS
|
|
148
152
|
# @raise [ParamContractError, TSS::ArgumentError] if invalid
|
149
153
|
Contract C::ArrayOf[C::Int] => C::Bool
|
150
154
|
def secret_bytes_is_smaller_than_max_size!(secret_bytes)
|
151
|
-
if secret_bytes.size
|
152
|
-
raise TSS::ArgumentError, 'invalid secret, combined padded
|
155
|
+
if secret_bytes.size > TSS::MAX_SECRET_SIZE
|
156
|
+
raise TSS::ArgumentError, 'invalid secret, combined padded and hashed secret is too large'
|
153
157
|
else
|
154
158
|
return true
|
155
159
|
end
|
data/lib/tss/tss.rb
CHANGED
@@ -16,6 +16,16 @@ module TSS
|
|
16
16
|
include Contracts::Core
|
17
17
|
C = Contracts
|
18
18
|
|
19
|
+
# Defined in TSS spec, two less than 2^16
|
20
|
+
MAX_SECRET_SIZE = 64_534
|
21
|
+
|
22
|
+
# Max size minus up to 16 bytes PKCS#7 padding
|
23
|
+
# and 32 bytes of cryptographic hash
|
24
|
+
MAX_UNPADDED_SECRET_SIZE = MAX_SECRET_SIZE - 48
|
25
|
+
|
26
|
+
# When applying PKCS#7 padding, what block size in bytes should be used
|
27
|
+
PADDING_BLOCK_SIZE_BYTES = 16
|
28
|
+
|
19
29
|
# An unexpected error has occurred.
|
20
30
|
class Error < StandardError; end
|
21
31
|
|
@@ -59,23 +69,11 @@ module TSS
|
|
59
69
|
# who are recombining the shares to verify if they have in fact recovered
|
60
70
|
# the correct secret.
|
61
71
|
# @option opts [String] :format ('BINARY') the format of the String share output, 'BINARY' or 'HUMAN'
|
62
|
-
# @option opts [
|
63
|
-
# to left pad the secret to. Defaults to not adding any padding (0). Padding
|
64
|
-
# is done with the "\u001F" character (decimal 31 in a Byte Array).
|
65
|
-
#
|
66
|
-
# Since TSS share data (minus the header) is essentially the same size as the
|
67
|
-
# original secret, padding smaller secrets may help mask the size of the
|
68
|
-
# contents from an attacker. Padding is not part of the RTSS spec so other
|
69
|
-
# TSS clients won't strip off the padding and may not validate correctly.
|
70
|
-
#
|
71
|
-
# If you need this interoperability you should probably pad the secret
|
72
|
-
# yourself prior to splitting it and leave the default zero-length pad in
|
73
|
-
# place. You would also need to manually remove the padding you added after
|
74
|
-
# the share is recombined, or instruct recipients to ignore it.
|
72
|
+
# @option opts [Boolean] :padding Whether to apply PKCS#7 padding to secret
|
75
73
|
#
|
76
74
|
# @return an Array of formatted String shares
|
77
75
|
# @raise [ParamContractError, TSS::ArgumentError] if the options Types or Values are invalid
|
78
|
-
Contract ({ :secret => C::SecretArg, :threshold => C::Maybe[C::ThresholdArg], :num_shares => C::Maybe[C::NumSharesArg], :identifier => C::Maybe[C::IdentifierArg], :hash_alg => C::Maybe[C::HashAlgArg], :format => C::Maybe[C::FormatArg], :
|
76
|
+
Contract ({ :secret => C::SecretArg, :threshold => C::Maybe[C::ThresholdArg], :num_shares => C::Maybe[C::NumSharesArg], :identifier => C::Maybe[C::IdentifierArg], :hash_alg => C::Maybe[C::HashAlgArg], :format => C::Maybe[C::FormatArg], :padding => C::Maybe[C::Bool] }) => C::ArrayOfShares
|
79
77
|
def self.split(opts)
|
80
78
|
TSS::Splitter.new(opts).split
|
81
79
|
end
|
@@ -86,6 +84,7 @@ module TSS
|
|
86
84
|
#
|
87
85
|
# @param [Hash] opts the options to create a message with.
|
88
86
|
# @option opts [Array<String>] :shares an Array of String shares to try to recombine into a secret
|
87
|
+
# @option opts [Boolean] :padding Whether PKCS#7 padding is expected in the secret and should be removed
|
89
88
|
# @option opts [String] :select_by ('FIRST') the method to use for selecting
|
90
89
|
# shares from the Array if more then threshold shares are provided. Can be
|
91
90
|
# upper case 'FIRST', 'SAMPLE', or 'COMBINATIONS'.
|
@@ -122,7 +121,7 @@ module TSS
|
|
122
121
|
# @raise [TSS::NoSecretError] if the secret cannot be re-created from the shares provided
|
123
122
|
# @raise [TSS::InvalidSecretHashError] if the embedded hash of the secret does not match the hash of the recreated secret
|
124
123
|
# @raise [ParamContractError, TSS::ArgumentError] if the options Types or Values are invalid
|
125
|
-
Contract ({ :shares => C::ArrayOfShares, :select_by => C::Maybe[C::SelectByArg] }) => ({ :hash => C::Maybe[String], :hash_alg => C::HashAlgArg, :identifier => C::IdentifierArg, :process_time => C::Num, :secret => C::SecretArg, :threshold => C::ThresholdArg})
|
124
|
+
Contract ({ :shares => C::ArrayOfShares, :padding => C::Maybe[C::Bool], :select_by => C::Maybe[C::SelectByArg] }) => ({ :hash => C::Maybe[String], :hash_alg => C::HashAlgArg, :identifier => C::IdentifierArg, :process_time => C::Num, :secret => C::SecretArg, :threshold => C::ThresholdArg })
|
126
125
|
def self.combine(opts)
|
127
126
|
TSS::Combiner.new(opts).combine
|
128
127
|
end
|
data/lib/tss/util.rb
CHANGED
@@ -271,18 +271,40 @@ module TSS
|
|
271
271
|
bytes_to_hex(utf8_to_bytes(str))
|
272
272
|
end
|
273
273
|
|
274
|
-
#
|
274
|
+
# Pad a String with PKCS#7 (RFC5652)
|
275
|
+
# See : https://tools.ietf.org/html/rfc5652#section-6.3
|
275
276
|
#
|
276
|
-
# @param
|
277
|
-
# @param
|
278
|
-
# @
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
277
|
+
# @param str the String or Array of bytes to pad
|
278
|
+
# @param k pad blocksize (0-255), default 16
|
279
|
+
# @return a PKCS#7 padded String or Array of bytes
|
280
|
+
Contract C::Or[Array, String], C::PadBlocksizeArg => C::Or[Array, String]
|
281
|
+
def self.pad(str, k = TSS::PADDING_BLOCK_SIZE_BYTES)
|
282
|
+
return str if k.zero?
|
283
|
+
str_bytes = str.is_a?(Array) ? str : TSS::Util.utf8_to_bytes(str)
|
284
|
+
l = str_bytes.length
|
285
|
+
val = k - (l % k)
|
286
|
+
pad_bytes = [val] * val
|
287
|
+
padded_str_bytes = str_bytes + pad_bytes
|
288
|
+
str.is_a?(Array) ? padded_str_bytes : TSS::Util.bytes_to_utf8(padded_str_bytes)
|
289
|
+
end
|
290
|
+
|
291
|
+
# Remove padding from a String previously padded with PKCS#7 (RFC5652)
|
292
|
+
#
|
293
|
+
# @param str the String to remove padding from
|
294
|
+
# @param k pad blocksize (0-255)
|
295
|
+
# @return an unpadded String or Array of bytes
|
296
|
+
Contract C::Or[Array, String], C::PadBlocksizeArg => C::Or[Array, String]
|
297
|
+
def self.unpad(str, k = TSS::PADDING_BLOCK_SIZE_BYTES)
|
298
|
+
return str if k.zero?
|
299
|
+
str_bytes = str.is_a?(Array) ? str : TSS::Util.utf8_to_bytes(str)
|
300
|
+
val = str_bytes.last
|
301
|
+
raise 'Input is not padded or padding is corrupt' if val > k
|
302
|
+
# Verify that the proper number of PKCS#7 padding bytes are present
|
303
|
+
# and match the last byte value in both value and number of bytes present.
|
304
|
+
raise 'Padding bytes are invalid' unless str_bytes.last(val).all? {|b| b == val}
|
305
|
+
l = str_bytes.length - val
|
306
|
+
unpadded_str_bytes = str_bytes.take(l)
|
307
|
+
str.is_a?(Array) ? unpadded_str_bytes : TSS::Util.bytes_to_utf8(unpadded_str_bytes)
|
286
308
|
end
|
287
309
|
|
288
310
|
# Constant time string comparison.
|
data/lib/tss/version.rb
CHANGED
data/tss.gemspec
CHANGED
@@ -48,8 +48,10 @@ Gem::Specification.new do |spec|
|
|
48
48
|
spec.executables << 'tss'
|
49
49
|
spec.require_paths = ['lib']
|
50
50
|
|
51
|
+
spec.metadata["yard.run"] = "yri" # use "yard" to build full HTML docs.
|
52
|
+
|
51
53
|
spec.add_dependency 'activesupport', '>= 4.0.0'
|
52
|
-
spec.add_dependency 'sysrandom', '>= 1.0.3', '~> 1.0.
|
54
|
+
spec.add_dependency 'sysrandom', '>= 1.0.3', '~> 1.0.4'
|
53
55
|
spec.add_dependency 'contracts', '~> 0.14'
|
54
56
|
spec.add_dependency 'binary_struct', '~> 2.1'
|
55
57
|
spec.add_dependency 'thor', '~> 0.19'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tss
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Glenn Rempe
|
@@ -30,7 +30,7 @@ cert_chain:
|
|
30
30
|
vprF5QiDz8HshVP9DjJT2I1wyGyvxEdU3cTRo0upMP/VZLcgyBVFy90N2XYWWk2D
|
31
31
|
GIxGSw==
|
32
32
|
-----END CERTIFICATE-----
|
33
|
-
date:
|
33
|
+
date: 2017-01-29 00:00:00.000000000 Z
|
34
34
|
dependencies:
|
35
35
|
- !ruby/object:Gem::Dependency
|
36
36
|
name: activesupport
|
@@ -55,7 +55,7 @@ dependencies:
|
|
55
55
|
version: 1.0.3
|
56
56
|
- - "~>"
|
57
57
|
- !ruby/object:Gem::Version
|
58
|
-
version: 1.0.
|
58
|
+
version: 1.0.4
|
59
59
|
type: :runtime
|
60
60
|
prerelease: false
|
61
61
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -65,7 +65,7 @@ dependencies:
|
|
65
65
|
version: 1.0.3
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: 1.0.
|
68
|
+
version: 1.0.4
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: contracts
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -281,7 +281,8 @@ files:
|
|
281
281
|
homepage: https://github.com/grempe/tss-rb
|
282
282
|
licenses:
|
283
283
|
- MIT
|
284
|
-
metadata:
|
284
|
+
metadata:
|
285
|
+
yard.run: yri
|
285
286
|
post_install_message:
|
286
287
|
rdoc_options: []
|
287
288
|
require_paths:
|
@@ -298,7 +299,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
298
299
|
version: '0'
|
299
300
|
requirements: []
|
300
301
|
rubyforge_project:
|
301
|
-
rubygems_version: 2.
|
302
|
+
rubygems_version: 2.6.8
|
302
303
|
signing_key:
|
303
304
|
specification_version: 4
|
304
305
|
summary: A Ruby gem implementing Threshold Secret Sharing. This code can be used in
|
metadata.gz.sig
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
<��'
|