ruby-paseto 0.1.2 → 0.2.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
- data/CHANGELOG.md +7 -0
- data/README.md +55 -50
- data/lib/paseto/asn1/ecdsa_signature.rb +2 -2
- data/lib/paseto/asymmetric_key.rb +7 -4
- data/lib/paseto/configuration/decode_configuration.rb +7 -7
- data/lib/paseto/interface/key.rb +5 -2
- data/lib/paseto/interface/pbkd.rb +4 -20
- data/lib/paseto/interface/pie.rb +5 -26
- data/lib/paseto/interface/pke.rb +15 -51
- data/lib/paseto/interface/version.rb +30 -117
- data/lib/paseto/operations/id/i_dv3.rb +1 -1
- data/lib/paseto/operations/id/i_dv4.rb +1 -1
- data/lib/paseto/operations/pbkd/p_b_k_dv3.rb +4 -5
- data/lib/paseto/operations/pbkd/p_b_k_dv4.rb +3 -4
- data/lib/paseto/operations/pbkw.rb +6 -6
- data/lib/paseto/operations/pke/p_k_ev3.rb +23 -25
- data/lib/paseto/operations/pke/p_k_ev4.rb +33 -34
- data/lib/paseto/operations/pke.rb +9 -10
- data/lib/paseto/operations/wrap.rb +1 -1
- data/lib/paseto/paserk.rb +1 -1
- data/lib/paseto/paserk_types.rb +2 -2
- data/lib/paseto/protocol/version3.rb +17 -16
- data/lib/paseto/protocol/version4.rb +17 -16
- data/lib/paseto/symmetric_key.rb +16 -10
- data/lib/paseto/token.rb +17 -15
- data/lib/paseto/token_types.rb +2 -2
- data/lib/paseto/util.rb +1 -1
- data/lib/paseto/v3/local.rb +1 -1
- data/lib/paseto/v3/public.rb +5 -4
- data/lib/paseto/v4/local.rb +3 -3
- data/lib/paseto/v4/public.rb +3 -6
- data/lib/paseto/validator.rb +1 -1
- data/lib/paseto/version.rb +1 -1
- data/lib/paseto/versions.rb +2 -2
- data/lib/paseto/wrappers/pie/pie_v3.rb +18 -21
- data/lib/paseto/wrappers/pie/pie_v4.rb +17 -20
- data/lib/paseto/wrappers/pie.rb +3 -17
- data/lib/paseto.rb +2 -5
- data/paseto.gemspec +5 -5
- data/sorbet/rbi/annotations/.gitattributes +1 -0
- data/sorbet/rbi/annotations/rainbow.rbi +4 -4
- data/sorbet/rbi/gems/.gitattributes +1 -0
- data/sorbet/rbi/gems/diff-lcs@1.5.0.rbi +1 -1
- data/sorbet/rbi/gems/docile@1.4.0.rbi +1 -1
- data/sorbet/rbi/gems/{ffi@1.15.5.rbi → ffi@1.16.3.rbi} +260 -117
- data/sorbet/rbi/gems/{oj@3.14.2.rbi → oj@3.16.1.rbi} +26 -37
- data/sorbet/rbi/gems/{rake@13.0.6.rbi → rake@13.1.0.rbi} +75 -69
- data/sorbet/rbi/gems/rbnacl@7.1.1.rbi +2 -2
- data/sorbet/rbi/gems/{rspec-core@3.12.1.rbi → rspec-core@3.12.2.rbi} +1 -1
- data/sorbet/rbi/gems/{rspec-expectations@3.12.2.rbi → rspec-expectations@3.12.3.rbi} +27 -33
- data/sorbet/rbi/gems/{rspec-mocks@3.12.4.rbi → rspec-mocks@3.12.6.rbi} +60 -61
- data/sorbet/rbi/gems/{rspec-support@3.12.0.rbi → rspec-support@3.12.1.rbi} +35 -43
- data/sorbet/rbi/gems/rspec@3.12.0.rbi +22 -28
- data/sorbet/rbi/gems/simplecov-html@0.12.3.rbi +41 -44
- data/sorbet/rbi/gems/simplecov_json_formatter@0.1.4.rbi +232 -2
- data/sorbet/rbi/gems/{timecop@0.9.6.rbi → timecop@0.9.8.rbi} +13 -16
- data/sorbet/rbi/shims/multi_json.rbi +2 -0
- data/sorbet/rbi/shims/openssl.rbi +0 -8
- data/sorbet/rbi/todo.rbi +5 -1
- metadata +19 -42
- data/sorbet/rbi/gems/ast@2.4.2.rbi +0 -584
- data/sorbet/rbi/gems/io-console@0.6.0.rbi +0 -8
- data/sorbet/rbi/gems/irb@1.6.3.rbi +0 -342
- data/sorbet/rbi/gems/json@2.6.3.rbi +0 -1541
- data/sorbet/rbi/gems/multi_json@1.15.0.rbi +0 -267
- data/sorbet/rbi/gems/netrc@0.11.0.rbi +0 -158
- data/sorbet/rbi/gems/openssl@3.1.0.rbi +0 -1739
- data/sorbet/rbi/gems/parallel@1.22.1.rbi +0 -277
- data/sorbet/rbi/gems/rainbow@3.1.1.rbi +0 -407
- data/sorbet/rbi/gems/regexp_parser@2.7.0.rbi +0 -3580
- data/sorbet/rbi/gems/reline@0.3.2.rbi +0 -8
- data/sorbet/rbi/gems/rexml@3.2.5.rbi +0 -4717
- data/sorbet/rbi/gems/ruby-progressbar@1.13.0.rbi +0 -1317
- data/sorbet/rbi/gems/thor@1.2.1.rbi +0 -3956
- data/sorbet/rbi/gems/unicode-display_width@2.4.2.rbi +0 -65
- data/sorbet/rbi/gems/webrick@1.7.0.rbi +0 -2555
- data/sorbet/rbi/gems/yard-sorbet@0.8.0.rbi +0 -441
- data/sorbet/rbi/gems/yard@0.9.28.rbi +0 -17816
- data/sorbet/rbi/gems/zeitwerk@2.6.7.rbi +0 -8
@@ -8,144 +8,57 @@ module Paseto
|
|
8
8
|
extend T::Helpers
|
9
9
|
|
10
10
|
include Comparable
|
11
|
-
include Kernel
|
12
11
|
|
13
12
|
abstract!
|
14
13
|
|
15
|
-
|
16
|
-
|
17
|
-
extend T::Helpers
|
14
|
+
sig { abstract.params(key: String, nonce: String, payload: String).returns(String) }
|
15
|
+
def crypt(key:, nonce:, payload:); end
|
18
16
|
|
19
|
-
|
17
|
+
sig { abstract.params(data: String, digest_size: Integer).returns(String) }
|
18
|
+
def digest(data, digest_size:); end
|
20
19
|
|
21
|
-
|
22
|
-
|
20
|
+
sig { abstract.returns(Integer) }
|
21
|
+
def digest_bytes; end
|
23
22
|
|
24
|
-
|
25
|
-
|
23
|
+
sig { abstract.params(data: String, key: String, digest_size: Integer).returns(String) }
|
24
|
+
def hmac(data, key:, digest_size: nil); end
|
26
25
|
|
27
|
-
|
28
|
-
|
26
|
+
sig { abstract.returns(Interface::ID) }
|
27
|
+
def id; end
|
29
28
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
sig { abstract.returns(Interface::ID) }
|
34
|
-
def id; end
|
35
|
-
|
36
|
-
sig do
|
37
|
-
abstract.params(
|
38
|
-
password: String,
|
39
|
-
salt: String,
|
40
|
-
length: Integer,
|
41
|
-
parameters: Integer
|
42
|
-
).returns(String)
|
43
|
-
end
|
44
|
-
def kdf(password, salt:, length:, **parameters); end
|
45
|
-
|
46
|
-
sig { abstract.returns(String) }
|
47
|
-
def paserk_version; end
|
48
|
-
|
49
|
-
sig { abstract.returns(String) }
|
50
|
-
def pbkd_local_header; end
|
51
|
-
|
52
|
-
sig { abstract.returns(String) }
|
53
|
-
def pbkd_secret_header; end
|
54
|
-
|
55
|
-
sig { abstract.params(password: String).returns(Interface::PBKD) }
|
56
|
-
def pbkw(password); end
|
57
|
-
|
58
|
-
sig { abstract.params(key: SymmetricKey).returns(Interface::PIE) }
|
59
|
-
def pie(key); end
|
60
|
-
|
61
|
-
sig { abstract.params(key: AsymmetricKey).returns(Interface::PKE) }
|
62
|
-
def pke(key); end
|
63
|
-
|
64
|
-
sig { abstract.params(size: Integer).returns(String) }
|
65
|
-
def random(size); end
|
66
|
-
|
67
|
-
sig { abstract.returns(String) }
|
68
|
-
def version; end
|
69
|
-
end
|
70
|
-
|
71
|
-
mixes_in_class_methods(ClassMethods)
|
72
|
-
|
73
|
-
sig(:final) { params(key: String, nonce: String, payload: String).returns(String) }
|
74
|
-
def crypt(key:, nonce:, payload:)
|
75
|
-
self.class.crypt(key: key, nonce: nonce, payload: payload)
|
76
|
-
end
|
77
|
-
|
78
|
-
sig(:final) { params(data: String, digest_size: T.nilable(Integer)).returns(String) }
|
79
|
-
def digest(data, digest_size: nil)
|
80
|
-
self.class.digest(data, digest_size: digest_size || digest_bytes)
|
81
|
-
end
|
82
|
-
|
83
|
-
sig(:final) { returns(Integer) }
|
84
|
-
def digest_bytes
|
85
|
-
self.class.digest_bytes
|
86
|
-
end
|
87
|
-
|
88
|
-
sig(:final) { params(data: String, key: String, digest_size: T.nilable(Integer)).returns(String) }
|
89
|
-
def hmac(data, key:, digest_size: nil)
|
90
|
-
self.class.hmac(data, key: key, digest_size: digest_size || digest_bytes)
|
91
|
-
end
|
92
|
-
|
93
|
-
sig(:final) { returns(Interface::ID) }
|
94
|
-
def id
|
95
|
-
self.class.id
|
96
|
-
end
|
97
|
-
|
98
|
-
sig(:final) do
|
99
|
-
params(
|
29
|
+
sig do
|
30
|
+
abstract.params(
|
100
31
|
password: String,
|
101
32
|
salt: String,
|
102
33
|
length: Integer,
|
103
|
-
parameters:
|
34
|
+
parameters: Integer
|
104
35
|
).returns(String)
|
105
36
|
end
|
106
|
-
def kdf(password, salt:, length:, **parameters)
|
107
|
-
self.class.kdf(password, salt: salt, length: length, **parameters)
|
108
|
-
end
|
37
|
+
def kdf(password, salt:, length:, **parameters); end
|
109
38
|
|
110
|
-
sig
|
111
|
-
def paserk_version
|
112
|
-
self.class.paserk_version
|
113
|
-
end
|
39
|
+
sig { abstract.returns(String) }
|
40
|
+
def paserk_version; end
|
114
41
|
|
115
|
-
sig
|
116
|
-
def pbkd_local_header
|
117
|
-
self.class.pbkd_local_header
|
118
|
-
end
|
42
|
+
sig { abstract.returns(String) }
|
43
|
+
def pbkd_local_header; end
|
119
44
|
|
120
|
-
sig
|
121
|
-
def pbkd_secret_header
|
122
|
-
self.class.pbkd_secret_header
|
123
|
-
end
|
45
|
+
sig { abstract.returns(String) }
|
46
|
+
def pbkd_secret_header; end
|
124
47
|
|
125
|
-
sig
|
126
|
-
def pbkw(password)
|
127
|
-
self.class.pbkw(password)
|
128
|
-
end
|
48
|
+
sig { abstract.params(password: String).returns(Interface::PBKD) }
|
49
|
+
def pbkw(password); end
|
129
50
|
|
130
|
-
sig
|
131
|
-
def pie(key)
|
132
|
-
self.class.pie(key)
|
133
|
-
end
|
51
|
+
sig { abstract.params(key: SymmetricKey).returns(Interface::PIE) }
|
52
|
+
def pie(key); end
|
134
53
|
|
135
|
-
sig
|
136
|
-
def pke(key)
|
137
|
-
self.class.pke(key)
|
138
|
-
end
|
54
|
+
sig { abstract.params(key: AsymmetricKey).returns(Interface::PKE) }
|
55
|
+
def pke(key); end
|
139
56
|
|
140
|
-
sig
|
141
|
-
def random(size)
|
142
|
-
self.class.random(size)
|
143
|
-
end
|
57
|
+
sig { abstract.params(size: Integer).returns(String) }
|
58
|
+
def random(size); end
|
144
59
|
|
145
|
-
sig
|
146
|
-
def version
|
147
|
-
self.class.version
|
148
|
-
end
|
60
|
+
sig { abstract.returns(String) }
|
61
|
+
def version; end
|
149
62
|
|
150
63
|
sig(:final) { params(other: T.untyped).returns(T.nilable(Integer)) }
|
151
64
|
def <=>(other)
|
@@ -11,13 +11,12 @@ module Paseto
|
|
11
11
|
include Interface::PBKD
|
12
12
|
|
13
13
|
sig { override.returns(Protocol::Version3) }
|
14
|
-
|
15
|
-
Protocol::Version3.new
|
16
|
-
end
|
14
|
+
attr_reader :protocol
|
17
15
|
|
18
16
|
sig { params(password: String).void }
|
19
17
|
def initialize(password)
|
20
18
|
@password = password
|
19
|
+
@protocol = T.let(Protocol::Version3.instance, Protocol::Version3)
|
21
20
|
end
|
22
21
|
|
23
22
|
sig do
|
@@ -43,7 +42,7 @@ module Paseto
|
|
43
42
|
sig { override.params(salt: String, params: T::Hash[Symbol, Integer]).returns(String) }
|
44
43
|
def pre_key(salt:, params:)
|
45
44
|
iterations = T.must(params[:iterations])
|
46
|
-
protocol.kdf(@password, salt
|
45
|
+
protocol.kdf(@password, salt:, length: 32, iterations:)
|
47
46
|
end
|
48
47
|
|
49
48
|
sig { override.returns(String) }
|
@@ -76,7 +75,7 @@ module Paseto
|
|
76
75
|
nonce: T.must(data.byteslice(36, 16)),
|
77
76
|
edk: T.must(data.byteslice(52, edk_len)),
|
78
77
|
tag: T.must(data.byteslice(-48, 48)),
|
79
|
-
params: { iterations:
|
78
|
+
params: { iterations: }
|
80
79
|
}
|
81
80
|
end
|
82
81
|
end
|
@@ -11,13 +11,12 @@ module Paseto
|
|
11
11
|
include Interface::PBKD
|
12
12
|
|
13
13
|
sig { override.returns(Protocol::Version4) }
|
14
|
-
|
15
|
-
Protocol::Version4.new
|
16
|
-
end
|
14
|
+
attr_reader :protocol
|
17
15
|
|
18
16
|
sig { params(password: String).void }
|
19
17
|
def initialize(password)
|
20
18
|
@password = password
|
19
|
+
@protocol = T.let(Protocol::Version4.instance, Protocol::Version4)
|
21
20
|
end
|
22
21
|
|
23
22
|
sig do
|
@@ -49,7 +48,7 @@ module Paseto
|
|
49
48
|
def pre_key(salt:, params:)
|
50
49
|
opslimit = T.must(params[:opslimit])
|
51
50
|
memlimit = T.must(params[:memlimit])
|
52
|
-
protocol.kdf(@password, salt
|
51
|
+
protocol.kdf(@password, salt:, length: 32, opslimit:, memlimit:)
|
53
52
|
end
|
54
53
|
|
55
54
|
sig { override.returns(String) }
|
@@ -30,11 +30,11 @@ module Paseto
|
|
30
30
|
salt = @coder.random_salt
|
31
31
|
nonce = @coder.random_nonce
|
32
32
|
|
33
|
-
pre_key = @coder.pre_key(salt
|
33
|
+
pre_key = @coder.pre_key(salt:, params: opts)
|
34
34
|
|
35
|
-
edk = @coder.crypt(payload: key.to_bytes, key: pre_key, nonce:
|
35
|
+
edk = @coder.crypt(payload: key.to_bytes, key: pre_key, nonce:)
|
36
36
|
|
37
|
-
message, t = @coder.authenticate(header: h, pre_key
|
37
|
+
message, t = @coder.authenticate(header: h, pre_key:, salt:, nonce:, edk:, params: opts)
|
38
38
|
|
39
39
|
data = Util.encode64("#{message}#{t}")
|
40
40
|
"#{h}.#{data}"
|
@@ -49,12 +49,12 @@ module Paseto
|
|
49
49
|
|
50
50
|
@coder.decode(data) => {salt:, nonce:, edk:, tag:, params:}
|
51
51
|
|
52
|
-
pre_key = @coder.pre_key(salt
|
52
|
+
pre_key = @coder.pre_key(salt:, params:)
|
53
53
|
|
54
|
-
_, t2 = @coder.authenticate(header
|
54
|
+
_, t2 = @coder.authenticate(header:, pre_key:, salt:, nonce:, edk:, params:)
|
55
55
|
raise InvalidAuthenticator unless Util.constant_compare(t2, tag)
|
56
56
|
|
57
|
-
ptk = @coder.crypt(payload: edk, key: pre_key, nonce:
|
57
|
+
ptk = @coder.crypt(payload: edk, key: pre_key, nonce:)
|
58
58
|
PaserkTypes.deserialize(header).generate(ptk)
|
59
59
|
end
|
60
60
|
|
@@ -10,28 +10,24 @@ module Paseto
|
|
10
10
|
|
11
11
|
include Interface::PKE
|
12
12
|
|
13
|
-
sig { override.
|
14
|
-
|
15
|
-
esk.public_key.to_octet_string(:compressed)
|
16
|
-
end
|
13
|
+
sig { override.returns(Protocol::Version3) }
|
14
|
+
attr_reader :protocol
|
17
15
|
|
18
|
-
sig
|
19
|
-
|
20
|
-
OpenSSL::PKey::EC.generate('secp384r1')
|
21
|
-
end
|
16
|
+
sig { override.returns(String) }
|
17
|
+
attr_reader :header
|
22
18
|
|
23
|
-
sig
|
24
|
-
def
|
25
|
-
|
26
|
-
end
|
19
|
+
sig { params(sealing_key: AsymmetricKey).void }
|
20
|
+
def initialize(sealing_key)
|
21
|
+
raise LucidityError unless sealing_key.is_a? V3::Public
|
27
22
|
|
28
|
-
|
29
|
-
|
30
|
-
|
23
|
+
@header = T.let('k3.seal.', String)
|
24
|
+
@protocol = T.let(Protocol::Version3.instance, Protocol::Version3)
|
25
|
+
@sealing_key = T.let(sealing_key, V3::Public)
|
26
|
+
@pk = T.let(@sealing_key.public_bytes, String)
|
31
27
|
end
|
32
28
|
|
33
29
|
sig { override.params(encoded_data: String).returns([String, OpenSSL::PKey::EC::Point, String]) }
|
34
|
-
def
|
30
|
+
def split(encoded_data)
|
35
31
|
data = Util.decode64(encoded_data)
|
36
32
|
|
37
33
|
t = T.must(data.slice(0, 48))
|
@@ -44,14 +40,6 @@ module Paseto
|
|
44
40
|
[t, epk, edk]
|
45
41
|
end
|
46
42
|
|
47
|
-
sig { params(sealing_key: AsymmetricKey).void }
|
48
|
-
def initialize(sealing_key)
|
49
|
-
raise LucidityError unless sealing_key.is_a? V3::Public
|
50
|
-
|
51
|
-
@sealing_key = T.let(sealing_key, V3::Public)
|
52
|
-
@pk = T.let(@sealing_key.public_bytes, String)
|
53
|
-
end
|
54
|
-
|
55
43
|
sig { override.params(message: String, ek: String, n: String).returns(SymmetricKey) }
|
56
44
|
def decrypt(message:, ek:, n:)
|
57
45
|
pdk = protocol.crypt(key: ek, nonce: n, payload: message)
|
@@ -67,7 +55,7 @@ module Paseto
|
|
67
55
|
ek = T.must(x[0, 32])
|
68
56
|
n = T.must(x[32, 16])
|
69
57
|
|
70
|
-
{ ek
|
58
|
+
{ ek:, n: }
|
71
59
|
end
|
72
60
|
|
73
61
|
sig { override.params(xk: String, epk: OpenSSL::PKey::EC::Point).returns(String) }
|
@@ -81,6 +69,16 @@ module Paseto
|
|
81
69
|
protocol.crypt(payload: message, key: ek, nonce: n)
|
82
70
|
end
|
83
71
|
|
72
|
+
sig { override.params(esk: OpenSSL::PKey::EC).returns(String) }
|
73
|
+
def epk_bytes_from_esk(esk)
|
74
|
+
esk.public_key.to_octet_string(:compressed)
|
75
|
+
end
|
76
|
+
|
77
|
+
sig(:final) { override.returns(OpenSSL::PKey::EC) }
|
78
|
+
def generate_ephemeral_key
|
79
|
+
OpenSSL::PKey::EC.generate('secp384r1')
|
80
|
+
end
|
81
|
+
|
84
82
|
sig { override.params(ak: String, epk: OpenSSL::PKey::EC::Point, edk: String).returns(String) }
|
85
83
|
def tag(ak:, epk:, edk:)
|
86
84
|
epk_bytes = epk.to_octet_string(:compressed)
|
@@ -10,44 +10,18 @@ module Paseto
|
|
10
10
|
|
11
11
|
include Interface::PKE
|
12
12
|
|
13
|
-
sig { override.
|
14
|
-
|
15
|
-
esk.public_key.to_bytes
|
16
|
-
end
|
17
|
-
|
18
|
-
sig(:final) { override.returns(RbNaCl::PrivateKey) }
|
19
|
-
def self.generate_ephemeral_key
|
20
|
-
RbNaCl::PrivateKey.generate
|
21
|
-
end
|
22
|
-
|
23
|
-
sig(:final) { override.returns(String) }
|
24
|
-
def self.header
|
25
|
-
'k4.seal.'
|
26
|
-
end
|
13
|
+
sig { override.returns(String) }
|
14
|
+
attr_reader :header
|
27
15
|
|
28
16
|
sig { override.returns(Protocol::Version4) }
|
29
|
-
|
30
|
-
Protocol::Version4.new
|
31
|
-
end
|
32
|
-
|
33
|
-
sig { override.params(encoded_data: String).returns([String, RbNaCl::PublicKey, String]) }
|
34
|
-
def self.split(encoded_data)
|
35
|
-
data = Util.decode64(encoded_data)
|
36
|
-
|
37
|
-
t = T.must(data.slice(0, 32))
|
38
|
-
|
39
|
-
epk_bytes = T.must(data.slice(32, 32))
|
40
|
-
epk = RbNaCl::PublicKey.new(epk_bytes)
|
41
|
-
|
42
|
-
edk = T.must(data.slice(64, 32))
|
43
|
-
|
44
|
-
[t, epk, edk]
|
45
|
-
end
|
17
|
+
attr_reader :protocol
|
46
18
|
|
47
19
|
sig { params(sealing_key: AsymmetricKey).void }
|
48
20
|
def initialize(sealing_key)
|
49
21
|
raise LucidityError unless sealing_key.is_a? V4::Public
|
50
22
|
|
23
|
+
@header = T.let('k4.seal.', String)
|
24
|
+
@protocol = T.let(Protocol::Version4.instance, Protocol::Version4)
|
51
25
|
@sealing_key = T.let(sealing_key, V4::Public)
|
52
26
|
@pk = T.let(@sealing_key.x25519_public_key, RbNaCl::PublicKey)
|
53
27
|
@pk_bytes = T.let(@pk.to_bytes, String)
|
@@ -61,13 +35,14 @@ module Paseto
|
|
61
35
|
|
62
36
|
sig { override.params(xk: String, epk: RbNaCl::PublicKey).returns({ ek: String, n: String }) }
|
63
37
|
def derive_ek_n(xk:, epk:)
|
38
|
+
epk_bytes = epk.to_bytes
|
64
39
|
ek = protocol.digest(
|
65
|
-
"#{DOMAIN_SEPARATOR_ENCRYPT}#{header}#{xk}#{
|
40
|
+
"#{DOMAIN_SEPARATOR_ENCRYPT}#{header}#{xk}#{epk_bytes}#{@pk_bytes}",
|
66
41
|
digest_size: 32
|
67
42
|
)
|
68
|
-
n = protocol.digest("#{
|
43
|
+
n = protocol.digest("#{epk_bytes}#{@pk_bytes}", digest_size: 24)
|
69
44
|
|
70
|
-
{ ek
|
45
|
+
{ ek:, n: }
|
71
46
|
end
|
72
47
|
|
73
48
|
sig { override.params(xk: String, epk: RbNaCl::PublicKey).returns(String) }
|
@@ -80,6 +55,30 @@ module Paseto
|
|
80
55
|
protocol.crypt(payload: message, key: ek, nonce: n)
|
81
56
|
end
|
82
57
|
|
58
|
+
sig { override.params(esk: RbNaCl::PrivateKey).returns(String) }
|
59
|
+
def epk_bytes_from_esk(esk)
|
60
|
+
esk.public_key.to_bytes
|
61
|
+
end
|
62
|
+
|
63
|
+
sig(:final) { override.returns(RbNaCl::PrivateKey) }
|
64
|
+
def generate_ephemeral_key
|
65
|
+
RbNaCl::PrivateKey.generate
|
66
|
+
end
|
67
|
+
|
68
|
+
sig { override.params(encoded_data: String).returns([String, RbNaCl::PublicKey, String]) }
|
69
|
+
def split(encoded_data)
|
70
|
+
data = Util.decode64(encoded_data)
|
71
|
+
|
72
|
+
t = T.must(data.slice(0, 32))
|
73
|
+
|
74
|
+
epk_bytes = T.must(data.slice(32, 32))
|
75
|
+
epk = RbNaCl::PublicKey.new(epk_bytes)
|
76
|
+
|
77
|
+
edk = T.must(data.slice(64, 32))
|
78
|
+
|
79
|
+
[t, epk, edk]
|
80
|
+
end
|
81
|
+
|
83
82
|
sig { override.params(ak: String, epk: RbNaCl::PublicKey, edk: String).returns(String) }
|
84
83
|
def tag(ak:, epk:, edk:)
|
85
84
|
protocol.hmac("#{header}#{epk.to_bytes}#{edk}", key: ak, digest_size: 32)
|
@@ -22,12 +22,12 @@ module Paseto
|
|
22
22
|
|
23
23
|
xk = @sealing_key.ecdh(esk)
|
24
24
|
|
25
|
-
@coder.derive_ek_n(xk
|
25
|
+
@coder.derive_ek_n(xk:, epk:) => {ek:, n:}
|
26
26
|
|
27
|
-
edk = @coder.encrypt(message: key.to_bytes, ek
|
27
|
+
edk = @coder.encrypt(message: key.to_bytes, ek:, n:)
|
28
28
|
|
29
|
-
ak = @coder.derive_ak(xk
|
30
|
-
t = @coder.tag(ak
|
29
|
+
ak = @coder.derive_ak(xk:, epk:)
|
30
|
+
t = @coder.tag(ak:, epk:, edk:)
|
31
31
|
|
32
32
|
epk_bytes = @coder.epk_bytes_from_esk(esk)
|
33
33
|
data = Util.encode64("#{t}#{epk_bytes}#{edk}")
|
@@ -37,20 +37,19 @@ module Paseto
|
|
37
37
|
sig { params(paserk: String).returns(Interface::Key) }
|
38
38
|
def unseal(paserk)
|
39
39
|
paserk.split('.') => [version, type, encoded_data]
|
40
|
-
raise LucidityError unless version == @sealing_key.paserk_version
|
41
|
-
raise LucidityError unless type == 'seal'
|
40
|
+
raise LucidityError unless version == @sealing_key.paserk_version && type == 'seal'
|
42
41
|
|
43
42
|
t, epk, edk = @coder.split(encoded_data)
|
44
43
|
|
45
44
|
xk = @sealing_key.ecdh(epk)
|
46
45
|
|
47
|
-
ak = @coder.derive_ak(xk
|
48
|
-
t2 = @coder.tag(ak
|
46
|
+
ak = @coder.derive_ak(xk:, epk:)
|
47
|
+
t2 = @coder.tag(ak:, epk:, edk:)
|
49
48
|
raise InvalidAuthenticator unless Util.constant_compare(t, t2)
|
50
49
|
|
51
|
-
@coder.derive_ek_n(xk
|
50
|
+
@coder.derive_ek_n(xk:, epk:) => {ek:, n:}
|
52
51
|
|
53
|
-
@coder.decrypt(message: edk, ek
|
52
|
+
@coder.decrypt(message: edk, ek:, n:)
|
54
53
|
end
|
55
54
|
end
|
56
55
|
end
|
@@ -22,7 +22,7 @@ module Paseto
|
|
22
22
|
|
23
23
|
sig { params(key: Interface::Key, wrapping_key: SymmetricKey, nonce: T.nilable(String)).returns(String) }
|
24
24
|
def self.wrap(key, wrapping_key:, nonce: nil)
|
25
|
-
Wrappers::PIE.new(wrapping_key).encode(key, nonce:
|
25
|
+
Wrappers::PIE.new(wrapping_key).encode(key, nonce:)
|
26
26
|
end
|
27
27
|
end
|
28
28
|
end
|
data/lib/paseto/paserk.rb
CHANGED
@@ -39,7 +39,7 @@ module Paseto
|
|
39
39
|
|
40
40
|
sig { params(key: Interface::Key, wrapping_key: SymmetricKey, nonce: T.nilable(String)).returns(String) }
|
41
41
|
def self.wrap(key:, wrapping_key:, nonce: nil)
|
42
|
-
Operations::Wrap.wrap(key, wrapping_key
|
42
|
+
Operations::Wrap.wrap(key, wrapping_key:, nonce:)
|
43
43
|
end
|
44
44
|
|
45
45
|
sig { params(key: Interface::Key, password: String, options: T::Hash[Symbol, T.any(Integer, Symbol)]).returns(String) }
|
data/lib/paseto/paserk_types.rb
CHANGED
@@ -32,9 +32,9 @@ module Paseto
|
|
32
32
|
V3::Public.from_scalar_bytes(input)
|
33
33
|
in K3Public
|
34
34
|
V3::Public.from_public_bytes(input)
|
35
|
-
in K4LocalWrap | K4LocalPBKW | K4Local if Paseto
|
35
|
+
in K4LocalWrap | K4LocalPBKW | K4Local if Paseto::HAS_RBNACL && input.bytesize == 32
|
36
36
|
V4::Local.new(ikm: input)
|
37
|
-
in K4SecretWrap | K4SecretPBKW | K4Secret if Paseto
|
37
|
+
in K4SecretWrap | K4SecretPBKW | K4Secret if Paseto::HAS_RBNACL && input.bytesize == 64
|
38
38
|
V4::Public.from_keypair(input)
|
39
39
|
in K4Public
|
40
40
|
V4::Public.from_public_bytes(input)
|
@@ -8,10 +8,11 @@ module Paseto
|
|
8
8
|
extend T::Sig
|
9
9
|
extend T::Helpers
|
10
10
|
|
11
|
+
include Singleton
|
11
12
|
include Interface::Version
|
12
13
|
|
13
14
|
sig(:final) { override.params(key: String, nonce: String, payload: String).returns(String) }
|
14
|
-
def
|
15
|
+
def crypt(key:, nonce:, payload:)
|
15
16
|
cipher = OpenSSL::Cipher.new('aes-256-ctr')
|
16
17
|
cipher.key = key
|
17
18
|
cipher.iv = nonce
|
@@ -19,22 +20,22 @@ module Paseto
|
|
19
20
|
end
|
20
21
|
|
21
22
|
sig(:final) { override.params(data: String, digest_size: Integer).returns(String) }
|
22
|
-
def
|
23
|
+
def digest(data, digest_size: 48)
|
23
24
|
T.must(OpenSSL::Digest.digest('SHA384', data).byteslice(0, digest_size))
|
24
25
|
end
|
25
26
|
|
26
27
|
sig(:final) { override.returns(Integer) }
|
27
|
-
def
|
28
|
+
def digest_bytes
|
28
29
|
48
|
29
30
|
end
|
30
31
|
|
31
32
|
sig(:final) { override.params(data: String, key: String, digest_size: Integer).returns(String) }
|
32
|
-
def
|
33
|
+
def hmac(data, key:, digest_size: 48)
|
33
34
|
T.must(OpenSSL::HMAC.digest('SHA384', key, data).byteslice(0, digest_size))
|
34
35
|
end
|
35
36
|
|
36
37
|
sig(:final) { override.returns(T.class_of(Operations::ID::IDv3)) }
|
37
|
-
def
|
38
|
+
def id
|
38
39
|
Operations::ID::IDv3
|
39
40
|
end
|
40
41
|
|
@@ -46,53 +47,53 @@ module Paseto
|
|
46
47
|
parameters: Integer
|
47
48
|
).returns(String)
|
48
49
|
end
|
49
|
-
def
|
50
|
+
def kdf(password, salt:, length:, **parameters)
|
50
51
|
OpenSSL::KDF.pbkdf2_hmac(
|
51
52
|
password,
|
52
|
-
salt
|
53
|
-
length
|
53
|
+
salt:,
|
54
|
+
length:,
|
54
55
|
iterations: T.must(parameters[:iterations]),
|
55
56
|
hash: 'SHA384'
|
56
57
|
)
|
57
58
|
end
|
58
59
|
|
59
60
|
sig(:final) { override.returns(String) }
|
60
|
-
def
|
61
|
+
def paserk_version
|
61
62
|
'k3'
|
62
63
|
end
|
63
64
|
|
64
65
|
sig(:final) { override.returns(String) }
|
65
|
-
def
|
66
|
+
def pbkd_local_header
|
66
67
|
'k3.local-pw'
|
67
68
|
end
|
68
69
|
|
69
70
|
sig(:final) { override.returns(String) }
|
70
|
-
def
|
71
|
+
def pbkd_secret_header
|
71
72
|
'k3.secret-pw'
|
72
73
|
end
|
73
74
|
|
74
75
|
sig(:final) { override.params(password: String).returns(Operations::PBKD::PBKDv3) }
|
75
|
-
def
|
76
|
+
def pbkw(password)
|
76
77
|
Operations::PBKD::PBKDv3.new(password)
|
77
78
|
end
|
78
79
|
|
79
80
|
sig(:final) { override.params(key: SymmetricKey).returns(Wrappers::PIE::PieV3) }
|
80
|
-
def
|
81
|
+
def pie(key)
|
81
82
|
Wrappers::PIE::PieV3.new(key)
|
82
83
|
end
|
83
84
|
|
84
85
|
sig(:final) { override.params(key: AsymmetricKey).returns(Operations::PKE::PKEv3) }
|
85
|
-
def
|
86
|
+
def pke(key)
|
86
87
|
Operations::PKE::PKEv3.new(key)
|
87
88
|
end
|
88
89
|
|
89
90
|
sig(:final) { override.params(size: Integer).returns(String) }
|
90
|
-
def
|
91
|
+
def random(size)
|
91
92
|
SecureRandom.random_bytes(size)
|
92
93
|
end
|
93
94
|
|
94
95
|
sig(:final) { override.returns(String) }
|
95
|
-
def
|
96
|
+
def version
|
96
97
|
'v3'
|
97
98
|
end
|
98
99
|
end
|