jose 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|