jose 0.1.0 → 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/.ruby-version +1 -1
- data/.travis.yml +11 -2
- data/CHANGELOG.md +69 -0
- data/README.md +5 -3
- data/jose.gemspec +3 -2
- data/lib/jose.rb +44 -6
- data/lib/jose/jwa.rb +23 -0
- data/lib/jose/jwa/curve25519.rb +102 -0
- data/lib/jose/jwa/curve25519_rbnacl.rb +67 -0
- data/lib/jose/jwa/curve25519_ruby.rb +54 -0
- data/lib/jose/jwa/curve25519_unsupported.rb +52 -0
- data/lib/jose/jwa/curve448.rb +99 -0
- data/lib/jose/jwa/curve448_ruby.rb +54 -0
- data/lib/jose/jwa/curve448_unsupported.rb +52 -0
- data/lib/jose/jwa/ed25519.rb +117 -0
- data/lib/jose/jwa/ed25519_rbnacl.rb +36 -0
- data/lib/jose/jwa/ed448.rb +166 -0
- data/lib/jose/jwa/edwards_point.rb +257 -0
- data/lib/jose/jwa/field_element.rb +161 -0
- data/lib/jose/jwa/sha3.rb +150 -0
- data/lib/jose/jwa/x25519.rb +188 -0
- data/lib/jose/jwa/x25519_rbnacl.rb +35 -0
- data/lib/jose/jwa/x448.rb +188 -0
- data/lib/jose/jwk.rb +74 -0
- data/lib/jose/jwk/kty.rb +6 -0
- data/lib/jose/jwk/kty_okp_ed25519.rb +112 -0
- data/lib/jose/jwk/kty_okp_ed25519ph.rb +112 -0
- data/lib/jose/jwk/kty_okp_ed448.rb +121 -0
- data/lib/jose/jwk/kty_okp_ed448ph.rb +121 -0
- data/lib/jose/jwk/kty_okp_x25519.rb +120 -0
- data/lib/jose/jwk/kty_okp_x448.rb +120 -0
- data/lib/jose/jws.rb +4 -0
- data/lib/jose/jws/alg.rb +1 -0
- data/lib/jose/jws/alg_eddsa.rb +35 -0
- data/lib/jose/version.rb +1 -1
- metadata +45 -7
@@ -0,0 +1,188 @@
|
|
1
|
+
module JOSE::JWA::X25519
|
2
|
+
|
3
|
+
extend self
|
4
|
+
|
5
|
+
C_p = ((2 ** 255) - 19).to_bn.freeze
|
6
|
+
C_A = 486662.to_bn.freeze
|
7
|
+
C_order = ((2 ** 252) + 0x14def9dea2f79cd65812631a5cf5d3ed).to_bn.freeze
|
8
|
+
C_cofactor = 8.to_bn.freeze
|
9
|
+
C_u = 9.to_bn.freeze
|
10
|
+
C_v = 14781619447589544791020593568409986887264606134616475288964881837755586237401.to_bn.freeze
|
11
|
+
C_bits = 256.to_bn.freeze
|
12
|
+
C_bytes = ((C_bits + 7) / 8)[0].freeze
|
13
|
+
C_bit_steps = (C_bits-1).to_i.downto(0).to_a.freeze
|
14
|
+
C_byte_steps = (C_bytes-1).to_i.downto(0).to_a.freeze
|
15
|
+
C_a24 = ((C_A - 2) / 4)[0].freeze
|
16
|
+
C_scalarbytes = C_bytes
|
17
|
+
C_coordinatebytes = C_bytes
|
18
|
+
C_one = 1.to_bn.freeze
|
19
|
+
C_zero = 0.to_bn.freeze
|
20
|
+
C_F = JOSE::JWA::FieldElement.new(C_one, C_p).freeze
|
21
|
+
C_F_one = C_F
|
22
|
+
C_F_zero = C_F.make(C_zero).freeze
|
23
|
+
C_F_a24 = C_F.make(C_a24).freeze
|
24
|
+
|
25
|
+
def clamp_scalar(scalar)
|
26
|
+
scalar = coerce_coordinate_bytes!(scalar)
|
27
|
+
scalar.setbyte(0, scalar.getbyte(0) & 248)
|
28
|
+
scalar.setbyte(31, (scalar.getbyte(31) & 127) | 64)
|
29
|
+
return C_F.from_bytes(scalar, C_bits)
|
30
|
+
end
|
31
|
+
|
32
|
+
def cswap(swap, x_2, x_3)
|
33
|
+
iswap = (-swap.x.to_i) & 0xff
|
34
|
+
x_2 = x_2.to_bytes(C_bits)
|
35
|
+
x_3 = x_3.to_bytes(C_bits)
|
36
|
+
C_byte_steps.each do |i|
|
37
|
+
x_2i = x_2.getbyte(i)
|
38
|
+
x_3i = x_3.getbyte(i)
|
39
|
+
s = iswap & (x_2i ^ x_3i)
|
40
|
+
x_2.setbyte(i, x_2i ^ s)
|
41
|
+
x_3.setbyte(i, x_3i ^ s)
|
42
|
+
end
|
43
|
+
x_2 = C_F.from_bytes(x_2, C_bits)
|
44
|
+
x_3 = C_F.from_bytes(x_3, C_bits)
|
45
|
+
return x_2, x_3
|
46
|
+
end
|
47
|
+
|
48
|
+
def curve25519(k, u)
|
49
|
+
x_1 = u
|
50
|
+
x_2 = C_F_one
|
51
|
+
z_2 = C_F_zero
|
52
|
+
x_3 = u
|
53
|
+
z_3 = C_F_one
|
54
|
+
swap = C_F_zero
|
55
|
+
|
56
|
+
C_bit_steps.each do |t|
|
57
|
+
k_t = (k >> t) & 1
|
58
|
+
swap ^= k_t
|
59
|
+
x_2, x_3 = cswap(swap, x_2, x_3)
|
60
|
+
z_2, z_3 = cswap(swap, z_2, z_3)
|
61
|
+
swap = k_t
|
62
|
+
|
63
|
+
a = x_2 + z_2
|
64
|
+
aa = a.sqr
|
65
|
+
b = x_2 - z_2
|
66
|
+
bb = b.sqr
|
67
|
+
e = aa - bb
|
68
|
+
c = x_3 + z_3
|
69
|
+
d = x_3 - z_3
|
70
|
+
da = d * a
|
71
|
+
cb = c * b
|
72
|
+
x_3 = (da + cb).sqr
|
73
|
+
z_3 = x_1 * (da - cb).sqr
|
74
|
+
x_2 = aa * bb
|
75
|
+
z_2 = e * (aa + C_F_a24 * e)
|
76
|
+
end
|
77
|
+
|
78
|
+
x_2, x_3 = cswap(swap, x_2, x_3)
|
79
|
+
z_2, z_3 = cswap(swap, z_2, z_3)
|
80
|
+
|
81
|
+
return x_2 / z_2
|
82
|
+
end
|
83
|
+
|
84
|
+
def x25519(sk, pk)
|
85
|
+
u = coerce_coordinate_fe!(pk)
|
86
|
+
k = clamp_scalar(sk)
|
87
|
+
r = curve25519(k, u)
|
88
|
+
return r.to_bytes(C_bits)
|
89
|
+
end
|
90
|
+
|
91
|
+
def x25519_base(sk)
|
92
|
+
return x25519(sk, C_u)
|
93
|
+
end
|
94
|
+
|
95
|
+
def keypair(sk = nil)
|
96
|
+
sk ||= SecureRandom.random_bytes(C_bytes)
|
97
|
+
sk = clamp_scalar(sk)
|
98
|
+
pk = sk_to_pk(sk)
|
99
|
+
return pk, sk.to_bytes(C_bits)
|
100
|
+
end
|
101
|
+
|
102
|
+
def shared_secret(pk, sk)
|
103
|
+
return x25519(sk, pk)
|
104
|
+
end
|
105
|
+
|
106
|
+
def sk_to_pk(sk)
|
107
|
+
return x25519_base(sk)
|
108
|
+
end
|
109
|
+
|
110
|
+
def coerce_coordinate_bn!(coordinate)
|
111
|
+
raise ArgumentError, "coordinate size must be #{C_coordinatebytes} bytes" if not valid_coordinate?(coordinate)
|
112
|
+
coordinate = coordinate.value if coordinate.is_a?(JOSE::JWA::FieldElement)
|
113
|
+
coordinate = coordinate.to_bn if not coordinate.is_a?(OpenSSL::BN) and coordinate.respond_to?(:to_bn)
|
114
|
+
coordinate = OpenSSL::BN.new(coordinate.reverse, 2) if coordinate.respond_to?(:bytesize)
|
115
|
+
return coordinate
|
116
|
+
end
|
117
|
+
|
118
|
+
def coerce_scalar_bn!(scalar)
|
119
|
+
raise ArgumentError, "scalar size must be #{C_scalarbytes} bytes" if not valid_scalar?(scalar)
|
120
|
+
scalar = scalar.value if scalar.is_a?(JOSE::JWA::FieldElement)
|
121
|
+
scalar = scalar.to_bn if not scalar.is_a?(OpenSSL::BN) and scalar.respond_to?(:to_bn)
|
122
|
+
scalar = OpenSSL::BN.new(scalar.reverse, 2) if scalar.respond_to?(:bytesize)
|
123
|
+
return scalar
|
124
|
+
end
|
125
|
+
|
126
|
+
def coerce_coordinate_bytes!(coordinate)
|
127
|
+
raise ArgumentError, "coordinate size must be #{C_coordinatebytes} bytes" if not valid_coordinate?(coordinate)
|
128
|
+
coordinate = coordinate.to_bytes(C_bits) if coordinate.is_a?(JOSE::JWA::FieldElement)
|
129
|
+
coordinate = coordinate.to_bn if not coordinate.is_a?(OpenSSL::BN) and coordinate.respond_to?(:to_bn)
|
130
|
+
coordinate = coordinate.to_s(2).rjust(C_bytes, JOSE::JWA::ZERO_PAD).reverse if coordinate.is_a?(OpenSSL::BN)
|
131
|
+
return coordinate
|
132
|
+
end
|
133
|
+
|
134
|
+
def coerce_scalar_bytes!(scalar)
|
135
|
+
raise ArgumentError, "scalar size must be #{C_scalarbytes} bytes" if not valid_scalar?(scalar)
|
136
|
+
scalar = scalar.to_bytes(C_bits) if scalar.is_a?(JOSE::JWA::FieldElement)
|
137
|
+
scalar = scalar.to_bn if not scalar.is_a?(OpenSSL::BN) and scalar.respond_to?(:to_bn)
|
138
|
+
scalar = scalar.to_s(2).rjust(C_bytes, JOSE::JWA::ZERO_PAD).reverse if scalar.is_a?(OpenSSL::BN)
|
139
|
+
return scalar
|
140
|
+
end
|
141
|
+
|
142
|
+
def coerce_coordinate_fe!(coordinate)
|
143
|
+
return coordinate if coordinate.is_a?(JOSE::JWA::FieldElement) and coordinate.p == C_p
|
144
|
+
coordinate = coerce_coordinate_bn!(coordinate)
|
145
|
+
return C_F.make(coordinate)
|
146
|
+
end
|
147
|
+
|
148
|
+
def coerce_scalar_fe!(scalar)
|
149
|
+
return scalar if scalar.is_a?(JOSE::JWA::FieldElement) and scalar.p == C_p
|
150
|
+
scalar = coerce_scalar_bn!(scalar)
|
151
|
+
return C_F.make(scalar)
|
152
|
+
end
|
153
|
+
|
154
|
+
def valid_coordinate?(coordinate)
|
155
|
+
return true if coordinate.is_a?(JOSE::JWA::FieldElement) and coordinate.p == C_p
|
156
|
+
if not coordinate.is_a?(OpenSSL::BN) and coordinate.respond_to?(:to_bn)
|
157
|
+
coordinate = coordinate.to_bn
|
158
|
+
end
|
159
|
+
ubytes = 0
|
160
|
+
if coordinate.is_a?(OpenSSL::BN)
|
161
|
+
if coordinate.num_bytes > C_coordinatebytes
|
162
|
+
ubytes = coordinate.num_bytes
|
163
|
+
else
|
164
|
+
ubytes = C_coordinatebytes
|
165
|
+
end
|
166
|
+
end
|
167
|
+
ubytes = coordinate.bytesize if coordinate.respond_to?(:bytesize)
|
168
|
+
return !!(ubytes == C_coordinatebytes)
|
169
|
+
end
|
170
|
+
|
171
|
+
def valid_scalar?(scalar)
|
172
|
+
return true if scalar.is_a?(JOSE::JWA::FieldElement) and scalar.p == C_p
|
173
|
+
if not scalar.is_a?(OpenSSL::BN) and scalar.respond_to?(:to_bn)
|
174
|
+
scalar = scalar.to_bn
|
175
|
+
end
|
176
|
+
kbytes = 0
|
177
|
+
if scalar.is_a?(OpenSSL::BN)
|
178
|
+
if scalar.num_bytes > C_scalarbytes
|
179
|
+
kbytes = scalar.num_bytes
|
180
|
+
else
|
181
|
+
kbytes = C_scalarbytes
|
182
|
+
end
|
183
|
+
end
|
184
|
+
kbytes = scalar.bytesize if scalar.respond_to?(:bytesize)
|
185
|
+
return !!(kbytes == C_scalarbytes)
|
186
|
+
end
|
187
|
+
|
188
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module JOSE::JWA::X25519_RbNaCl
|
2
|
+
|
3
|
+
extend self
|
4
|
+
|
5
|
+
def curve25519(k, u)
|
6
|
+
k = JOSE::JWA::X25519.coerce_scalar_bytes!(k) if not k.respond_to?(:bytesize)
|
7
|
+
u = RbNaCl::GroupElements::Curve25519.new(JOSE::JWA::X25519.coerce_coordinate_bytes!(u)) if not u.is_a?(RbNaCl::GroupElements::Curve25519)
|
8
|
+
return u.mult(k)
|
9
|
+
end
|
10
|
+
|
11
|
+
def x25519(sk, pk)
|
12
|
+
return curve25519(sk, pk).to_bytes
|
13
|
+
end
|
14
|
+
|
15
|
+
def x25519_base(sk)
|
16
|
+
sk = JOSE::JWA::X25519.coerce_scalar_bytes!(sk) if not sk.respond_to?(:bytesize)
|
17
|
+
return RbNaCl::GroupElements::Curve25519.base_point.mult(sk).to_bytes
|
18
|
+
end
|
19
|
+
|
20
|
+
def keypair(sk = nil)
|
21
|
+
sk ||= RbNaCl::Random.random_bytes(JOSE::JWA::X25519::C_bytes)
|
22
|
+
sk = JOSE::JWA::X25519.clamp_scalar(sk)
|
23
|
+
pk = sk_to_pk(sk)
|
24
|
+
return pk, sk.to_bytes(JOSE::JWA::X25519::C_bits)
|
25
|
+
end
|
26
|
+
|
27
|
+
def shared_secret(pk, sk)
|
28
|
+
return x25519(sk, pk)
|
29
|
+
end
|
30
|
+
|
31
|
+
def sk_to_pk(sk)
|
32
|
+
return x25519_base(sk)
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,188 @@
|
|
1
|
+
module JOSE::JWA::X448
|
2
|
+
|
3
|
+
extend self
|
4
|
+
|
5
|
+
C_p = ((2 ** 448) - (2 ** 224) - 1).to_bn.freeze
|
6
|
+
C_A = 156326.to_bn.freeze
|
7
|
+
C_order = ((2 ** 446) + 0x8335dc163bb124b65129c96fde933d8d723a70aadc873d6d54a7bb0d).to_bn.freeze
|
8
|
+
C_cofactor = 4.to_bn.freeze
|
9
|
+
C_u = 5.to_bn.freeze
|
10
|
+
C_v = 355293926785568175264127502063783334808976399387714271831880898435169088786967410002932673765864550910142774147268105838985595290606362.to_bn.freeze
|
11
|
+
C_bits = 448.to_bn.freeze
|
12
|
+
C_bytes = ((C_bits + 7) / 8)[0].freeze
|
13
|
+
C_bit_steps = (C_bits-1).to_i.downto(0).to_a.freeze
|
14
|
+
C_byte_steps = (C_bytes-1).to_i.downto(0).to_a.freeze
|
15
|
+
C_a24 = ((C_A - 2) / 4)[0].freeze
|
16
|
+
C_scalarbytes = C_bytes
|
17
|
+
C_coordinatebytes = C_bytes
|
18
|
+
C_one = 1.to_bn.freeze
|
19
|
+
C_zero = 0.to_bn.freeze
|
20
|
+
C_F = JOSE::JWA::FieldElement.new(C_one, C_p).freeze
|
21
|
+
C_F_one = C_F
|
22
|
+
C_F_zero = C_F.make(C_zero).freeze
|
23
|
+
C_F_a24 = C_F.make(C_a24).freeze
|
24
|
+
|
25
|
+
def clamp_scalar(scalar)
|
26
|
+
scalar = coerce_coordinate_bytes!(scalar)
|
27
|
+
scalar.setbyte(0, scalar.getbyte(0) & 252)
|
28
|
+
scalar.setbyte(55, scalar.getbyte(55) | 128)
|
29
|
+
return C_F.from_bytes(scalar, C_bits)
|
30
|
+
end
|
31
|
+
|
32
|
+
def cswap(swap, x_2, x_3)
|
33
|
+
iswap = (-swap.x.to_i) & 0xff
|
34
|
+
x_2 = x_2.to_bytes(C_bits)
|
35
|
+
x_3 = x_3.to_bytes(C_bits)
|
36
|
+
C_byte_steps.each do |i|
|
37
|
+
x_2i = x_2.getbyte(i)
|
38
|
+
x_3i = x_3.getbyte(i)
|
39
|
+
s = iswap & (x_2i ^ x_3i)
|
40
|
+
x_2.setbyte(i, x_2i ^ s)
|
41
|
+
x_3.setbyte(i, x_3i ^ s)
|
42
|
+
end
|
43
|
+
x_2 = C_F.from_bytes(x_2, C_bits)
|
44
|
+
x_3 = C_F.from_bytes(x_3, C_bits)
|
45
|
+
return x_2, x_3
|
46
|
+
end
|
47
|
+
|
48
|
+
def curve448(k, u)
|
49
|
+
x_1 = u
|
50
|
+
x_2 = C_F_one
|
51
|
+
z_2 = C_F_zero
|
52
|
+
x_3 = u
|
53
|
+
z_3 = C_F_one
|
54
|
+
swap = C_F_zero
|
55
|
+
|
56
|
+
C_bit_steps.each do |t|
|
57
|
+
k_t = (k >> t) & 1
|
58
|
+
swap ^= k_t
|
59
|
+
x_2, x_3 = cswap(swap, x_2, x_3)
|
60
|
+
z_2, z_3 = cswap(swap, z_2, z_3)
|
61
|
+
swap = k_t
|
62
|
+
|
63
|
+
a = x_2 + z_2
|
64
|
+
aa = a.sqr
|
65
|
+
b = x_2 - z_2
|
66
|
+
bb = b.sqr
|
67
|
+
e = aa - bb
|
68
|
+
c = x_3 + z_3
|
69
|
+
d = x_3 - z_3
|
70
|
+
da = d * a
|
71
|
+
cb = c * b
|
72
|
+
x_3 = (da + cb).sqr
|
73
|
+
z_3 = x_1 * (da - cb).sqr
|
74
|
+
x_2 = aa * bb
|
75
|
+
z_2 = e * (aa + C_F_a24 * e)
|
76
|
+
end
|
77
|
+
|
78
|
+
x_2, x_3 = cswap(swap, x_2, x_3)
|
79
|
+
z_2, z_3 = cswap(swap, z_2, z_3)
|
80
|
+
|
81
|
+
return x_2 / z_2
|
82
|
+
end
|
83
|
+
|
84
|
+
def x448(sk, pk)
|
85
|
+
u = coerce_coordinate_fe!(pk)
|
86
|
+
k = clamp_scalar(sk)
|
87
|
+
r = curve448(k, u)
|
88
|
+
return r.to_bytes(C_bits)
|
89
|
+
end
|
90
|
+
|
91
|
+
def x448_base(sk)
|
92
|
+
return x448(sk, C_u)
|
93
|
+
end
|
94
|
+
|
95
|
+
def keypair(sk = nil)
|
96
|
+
sk ||= SecureRandom.random_bytes(C_bytes)
|
97
|
+
sk = clamp_scalar(sk)
|
98
|
+
pk = sk_to_pk(sk)
|
99
|
+
return pk, sk.to_bytes(C_bits)
|
100
|
+
end
|
101
|
+
|
102
|
+
def shared_secret(pk, sk)
|
103
|
+
return x448(sk, pk)
|
104
|
+
end
|
105
|
+
|
106
|
+
def sk_to_pk(sk)
|
107
|
+
return x448_base(sk)
|
108
|
+
end
|
109
|
+
|
110
|
+
def coerce_coordinate_bn!(coordinate)
|
111
|
+
raise ArgumentError, "coordinate size must be #{C_coordinatebytes} bytes" if not valid_coordinate?(coordinate)
|
112
|
+
coordinate = coordinate.value if coordinate.is_a?(JOSE::JWA::FieldElement)
|
113
|
+
coordinate = coordinate.to_bn if not coordinate.is_a?(OpenSSL::BN) and coordinate.respond_to?(:to_bn)
|
114
|
+
coordinate = OpenSSL::BN.new(coordinate.reverse, 2) if coordinate.respond_to?(:bytesize)
|
115
|
+
return coordinate
|
116
|
+
end
|
117
|
+
|
118
|
+
def coerce_scalar_bn!(scalar)
|
119
|
+
raise ArgumentError, "scalar size must be #{C_scalarbytes} bytes" if not valid_scalar?(scalar)
|
120
|
+
scalar = scalar.value if scalar.is_a?(JOSE::JWA::FieldElement)
|
121
|
+
scalar = scalar.to_bn if not scalar.is_a?(OpenSSL::BN) and scalar.respond_to?(:to_bn)
|
122
|
+
scalar = OpenSSL::BN.new(scalar.reverse, 2) if scalar.respond_to?(:bytesize)
|
123
|
+
return scalar
|
124
|
+
end
|
125
|
+
|
126
|
+
def coerce_coordinate_bytes!(coordinate)
|
127
|
+
raise ArgumentError, "coordinate size must be #{C_coordinatebytes} bytes" if not valid_coordinate?(coordinate)
|
128
|
+
coordinate = coordinate.to_bytes(C_bits) if coordinate.is_a?(JOSE::JWA::FieldElement)
|
129
|
+
coordinate = coordinate.to_bn if not coordinate.is_a?(OpenSSL::BN) and coordinate.respond_to?(:to_bn)
|
130
|
+
coordinate = coordinate.to_s(2).rjust(C_bytes, JOSE::JWA::ZERO_PAD).reverse if coordinate.is_a?(OpenSSL::BN)
|
131
|
+
return coordinate
|
132
|
+
end
|
133
|
+
|
134
|
+
def coerce_scalar_bytes!(scalar)
|
135
|
+
raise ArgumentError, "scalar size must be #{C_scalarbytes} bytes" if not valid_scalar?(scalar)
|
136
|
+
scalar = scalar.to_bytes(C_bits) if scalar.is_a?(JOSE::JWA::FieldElement)
|
137
|
+
scalar = scalar.to_bn if not scalar.is_a?(OpenSSL::BN) and scalar.respond_to?(:to_bn)
|
138
|
+
scalar = scalar.to_s(2).rjust(C_bytes, JOSE::JWA::ZERO_PAD).reverse if scalar.is_a?(OpenSSL::BN)
|
139
|
+
return scalar
|
140
|
+
end
|
141
|
+
|
142
|
+
def coerce_coordinate_fe!(coordinate)
|
143
|
+
return coordinate if coordinate.is_a?(JOSE::JWA::FieldElement) and coordinate.p == C_p
|
144
|
+
coordinate = coerce_coordinate_bn!(coordinate)
|
145
|
+
return C_F.make(coordinate)
|
146
|
+
end
|
147
|
+
|
148
|
+
def coerce_scalar_fe!(scalar)
|
149
|
+
return scalar if scalar.is_a?(JOSE::JWA::FieldElement) and scalar.p == C_p
|
150
|
+
scalar = coerce_scalar_bn!(scalar)
|
151
|
+
return C_F.make(scalar)
|
152
|
+
end
|
153
|
+
|
154
|
+
def valid_coordinate?(coordinate)
|
155
|
+
return true if coordinate.is_a?(JOSE::JWA::FieldElement) and coordinate.p == C_p
|
156
|
+
if not coordinate.is_a?(OpenSSL::BN) and coordinate.respond_to?(:to_bn)
|
157
|
+
coordinate = coordinate.to_bn
|
158
|
+
end
|
159
|
+
ubytes = 0
|
160
|
+
if coordinate.is_a?(OpenSSL::BN)
|
161
|
+
if coordinate.num_bytes > C_coordinatebytes
|
162
|
+
ubytes = coordinate.num_bytes
|
163
|
+
else
|
164
|
+
ubytes = C_coordinatebytes
|
165
|
+
end
|
166
|
+
end
|
167
|
+
ubytes = coordinate.bytesize if coordinate.respond_to?(:bytesize)
|
168
|
+
return !!(ubytes == C_coordinatebytes)
|
169
|
+
end
|
170
|
+
|
171
|
+
def valid_scalar?(scalar)
|
172
|
+
return true if scalar.is_a?(JOSE::JWA::FieldElement) and scalar.p == C_p
|
173
|
+
if not scalar.is_a?(OpenSSL::BN) and scalar.respond_to?(:to_bn)
|
174
|
+
scalar = scalar.to_bn
|
175
|
+
end
|
176
|
+
kbytes = 0
|
177
|
+
if scalar.is_a?(OpenSSL::BN)
|
178
|
+
if scalar.num_bytes > C_scalarbytes
|
179
|
+
kbytes = scalar.num_bytes
|
180
|
+
else
|
181
|
+
kbytes = C_scalarbytes
|
182
|
+
end
|
183
|
+
end
|
184
|
+
kbytes = scalar.bytesize if scalar.respond_to?(:bytesize)
|
185
|
+
return !!(kbytes == C_scalarbytes)
|
186
|
+
end
|
187
|
+
|
188
|
+
end
|
data/lib/jose/jwk.rb
CHANGED
@@ -86,6 +86,27 @@ module JOSE
|
|
86
86
|
return from_oct(File.binread(file), modules)
|
87
87
|
end
|
88
88
|
|
89
|
+
def self.from_okp(object, modules = {})
|
90
|
+
raise ArgumentError, "object must be an Array of length 2" if not object.is_a?(Array) or object.length != 2
|
91
|
+
kty = modules[:kty] || case object[0]
|
92
|
+
when :Ed25519
|
93
|
+
JOSE::JWK::KTY_OKP_Ed25519
|
94
|
+
when :Ed25519ph
|
95
|
+
JOSE::JWK::KTY_OKP_Ed25519ph
|
96
|
+
when :Ed448
|
97
|
+
JOSE::JWK::KTY_OKP_Ed448
|
98
|
+
when :Ed448ph
|
99
|
+
JOSE::JWK::KTY_OKP_Ed448ph
|
100
|
+
when :X25519
|
101
|
+
JOSE::JWK::KTY_OKP_X25519
|
102
|
+
when :X448
|
103
|
+
JOSE::JWK::KTY_OKP_X448
|
104
|
+
else
|
105
|
+
raise ArgumentError, "unrecognized :okp object"
|
106
|
+
end
|
107
|
+
return JOSE::JWK.new(nil, *kty.from_okp(object))
|
108
|
+
end
|
109
|
+
|
89
110
|
# Encode API
|
90
111
|
|
91
112
|
def self.to_binary(jwk, key = nil, jwe = nil)
|
@@ -142,6 +163,14 @@ module JOSE
|
|
142
163
|
return kty.to_oct
|
143
164
|
end
|
144
165
|
|
166
|
+
def self.to_okp(jwk)
|
167
|
+
return from(jwk).to_okp
|
168
|
+
end
|
169
|
+
|
170
|
+
def to_okp
|
171
|
+
return kty.to_okp
|
172
|
+
end
|
173
|
+
|
145
174
|
def self.to_pem(jwk, password = nil)
|
146
175
|
return from(jwk).to_pem(password)
|
147
176
|
end
|
@@ -254,6 +283,23 @@ module JOSE
|
|
254
283
|
return JOSE::JWK.new(nil, *JOSE::JWK::KTY_EC.generate_key(params))
|
255
284
|
when :oct
|
256
285
|
return JOSE::JWK.new(nil, *JOSE::JWK::KTY_oct.generate_key(params))
|
286
|
+
when :okp
|
287
|
+
case params[1]
|
288
|
+
when :Ed25519
|
289
|
+
return JOSE::JWK.new(nil, *JOSE::JWK::KTY_OKP_Ed25519.generate_key(params))
|
290
|
+
when :Ed25519ph
|
291
|
+
return JOSE::JWK.new(nil, *JOSE::JWK::KTY_OKP_Ed25519ph.generate_key(params))
|
292
|
+
when :Ed448
|
293
|
+
return JOSE::JWK.new(nil, *JOSE::JWK::KTY_OKP_Ed448.generate_key(params))
|
294
|
+
when :Ed448ph
|
295
|
+
return JOSE::JWK.new(nil, *JOSE::JWK::KTY_OKP_Ed448ph.generate_key(params))
|
296
|
+
when :X25519
|
297
|
+
return JOSE::JWK.new(nil, *JOSE::JWK::KTY_OKP_X25519.generate_key(params))
|
298
|
+
when :X448
|
299
|
+
return JOSE::JWK.new(nil, *JOSE::JWK::KTY_OKP_X448.generate_key(params))
|
300
|
+
else
|
301
|
+
raise ArgumentError, "invalid :okp key generation params"
|
302
|
+
end
|
257
303
|
when :rsa
|
258
304
|
return JOSE::JWK.new(nil, *JOSE::JWK::KTY_RSA.generate_key(params))
|
259
305
|
else
|
@@ -272,6 +318,17 @@ module JOSE
|
|
272
318
|
return JOSE::JWK.new(nil, *kty.generate_key(fields))
|
273
319
|
end
|
274
320
|
|
321
|
+
def self.shared_secret(your_jwk, my_jwk)
|
322
|
+
return from(your_jwk).shared_secret(from(my_jwk))
|
323
|
+
end
|
324
|
+
|
325
|
+
def shared_secret(other_jwk)
|
326
|
+
other_jwk = from(other_jwk) if not other_jwk.is_a?(JOSE::JWK)
|
327
|
+
raise ArgumentError, "key types must match" if other_jwk.kty.class != kty.class
|
328
|
+
raise ArgumentError, "key type does not support shared secret computations" if not kty.respond_to?(:derive_key)
|
329
|
+
return kty.derive_key(other_jwk)
|
330
|
+
end
|
331
|
+
|
275
332
|
def self.sign(jwk, plain_text, jws = nil, header = nil)
|
276
333
|
return from(jwk).sign(plain_text, jws, header)
|
277
334
|
end
|
@@ -325,6 +382,23 @@ module JOSE
|
|
325
382
|
JOSE::JWK::KTY_EC
|
326
383
|
when 'oct'
|
327
384
|
JOSE::JWK::KTY_oct
|
385
|
+
when 'OKP'
|
386
|
+
case jwk.fields['crv']
|
387
|
+
when 'Ed25519'
|
388
|
+
JOSE::JWK::KTY_OKP_Ed25519
|
389
|
+
when 'Ed25519ph'
|
390
|
+
JOSE::JWK::KTY_OKP_Ed25519ph
|
391
|
+
when 'Ed448'
|
392
|
+
JOSE::JWK::KTY_OKP_Ed448
|
393
|
+
when 'Ed448ph'
|
394
|
+
JOSE::JWK::KTY_OKP_Ed448ph
|
395
|
+
when 'X25519'
|
396
|
+
JOSE::JWK::KTY_OKP_X25519
|
397
|
+
when 'X448'
|
398
|
+
JOSE::JWK::KTY_OKP_X448
|
399
|
+
else
|
400
|
+
raise ArgumentError, "unknown 'crv' for 'kty' of 'OKP': #{jwk.fields['crv'].inspect}"
|
401
|
+
end
|
328
402
|
when 'RSA'
|
329
403
|
JOSE::JWK::KTY_RSA
|
330
404
|
else
|