scl 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +6 -0
- data/README.md +71 -0
- data/Rakefile +2 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/scl +124 -0
- data/lib/scl/aes.rb +28 -0
- data/lib/scl/control/aes.rb +51 -0
- data/lib/scl/control/controller.rb +96 -0
- data/lib/scl/control/controller_module.rb +102 -0
- data/lib/scl/control/dh.rb +84 -0
- data/lib/scl/control/digest.rb +90 -0
- data/lib/scl/control/output.rb +14 -0
- data/lib/scl/control/rsa.rb +161 -0
- data/lib/scl/control/sss.rb +48 -0
- data/lib/scl/control.rb +14 -0
- data/lib/scl/dh.rb +52 -0
- data/lib/scl/digest.rb +29 -0
- data/lib/scl/formats/auto.rb +23 -0
- data/lib/scl/formats/base64.rb +12 -0
- data/lib/scl/formats/binary.rb +11 -0
- data/lib/scl/formats/format.rb +44 -0
- data/lib/scl/formats/hex.rb +11 -0
- data/lib/scl/formats/qrcode.rb +11 -0
- data/lib/scl/formats/stdout.rb +11 -0
- data/lib/scl/formats/wordlist.txt +235886 -0
- data/lib/scl/formats/words.rb +23 -0
- data/lib/scl/rsa.rb +72 -0
- data/lib/scl/secret_share.rb +122 -0
- data/lib/scl/version.rb +3 -0
- data/lib/scl.rb +12 -0
- data/scl.gemspec +25 -0
- metadata +120 -0
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'json'
|
2
|
+
module Scl
|
3
|
+
module Control
|
4
|
+
class DH < ControllerModule
|
5
|
+
|
6
|
+
help <<-HELP,
|
7
|
+
syn. Step 1 of a diffie hellman exchange.
|
8
|
+
Generates a private and public key and der to be used to generate a symmetric key with a second party.
|
9
|
+
|
10
|
+
e.g
|
11
|
+
>> Using public key (Saves to [filename].enc by default, unless -o is used)
|
12
|
+
scl dh syn
|
13
|
+
scl dh syn -fbase64
|
14
|
+
scl dh syn -o ./dhell
|
15
|
+
HELP
|
16
|
+
def syn
|
17
|
+
syn = dh.syn
|
18
|
+
args.output_file ||= "dh-key-exchange"
|
19
|
+
controller.output(
|
20
|
+
Output.new(syn[:private].to_json, ".dh1.priv"),
|
21
|
+
Output.new(syn[:public].to_json, ".dh1.pub")
|
22
|
+
)
|
23
|
+
end
|
24
|
+
|
25
|
+
help <<-HELP,
|
26
|
+
ack. Step 2 of a diffie hellman exchange.
|
27
|
+
Requires the public output of step 1 (The der and public key)
|
28
|
+
Generates a private and public key and der to be used to generate a symmetric key with a second party.
|
29
|
+
|
30
|
+
The output [output_file].key contains the secret key generated by the DH exchange.
|
31
|
+
The public output [output_file].dh2.pub must be passed back to the first party to complete the exchange
|
32
|
+
e.g
|
33
|
+
>> Using public key (Saves to [filename].enc by default, unless -o is used)
|
34
|
+
scl dh ack ./dh-key-exchange.dh1.pub
|
35
|
+
scl dh ack ./dhell.dh1.pub -o ./dhell
|
36
|
+
HELP
|
37
|
+
def ack(file)
|
38
|
+
unless File.exists?(file)
|
39
|
+
raise ControlError.new("Couldn't find file containing part 1 of diffie hellman exchange: #{file}. File doesnt exist")
|
40
|
+
end
|
41
|
+
input = JSON.parse(input_decoder.decode(IO.read(file)))
|
42
|
+
ack = dh.ack(der: input['der'], public_key: input['public_key'])
|
43
|
+
args.output_file ||= "dh-key-exchange"
|
44
|
+
controller.output(
|
45
|
+
Output.new(ack[:private].to_json, ".dh2.key"),
|
46
|
+
Output.new(ack[:public].to_json, ".dh2.pub")
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
help <<-HELP,
|
51
|
+
fin. Step 3 and final step of a diffie hellman exchange.
|
52
|
+
Requires the private output of step 1 (The der and private key) and the public key from step 2
|
53
|
+
Generates a secret key shared with the second party
|
54
|
+
|
55
|
+
The output [output_file].key contains the secret key generated by the DH exchange.
|
56
|
+
|
57
|
+
e.g
|
58
|
+
>> Using public key (Saves to [filename].enc by default, unless -o is used)
|
59
|
+
scl dh fin ./dh-key-exchange.dh1.priv ./dh-key-exchange.dh2.pub
|
60
|
+
scl dh fin ./dhell.dh1.priv ./dhell.dh2.pub -o ./dhell
|
61
|
+
HELP
|
62
|
+
def fin(dh1_priv, dh2_pub)
|
63
|
+
unless File.exists?(dh1_priv)
|
64
|
+
raise ControlError.new("Couldn't find file private portion of part 1 of diffie hellman exchange: #{dh1_priv}. File doesnt exist")
|
65
|
+
end
|
66
|
+
unless File.exists?(dh2_pub)
|
67
|
+
raise ControlError.new("Couldn't find file containing public portion of part 2 of diffie hellman exchange: #{dh2_pub}. File doesnt exist")
|
68
|
+
end
|
69
|
+
dh1 = JSON.parse(input_decoder.decode(IO.read(dh1_priv)))
|
70
|
+
dh2 = JSON.parse(input_decoder.decode(IO.read(dh2_pub)))
|
71
|
+
result = dh.fin(der: dh1['der'], private_key: dh1['private_key'], public_key: dh2['public_key'])
|
72
|
+
args.output_file ||= "dh-key-exchange"
|
73
|
+
controller.output(
|
74
|
+
Output.new(result[:private].to_json, ".dh1.key")
|
75
|
+
)
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
def dh
|
80
|
+
@dh ||= Scl::DH.new
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module Scl
|
2
|
+
module Control
|
3
|
+
class Digest < ControllerModule
|
4
|
+
|
5
|
+
help <<-HELP,
|
6
|
+
sign. Signs a file using a support hash algorithm. Defaults to sha256
|
7
|
+
e.g
|
8
|
+
scl digest sign /path/to/file
|
9
|
+
scl digest sign /path/to/file -o stdout
|
10
|
+
scl digest sign /path/to/file -d sha512
|
11
|
+
HELP
|
12
|
+
def sign(input_file)
|
13
|
+
signature = Scl::Digest.digest(args.digest || 'sha256', read_file(input_file, "File to sign"))
|
14
|
+
args.output_file ||= input_file
|
15
|
+
args.output_format ||= 'binary'
|
16
|
+
controller.output(
|
17
|
+
Output.new(signature, ".sig")
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
help <<-HELP,
|
22
|
+
verify
|
23
|
+
e.g.
|
24
|
+
scl digest verify file signature
|
25
|
+
scl digest verify file signature -d sha512
|
26
|
+
HELP
|
27
|
+
def verify(input_file, signature_file)
|
28
|
+
signature = Scl::Digest.digest(args.digest || 'sha256', read_file(input_file, "File to verify"))
|
29
|
+
args.input_format ||= 'binary'
|
30
|
+
if signature == input_decoder.decode(read_file(signature_file, "Signature"))
|
31
|
+
exit(0)
|
32
|
+
else
|
33
|
+
exit(1)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
help <<-HELP,
|
38
|
+
hmac. Generates an HMAC for a file, can be given an optional key or alternately one will be
|
39
|
+
generated for you. Keep hold of this key for verifying signatures in the future
|
40
|
+
e.g.
|
41
|
+
scl hmac file # Generates both a digest and a secure random key
|
42
|
+
scl hmac file -k keyfile # Generates a digest using an existing key
|
43
|
+
scl hmac file -d sha512 # Provide alternate digest algorithm
|
44
|
+
HELP
|
45
|
+
def hmac(input_file)
|
46
|
+
input_key = args.key_path ?
|
47
|
+
read_file(args.key_path) :
|
48
|
+
nil
|
49
|
+
signature, key = Scl::Digest.hmac(args.digest || 'sha256', read_file(input_file, "File to sign"), input_key)
|
50
|
+
args.output_file ||= input_file
|
51
|
+
args.output_format ||= 'binary'
|
52
|
+
controller.output(
|
53
|
+
Output.new(signature, ".sig"),
|
54
|
+
input_key ? nil : Output.new(key, '.key')
|
55
|
+
)
|
56
|
+
end
|
57
|
+
|
58
|
+
help <<-HELP,
|
59
|
+
hmac. Verifies the contents of a file match an HMAC signature (using a given key)
|
60
|
+
e.g.
|
61
|
+
scl hmac_verify file signature -k keyfile
|
62
|
+
HELP
|
63
|
+
def hmac_verify(input_file, signature_file)
|
64
|
+
args.input_format ||= 'binary'
|
65
|
+
key = input_decoder.decode(read_file(args.key_path, 'HMAC Key file', 'Use -k'))
|
66
|
+
data = read_file(input_file, "File to verify")
|
67
|
+
signature, key = Scl::Digest.hmac(args.digest || 'sha256', data, key)
|
68
|
+
if signature == input_decoder.decode(read_file(signature_file, "Signature"))
|
69
|
+
exit(0)
|
70
|
+
else
|
71
|
+
exit(1)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
help <<-HELP,
|
76
|
+
list. List supported hash algorithms
|
77
|
+
e.g.
|
78
|
+
scl digest list
|
79
|
+
HELP
|
80
|
+
def list
|
81
|
+
puts OpenSSL::Digest.constants.reject{|x| x.to_s =~ /Error/ }
|
82
|
+
end
|
83
|
+
|
84
|
+
private
|
85
|
+
def ss
|
86
|
+
@ss ||= Scl::SecretShare.new(args.min_shares.to_i, args.num_shares.to_i)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Scl
|
2
|
+
module Control
|
3
|
+
class Output
|
4
|
+
attr_reader :content
|
5
|
+
def initialize(content, suffix)
|
6
|
+
@content, @suffix = content, suffix
|
7
|
+
end
|
8
|
+
|
9
|
+
def file(path)
|
10
|
+
File.join("#{path.gsub(%r(#{@suffix.gsub('.','\.')}$),'')}#{@suffix}")
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
module Scl
|
2
|
+
module Control
|
3
|
+
class RSA < ControllerModule
|
4
|
+
|
5
|
+
help <<-HELP,
|
6
|
+
Generates an RSA keypair
|
7
|
+
e.g
|
8
|
+
>> Generates a key-pair and prints to stdout
|
9
|
+
$ scl rsa generate
|
10
|
+
|
11
|
+
>> Generates a key-pair and saves to the filesystem
|
12
|
+
$ scl rsa generate -o /path/to/file
|
13
|
+
HELP
|
14
|
+
def generate
|
15
|
+
begin
|
16
|
+
result = Scl::RSA.generate(args.key_size)
|
17
|
+
controller.output(
|
18
|
+
Output.new(result.public.export, '.pub'),
|
19
|
+
Output.new(result.private.export, '.priv')
|
20
|
+
)
|
21
|
+
rescue StandardError => e
|
22
|
+
raise ControlError.new("Couldn't generate key of size #{args.key_size}")
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
help <<-HELP,
|
27
|
+
Signs a file using an RSA private key.
|
28
|
+
This file can then be verified using the corresponding public-key or the same private-key
|
29
|
+
e.g
|
30
|
+
>> Sign [file] using private key
|
31
|
+
$ scl rsa sign file -Z /path/to/private/key
|
32
|
+
HELP
|
33
|
+
def sign(file)
|
34
|
+
unless args.private_key_file
|
35
|
+
raise ControlError.new("Please provide a private key file (-Z or --priv) use --help to find out more")
|
36
|
+
end
|
37
|
+
unless File.exists?(args.private_key_file)
|
38
|
+
raise ControlError.new("Private key file #{args.private_key_file} doesnt exist")
|
39
|
+
end
|
40
|
+
unless File.exists?(file)
|
41
|
+
raise ControlError.new("Couldn't find file to sign: #{file}. File doesnt exist")
|
42
|
+
end
|
43
|
+
|
44
|
+
private_key = load_key(args.private_key_file)
|
45
|
+
signature = private_key.sign(IO.read(file))
|
46
|
+
args.output_file ||= file
|
47
|
+
controller.output(
|
48
|
+
Output.new(signature, ".sig")
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
help <<-HELP,
|
53
|
+
Verifies a file matches a signature for an RSA private key
|
54
|
+
Verification can be performed using the corresponding public-key or the same private-key that generated the signature
|
55
|
+
e.g
|
56
|
+
|
57
|
+
>> Verify [file] using public key
|
58
|
+
$ scl rsa verify -p /path/to/private/key file file.sig
|
59
|
+
$ scl rsa verify --pub-key /path/to/private/key file file.sig
|
60
|
+
|
61
|
+
>> Verify [file] using private key
|
62
|
+
$ scl rsa verify -Z /path/to/private/key file file.sig
|
63
|
+
HELP
|
64
|
+
def verify(file, signature="#{file}.sig")
|
65
|
+
key_file = args.public_key_file || args.private_key_file
|
66
|
+
unless key_file
|
67
|
+
raise ControlError.new("Please provide a private or public key file (-p --pub-key, -Z or --priv-key) use --help to find out more")
|
68
|
+
end
|
69
|
+
unless File.exists?(key_file)
|
70
|
+
raise ControlError.new("Key file #{key_file} doesnt exist")
|
71
|
+
end
|
72
|
+
unless File.exists?(file)
|
73
|
+
raise ControlError.new("Couldn't find file to verify: #{file}. File doesnt exist")
|
74
|
+
end
|
75
|
+
unless File.exists?(signature)
|
76
|
+
raise ControlError.new("Couldn't find signature to verify: #{signature}. File doesnt exist")
|
77
|
+
end
|
78
|
+
key = load_key(key_file)
|
79
|
+
if key.verify(input_decoder.decode(IO.read(signature)), IO.read(file))
|
80
|
+
exit(0)
|
81
|
+
else
|
82
|
+
exit(1)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
help <<-HELP,
|
87
|
+
Encrypts a file.
|
88
|
+
e.g
|
89
|
+
>> Using public key (Saves to [filename].enc by default, unless -o is used)
|
90
|
+
scl rsa encrypt -p /path/to/public_key /path/to/file
|
91
|
+
scl rsa encrypt --pub-key /path/to/public_key /path/to/file
|
92
|
+
|
93
|
+
>> Using public key (Saves to [filename].enc by default, unless -o is used)
|
94
|
+
scl rsa encrypt -Z /path/to/private_key /path/to/file
|
95
|
+
scl rsa encrypt --priv-key /path/to/private_key /path/to/file
|
96
|
+
HELP
|
97
|
+
def encrypt(file)
|
98
|
+
key_file = args.public_key_file || args.private_key_file
|
99
|
+
unless key_file
|
100
|
+
raise ControlError.new("Please provide a private or public key file (-p --pub-key, -Z or --priv-key) use --help to find out more")
|
101
|
+
end
|
102
|
+
unless File.exists?(key_file)
|
103
|
+
raise ControlError.new("Key file #{key_file} doesnt exist")
|
104
|
+
end
|
105
|
+
unless File.exists?(file)
|
106
|
+
raise ControlError.new("Couldn't find file to verify: #{file}. File doesnt exist")
|
107
|
+
end
|
108
|
+
key = load_key(key_file)
|
109
|
+
encrypted = key.encrypt(IO.read(file))
|
110
|
+
args.output_file ||= file
|
111
|
+
controller.output(
|
112
|
+
Output.new(encrypted, '.enc')
|
113
|
+
)
|
114
|
+
end
|
115
|
+
|
116
|
+
help <<-HELP,
|
117
|
+
Decrypts a file.
|
118
|
+
e.g
|
119
|
+
>> Using public key (Writes to stdout unless -o is used)
|
120
|
+
scl rsa decrypt -p /path/to/public_key /path/to/file.enc
|
121
|
+
scl rsa decrypt --pub-key /path/to/public_key /path/to/file.enc
|
122
|
+
|
123
|
+
>> Using public key (Writes to stdout unless -o is used)
|
124
|
+
scl rsa decrypt -Z /path/to/private_key /path/to/file.enc
|
125
|
+
scl rsa decrypt --priv-key /path/to/private_key /path/to/file.enc
|
126
|
+
HELP
|
127
|
+
def decrypt(file)
|
128
|
+
key_file = args.public_key_file || args.private_key_file
|
129
|
+
unless key_file
|
130
|
+
raise ControlError.new("Please provide a private or public key file (-p --pub-key, -Z or --priv-key) use --help to find out more")
|
131
|
+
end
|
132
|
+
unless File.exists?(key_file)
|
133
|
+
raise ControlError.new("Key file #{key_file} doesnt exist")
|
134
|
+
end
|
135
|
+
unless File.exists?(file)
|
136
|
+
raise ControlError.new("Couldn't find file to verify: #{file}. File doesnt exist")
|
137
|
+
end
|
138
|
+
key = load_key(key_file)
|
139
|
+
decrypted = key.decrypt(input_decoder.decode(IO.read(file)))
|
140
|
+
args.output_format = 'binary'
|
141
|
+
controller.output(
|
142
|
+
Output.new(decrypted, '')
|
143
|
+
)
|
144
|
+
end
|
145
|
+
|
146
|
+
private
|
147
|
+
def load_key(key_file)
|
148
|
+
raw_input = IO.read(key_file)
|
149
|
+
puts "Decoding key using #{input_decoder.name}" if args.verbose
|
150
|
+
decoded_input = key_coder.decode(raw_input)
|
151
|
+
puts "Constructing new RSA key using decoded input" if args.verbose
|
152
|
+
begin
|
153
|
+
pkey = OpenSSL::PKey::RSA.new(decoded_input)
|
154
|
+
Scl::RSA::Key.new(pkey)
|
155
|
+
rescue StandardError => e
|
156
|
+
raise ControlError.new("Unable to construct key from decoded input #{e.message}")
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Scl
|
2
|
+
module Control
|
3
|
+
class SSS < ControllerModule
|
4
|
+
|
5
|
+
help <<-HELP,
|
6
|
+
generate. Generate a set of shares for a shared secret
|
7
|
+
Arguments are the total number of shares to generate, and the number of shares required to unlock
|
8
|
+
the secret.
|
9
|
+
e.g
|
10
|
+
scl sss generate -m 3 -n 5
|
11
|
+
scl sss generate --min-shares=11 --num-shares=14 -o output_file
|
12
|
+
|
13
|
+
Large secrets are encoded using multiple blocks, which can create large shares.
|
14
|
+
An alternative, more space efficient approach to this is to encode a shorter key using secret sharing,
|
15
|
+
and to then encrypt the large secret using this key and a block-cipher
|
16
|
+
|
17
|
+
HELP
|
18
|
+
def generate(input_file)
|
19
|
+
raise ControlError.new("Min-shares must be a positive integer") unless args.min_shares.to_i > 0
|
20
|
+
raise ControlError.new("Num-shares must be a positive integer") unless args.num_shares.to_i > 0
|
21
|
+
raise ControlError.new('Num shares must be larger than or equal to min shares') unless args.num_shares.to_i >= args.min_shares.to_i
|
22
|
+
input = read_file(input_file)
|
23
|
+
args.output_file ||= input_file
|
24
|
+
controller.output(
|
25
|
+
Output.new(ss.generate(input).join("\n"), ".shares")
|
26
|
+
)
|
27
|
+
end
|
28
|
+
|
29
|
+
help <<-HELP,
|
30
|
+
combine. Combines a set of shares for a shared secret
|
31
|
+
Expects as an argument a file of "\n" separate secret shares
|
32
|
+
e.g
|
33
|
+
scl sss combine shares.txt
|
34
|
+
HELP
|
35
|
+
def combine(input_file)
|
36
|
+
shares = read_file(input_file).split("\n")
|
37
|
+
controller.output(
|
38
|
+
Output.new(Scl::SecretShare.combine(shares), ".sec")
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
def ss
|
44
|
+
@ss ||= Scl::SecretShare.new(args.min_shares.to_i, args.num_shares.to_i)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/scl/control.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'scl/control/output'
|
2
|
+
require 'scl/control/controller'
|
3
|
+
require 'scl/control/controller_module'
|
4
|
+
require 'scl/control/aes'
|
5
|
+
require 'scl/control/rsa'
|
6
|
+
require 'scl/control/sss'
|
7
|
+
require 'scl/control/dh'
|
8
|
+
require 'scl/control/digest'
|
9
|
+
|
10
|
+
module Scl
|
11
|
+
module Control
|
12
|
+
class ControlError < StandardError; end
|
13
|
+
end
|
14
|
+
end
|
data/lib/scl/dh.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
module Scl
|
2
|
+
require 'base64'
|
3
|
+
class DH
|
4
|
+
attr_reader :encoder
|
5
|
+
|
6
|
+
def initialize(encoder: Format::BASE64)
|
7
|
+
@encoder = encoder
|
8
|
+
end
|
9
|
+
# :0> syn = Scl::DH.new.syn
|
10
|
+
# :1> ack = Scl::DH.new.ack(syn[:public])
|
11
|
+
# :2> shared_key1 = Scl::DH.new.fin(syn[:private].merge(ack[:public]))[:private][:shared_key]
|
12
|
+
# :3> shared_key2 = ack[:private][:shared_key]
|
13
|
+
def syn(length: 512)
|
14
|
+
dh = OpenSSL::PKey::DH.new(length)
|
15
|
+
{
|
16
|
+
private: {
|
17
|
+
der: encoder.encode(dh.public_key.to_der),
|
18
|
+
private_key: encoder.encode(dh.priv_key.to_s(16))
|
19
|
+
},
|
20
|
+
public: {
|
21
|
+
der: encoder.encode(dh.public_key.to_der),
|
22
|
+
public_key: encoder.encode(dh.pub_key.to_s(16))
|
23
|
+
}
|
24
|
+
}
|
25
|
+
end
|
26
|
+
|
27
|
+
def ack(der:, public_key:)
|
28
|
+
dh = OpenSSL::PKey::DH.new(encoder.decode(der))
|
29
|
+
dh.generate_key!
|
30
|
+
shared_key = dh.compute_key(OpenSSL::BN.new(encoder.decode(public_key), 16))
|
31
|
+
{
|
32
|
+
private: {
|
33
|
+
shared_key: encoder.encode(shared_key)
|
34
|
+
},
|
35
|
+
public: {
|
36
|
+
public_key: encoder.encode(dh.pub_key.to_s(16))
|
37
|
+
}
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
def fin(private_key:, der:, public_key:)
|
42
|
+
dh = OpenSSL::PKey::DH.new(encoder.decode(der))
|
43
|
+
dh.priv_key = OpenSSL::BN.new(encoder.decode(private_key), 16)
|
44
|
+
shared_key = dh.compute_key(OpenSSL::BN.new(encoder.decode(public_key), 16))
|
45
|
+
{
|
46
|
+
private: {
|
47
|
+
shared_key: encoder.encode(shared_key)
|
48
|
+
}
|
49
|
+
}
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/scl/digest.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
module Scl
|
2
|
+
class Digest
|
3
|
+
def self.digest(digest, data)
|
4
|
+
if digest_exists?(digest)
|
5
|
+
OpenSSL::Digest.const_get(digest.upcase).new.hexdigest(data)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.hmac(digest, data, key=nil)
|
10
|
+
if digest_exists?(digest)
|
11
|
+
require 'securerandom'
|
12
|
+
key = key || SecureRandom.hex
|
13
|
+
[OpenSSL::HMAC.hexdigest(digest, key, data), key]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
def self.digest_exists?(digest)
|
19
|
+
begin
|
20
|
+
OpenSSL::Digest.const_get(digest.upcase)
|
21
|
+
rescue NameError => e
|
22
|
+
puts "Couldn't get digest type. #{digest}"
|
23
|
+
puts "Try $ scl digest list – for a list of supported digests"
|
24
|
+
return false
|
25
|
+
end
|
26
|
+
true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Scl
|
2
|
+
class Scl::Auto < Scl::Format
|
3
|
+
def encode(data)
|
4
|
+
sorted = (data.chars.map(&:ord).uniq.sort) - [10]
|
5
|
+
if sorted.first < 32 || sorted.max > 126
|
6
|
+
Scl::Format::BASE64.encode(data)
|
7
|
+
else
|
8
|
+
Scl::Format::BINARY.encode(data)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def decode(data)
|
13
|
+
png = Regexp.new("\x89PNG".force_encoding("binary"))
|
14
|
+
if /^#{png}/ === data
|
15
|
+
Scl::Format::QRCODE.decode(data)
|
16
|
+
elsif data[/[^A-Za-z0-9\+\/\n=]/]
|
17
|
+
Scl::Format::BINARY.decode(data)
|
18
|
+
else
|
19
|
+
Scl::Format::BASE64.decode(data)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Scl
|
2
|
+
class Format
|
3
|
+
def output(filename, data)
|
4
|
+
IO.write(filename, encode(data))
|
5
|
+
end
|
6
|
+
|
7
|
+
def read(filename)
|
8
|
+
decode(IO.read(filename))
|
9
|
+
end
|
10
|
+
|
11
|
+
def encode(data)
|
12
|
+
raise "Must be implemented by subclass"
|
13
|
+
end
|
14
|
+
|
15
|
+
def decode(data)
|
16
|
+
raise "Must be implemented by subclass"
|
17
|
+
end
|
18
|
+
|
19
|
+
def name
|
20
|
+
self.class.name
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
require 'scl/formats/base64'
|
26
|
+
require 'scl/formats/binary'
|
27
|
+
require 'scl/formats/words'
|
28
|
+
require 'scl/formats/auto'
|
29
|
+
require 'scl/formats/hex'
|
30
|
+
require 'scl/formats/qrcode'
|
31
|
+
require 'scl/formats/stdout'
|
32
|
+
|
33
|
+
module Scl
|
34
|
+
class Format
|
35
|
+
|
36
|
+
BASE64 = Scl::Base64.new
|
37
|
+
BINARY = Scl::Binary.new
|
38
|
+
WORDS = Scl::Words.new
|
39
|
+
QRCODE = Scl::QRCode.new
|
40
|
+
HEX = Scl::Hex.new
|
41
|
+
AUTO = Scl::Auto.new
|
42
|
+
STDOUT = Scl::Stdout.new
|
43
|
+
end
|
44
|
+
end
|