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.
data/lib/jose/jwk/kty.rb CHANGED
@@ -31,4 +31,10 @@ end
31
31
 
32
32
  require 'jose/jwk/kty_ec'
33
33
  require 'jose/jwk/kty_oct'
34
+ require 'jose/jwk/kty_okp_ed25519'
35
+ require 'jose/jwk/kty_okp_ed25519ph'
36
+ require 'jose/jwk/kty_okp_ed448'
37
+ require 'jose/jwk/kty_okp_ed448ph'
38
+ require 'jose/jwk/kty_okp_x25519'
39
+ require 'jose/jwk/kty_okp_x448'
34
40
  require 'jose/jwk/kty_rsa'
@@ -0,0 +1,112 @@
1
+ class JOSE::JWK::KTY_OKP_Ed25519 < Struct.new(:okp)
2
+
3
+ SECRET_BYTES = 32
4
+ PK_BYTES = 32
5
+ SK_BYTES = SECRET_BYTES + PK_BYTES
6
+
7
+ # JOSE::JWK callbacks
8
+
9
+ def self.from_map(fields)
10
+ if fields['kty'] == 'OKP' and fields['crv'] == 'Ed25519' and fields['x'].is_a?(String)
11
+ pk = JOSE.urlsafe_decode64(fields['x'])
12
+ secret = nil
13
+ if fields['d'].is_a?(String)
14
+ secret = JOSE.urlsafe_decode64(fields['d'])
15
+ end
16
+ if pk.bytesize == PK_BYTES and (secret.nil? or secret.bytesize == SECRET_BYTES)
17
+ if secret.nil?
18
+ return JOSE::JWK::KTY_OKP_Ed25519.new(pk), fields.except('kty', 'crv', 'x')
19
+ else
20
+ return JOSE::JWK::KTY_OKP_Ed25519.new(secret + pk), fields.except('kty', 'crv', 'x', 'd')
21
+ end
22
+ end
23
+ end
24
+ raise ArgumentError, "invalid 'OKP' crv 'Ed25519' JWK"
25
+ end
26
+
27
+ def to_key
28
+ return okp
29
+ end
30
+
31
+ def to_map(fields)
32
+ if okp.bytesize == SK_BYTES
33
+ secret, pk = okp[0, SECRET_BYTES], okp[SECRET_BYTES, SK_BYTES]
34
+ return fields.
35
+ put('crv', 'Ed25519').
36
+ put('d', JOSE.urlsafe_encode64(secret)).
37
+ put('kty', 'OKP').
38
+ put('x', JOSE.urlsafe_encode64(pk))
39
+ else
40
+ pk = okp
41
+ return fields.
42
+ put('crv', 'Ed25519').
43
+ put('kty', 'OKP').
44
+ put('x', JOSE.urlsafe_encode64(pk))
45
+ end
46
+ end
47
+
48
+ def to_public_map(fields)
49
+ return to_map(fields).except('d')
50
+ end
51
+
52
+ def to_thumbprint_map(fields)
53
+ return to_public_map(fields).slice('crv', 'kty', 'x')
54
+ end
55
+
56
+ # JOSE::JWK::KTY callbacks
57
+
58
+ def self.generate_key(okp_params)
59
+ secret = nil
60
+ if okp_params.is_a?(Array) and (okp_params.length == 2 or okp_params.length == 3) and okp_params[0] == :okp and okp_params[1] == :Ed25519
61
+ secret = okp_params[2] if okp_params.length == 3
62
+ elsif okp_params.is_a?(String)
63
+ secret = okp_params
64
+ end
65
+ if secret.nil? or (secret.is_a?(String) and secret.bytesize == SECRET_BYTES)
66
+ return from_okp([:Ed25519, JOSE::JWA::Curve25519.ed25519_keypair(secret)[1]])
67
+ else
68
+ raise ArgumentError, "'secret' must be nil or a String of #{SECRET_BYTES} bytes"
69
+ end
70
+ end
71
+
72
+ def generate_key(fields)
73
+ kty, other_fields = JOSE::JWK::KTY_OKP_Ed25519.generate_key([:okp, :Ed25519])
74
+ return kty, fields.delete('kid').merge(other_fields)
75
+ end
76
+
77
+ def key_encryptor(fields, key)
78
+ return JOSE::JWK::KTY.key_encryptor(self, fields, key)
79
+ end
80
+
81
+ def sign(message, digest_type)
82
+ raise ArgumentError, "'digest_type' must be :Ed25519" if digest_type != :Ed25519
83
+ raise NotImplementedError, "Ed25519 public key cannot be used for signing" if okp.bytesize != SK_BYTES
84
+ return JOSE::JWA::Curve25519.ed25519_sign(message, okp)
85
+ end
86
+
87
+ def signer(fields = nil, plain_text = nil)
88
+ return JOSE::Map['alg' => 'Ed25519']
89
+ end
90
+
91
+ def verify(message, digest_type, signature)
92
+ raise ArgumentError, "'digest_type' must be :Ed25519" if digest_type != :Ed25519
93
+ pk = okp
94
+ pk = JOSE::JWA::Curve25519.ed25519_secret_to_public(okp) if okp.bytesize == SK_BYTES
95
+ return JOSE::JWA::Curve25519.ed25519_verify(signature, message, pk)
96
+ end
97
+
98
+ # API functions
99
+
100
+ def self.from_okp(okp)
101
+ if okp.is_a?(Array) and okp.length == 2 and okp[0] == :Ed25519 and okp[1].is_a?(String) and (okp[1].bytesize == PK_BYTES or okp[1].bytesize == SK_BYTES)
102
+ return JOSE::JWK::KTY_OKP_Ed25519.new(okp[1]), JOSE::Map[]
103
+ else
104
+ raise ArgumentError, "'okp' must be an Array in the form of [:Ed25519, String]"
105
+ end
106
+ end
107
+
108
+ def to_okp
109
+ return [:Ed25519, okp]
110
+ end
111
+
112
+ end
@@ -0,0 +1,112 @@
1
+ class JOSE::JWK::KTY_OKP_Ed25519ph < Struct.new(:okp)
2
+
3
+ SECRET_BYTES = 32
4
+ PK_BYTES = 32
5
+ SK_BYTES = SECRET_BYTES + PK_BYTES
6
+
7
+ # JOSE::JWK callbacks
8
+
9
+ def self.from_map(fields)
10
+ if fields['kty'] == 'OKP' and fields['crv'] == 'Ed25519ph' and fields['x'].is_a?(String)
11
+ pk = JOSE.urlsafe_decode64(fields['x'])
12
+ secret = nil
13
+ if fields['d'].is_a?(String)
14
+ secret = JOSE.urlsafe_decode64(fields['d'])
15
+ end
16
+ if pk.bytesize == PK_BYTES and (secret.nil? or secret.bytesize == SECRET_BYTES)
17
+ if secret.nil?
18
+ return JOSE::JWK::KTY_OKP_Ed25519ph.new(pk), fields.except('kty', 'crv', 'x')
19
+ else
20
+ return JOSE::JWK::KTY_OKP_Ed25519ph.new(secret + pk), fields.except('kty', 'crv', 'x', 'd')
21
+ end
22
+ end
23
+ end
24
+ raise ArgumentError, "invalid 'OKP' crv 'Ed25519ph' JWK"
25
+ end
26
+
27
+ def to_key
28
+ return okp
29
+ end
30
+
31
+ def to_map(fields)
32
+ if okp.bytesize == SK_BYTES
33
+ secret, pk = okp[0, SECRET_BYTES], okp[SECRET_BYTES, SK_BYTES]
34
+ return fields.
35
+ put('crv', 'Ed25519ph').
36
+ put('d', JOSE.urlsafe_encode64(secret)).
37
+ put('kty', 'OKP').
38
+ put('x', JOSE.urlsafe_encode64(pk))
39
+ else
40
+ pk = okp
41
+ return fields.
42
+ put('crv', 'Ed25519ph').
43
+ put('kty', 'OKP').
44
+ put('x', JOSE.urlsafe_encode64(pk))
45
+ end
46
+ end
47
+
48
+ def to_public_map(fields)
49
+ return to_map(fields).except('d')
50
+ end
51
+
52
+ def to_thumbprint_map(fields)
53
+ return to_public_map(fields).slice('crv', 'kty', 'x')
54
+ end
55
+
56
+ # JOSE::JWK::KTY callbacks
57
+
58
+ def self.generate_key(okp_params)
59
+ secret = nil
60
+ if okp_params.is_a?(Array) and (okp_params.length == 2 or okp_params.length == 3) and okp_params[0] == :okp and okp_params[1] == :Ed25519ph
61
+ secret = okp_params[2] if okp_params.length == 3
62
+ elsif okp_params.is_a?(String)
63
+ secret = okp_params
64
+ end
65
+ if secret.nil? or (secret.is_a?(String) and secret.bytesize == SECRET_BYTES)
66
+ return from_okp([:Ed25519ph, JOSE::JWA::Curve25519.ed25519ph_keypair(secret)[1]])
67
+ else
68
+ raise ArgumentError, "'secret' must be nil or a String of #{SECRET_BYTES} bytes"
69
+ end
70
+ end
71
+
72
+ def generate_key(fields)
73
+ kty, other_fields = JOSE::JWK::KTY_OKP_Ed25519ph.generate_key([:okp, :Ed25519ph])
74
+ return kty, fields.delete('kid').merge(other_fields)
75
+ end
76
+
77
+ def key_encryptor(fields, key)
78
+ return JOSE::JWK::KTY.key_encryptor(self, fields, key)
79
+ end
80
+
81
+ def sign(message, sign_type)
82
+ raise ArgumentError, "'sign_type' must be :Ed25519ph" if sign_type != :Ed25519ph
83
+ raise NotImplementedError, "Ed25519ph public key cannot be used for signing" if okp.bytesize != SK_BYTES
84
+ return JOSE::JWA::Curve25519.ed25519ph_sign(message, okp)
85
+ end
86
+
87
+ def signer(fields = nil, plain_text = nil)
88
+ return JOSE::Map['alg' => 'Ed25519ph']
89
+ end
90
+
91
+ def verify(message, sign_type, signature)
92
+ raise ArgumentError, "'sign_type' must be :Ed25519ph" if sign_type != :Ed25519ph
93
+ pk = okp
94
+ pk = JOSE::JWA::Curve25519.ed25519ph_secret_to_public(okp) if okp.bytesize == SK_BYTES
95
+ return JOSE::JWA::Curve25519.ed25519ph_verify(signature, message, pk)
96
+ end
97
+
98
+ # API functions
99
+
100
+ def self.from_okp(okp)
101
+ if okp.is_a?(Array) and okp.length == 2 and okp[0] == :Ed25519ph and okp[1].is_a?(String) and (okp[1].bytesize == PK_BYTES or okp[1].bytesize == SK_BYTES)
102
+ return JOSE::JWK::KTY_OKP_Ed25519ph.new(okp[1]), JOSE::Map[]
103
+ else
104
+ raise ArgumentError, "'okp' must be an Array in the form of [:Ed25519ph, String]"
105
+ end
106
+ end
107
+
108
+ def to_okp
109
+ return [:Ed25519, okp]
110
+ end
111
+
112
+ end
@@ -0,0 +1,121 @@
1
+ class JOSE::JWK::KTY_OKP_Ed448 < Struct.new(:okp)
2
+
3
+ SECRET_BYTES = 57
4
+ LEGACY_SECRET_BYTES = 32
5
+ PK_BYTES = 57
6
+ SK_BYTES = SECRET_BYTES + PK_BYTES
7
+ LEGACY_SK_BYTES = LEGACY_SECRET_BYTES + PK_BYTES
8
+
9
+ # JOSE::JWK callbacks
10
+
11
+ def self.from_map(fields)
12
+ if fields['kty'] == 'OKP' and fields['crv'] == 'Ed448' and fields['x'].is_a?(String)
13
+ pk = JOSE.urlsafe_decode64(fields['x'])
14
+ secret = nil
15
+ if fields['d'].is_a?(String)
16
+ secret = JOSE.urlsafe_decode64(fields['d'])
17
+ end
18
+ if pk.bytesize == PK_BYTES and (secret.nil? or secret.bytesize == SECRET_BYTES or secret.bytesize == LEGACY_SECRET_BYTES)
19
+ if secret.nil?
20
+ return JOSE::JWK::KTY_OKP_Ed448.new(pk), fields.except('kty', 'crv', 'x')
21
+ else
22
+ return JOSE::JWK::KTY_OKP_Ed448.new(secret + pk), fields.except('kty', 'crv', 'x', 'd')
23
+ end
24
+ end
25
+ end
26
+ raise ArgumentError, "invalid 'OKP' crv 'Ed448' JWK"
27
+ end
28
+
29
+ def to_key
30
+ return okp
31
+ end
32
+
33
+ def to_map(fields)
34
+ if okp.bytesize == SK_BYTES
35
+ secret, pk = okp[0, SECRET_BYTES], okp[SECRET_BYTES, SK_BYTES]
36
+ return fields.
37
+ put('crv', 'Ed448').
38
+ put('d', JOSE.urlsafe_encode64(secret)).
39
+ put('kty', 'OKP').
40
+ put('x', JOSE.urlsafe_encode64(pk))
41
+ elsif okp.bytesize == LEGACY_SK_BYTES
42
+ secret, pk = okp[0, LEGACY_SECRET_BYTES], okp[LEGACY_SECRET_BYTES, LEGACY_SK_BYTES]
43
+ return fields.
44
+ put('crv', 'Ed448').
45
+ put('d', JOSE.urlsafe_encode64(secret)).
46
+ put('kty', 'OKP').
47
+ put('x', JOSE.urlsafe_encode64(pk))
48
+ else
49
+ pk = okp
50
+ return fields.
51
+ put('crv', 'Ed448').
52
+ put('kty', 'OKP').
53
+ put('x', JOSE.urlsafe_encode64(pk))
54
+ end
55
+ end
56
+
57
+ def to_public_map(fields)
58
+ return to_map(fields).except('d')
59
+ end
60
+
61
+ def to_thumbprint_map(fields)
62
+ return to_public_map(fields).slice('crv', 'kty', 'x')
63
+ end
64
+
65
+ # JOSE::JWK::KTY callbacks
66
+
67
+ def self.generate_key(okp_params)
68
+ secret = nil
69
+ if okp_params.is_a?(Array) and (okp_params.length == 2 or okp_params.length == 3) and okp_params[0] == :okp and okp_params[1] == :Ed448
70
+ secret = okp_params[2] if okp_params.length == 3
71
+ elsif okp_params.is_a?(String)
72
+ secret = okp_params
73
+ end
74
+ if secret.nil? or (secret.is_a?(String) and (secret.bytesize == SECRET_BYTES or secret.bytesize == LEGACY_SECRET_BYTES))
75
+ return from_okp([:Ed448, JOSE::JWA::Curve448.ed448_keypair(secret)[1]])
76
+ else
77
+ raise ArgumentError, "'secret' must be nil or a String of #{SECRET_BYTES} bytes"
78
+ end
79
+ end
80
+
81
+ def generate_key(fields)
82
+ kty, other_fields = JOSE::JWK::KTY_OKP_Ed448.generate_key([:okp, :Ed448])
83
+ return kty, fields.delete('kid').merge(other_fields)
84
+ end
85
+
86
+ def key_encryptor(fields, key)
87
+ return JOSE::JWK::KTY.key_encryptor(self, fields, key)
88
+ end
89
+
90
+ def sign(message, digest_type)
91
+ raise ArgumentError, "'digest_type' must be :Ed448" if digest_type != :Ed448
92
+ raise NotImplementedError, "Ed448 public key cannot be used for signing" if okp.bytesize != SK_BYTES and okp.bytesize != LEGACY_SK_BYTES
93
+ return JOSE::JWA::Curve448.ed448_sign(message, okp)
94
+ end
95
+
96
+ def signer(fields = nil, plain_text = nil)
97
+ return JOSE::Map['alg' => 'Ed448']
98
+ end
99
+
100
+ def verify(message, digest_type, signature)
101
+ raise ArgumentError, "'digest_type' must be :Ed448" if digest_type != :Ed448
102
+ pk = okp
103
+ pk = JOSE::JWA::Curve448.ed448_secret_to_public(okp) if okp.bytesize == SK_BYTES or okp.bytesize == LEGACY_SK_BYTES
104
+ return JOSE::JWA::Curve448.ed448_verify(signature, message, pk)
105
+ end
106
+
107
+ # API functions
108
+
109
+ def self.from_okp(okp)
110
+ if okp.is_a?(Array) and okp.length == 2 and okp[0] == :Ed448 and okp[1].is_a?(String) and (okp[1].bytesize == PK_BYTES or okp[1].bytesize == SK_BYTES or okp[1].bytesize == LEGACY_SK_BYTES)
111
+ return JOSE::JWK::KTY_OKP_Ed448.new(okp[1]), JOSE::Map[]
112
+ else
113
+ raise ArgumentError, "'okp' must be an Array in the form of [:Ed448, String]"
114
+ end
115
+ end
116
+
117
+ def to_okp
118
+ return [:Ed448, okp]
119
+ end
120
+
121
+ end
@@ -0,0 +1,121 @@
1
+ class JOSE::JWK::KTY_OKP_Ed448ph < Struct.new(:okp)
2
+
3
+ SECRET_BYTES = 57
4
+ LEGACY_SECRET_BYTES = 32
5
+ PK_BYTES = 57
6
+ SK_BYTES = SECRET_BYTES + PK_BYTES
7
+ LEGACY_SK_BYTES = LEGACY_SECRET_BYTES + PK_BYTES
8
+
9
+ # JOSE::JWK callbacks
10
+
11
+ def self.from_map(fields)
12
+ if fields['kty'] == 'OKP' and fields['crv'] == 'Ed448ph' and fields['x'].is_a?(String)
13
+ pk = JOSE.urlsafe_decode64(fields['x'])
14
+ secret = nil
15
+ if fields['d'].is_a?(String)
16
+ secret = JOSE.urlsafe_decode64(fields['d'])
17
+ end
18
+ if pk.bytesize == PK_BYTES and (secret.nil? or secret.bytesize == SECRET_BYTES or secret.bytesize == LEGACY_SECRET_BYTES)
19
+ if secret.nil?
20
+ return JOSE::JWK::KTY_OKP_Ed448ph.new(pk), fields.except('kty', 'crv', 'x')
21
+ else
22
+ return JOSE::JWK::KTY_OKP_Ed448ph.new(secret + pk), fields.except('kty', 'crv', 'x', 'd')
23
+ end
24
+ end
25
+ end
26
+ raise ArgumentError, "invalid 'OKP' crv 'Ed448ph' JWK"
27
+ end
28
+
29
+ def to_key
30
+ return okp
31
+ end
32
+
33
+ def to_map(fields)
34
+ if okp.bytesize == SK_BYTES
35
+ secret, pk = okp[0, SECRET_BYTES], okp[SECRET_BYTES, SK_BYTES]
36
+ return fields.
37
+ put('crv', 'Ed448ph').
38
+ put('d', JOSE.urlsafe_encode64(secret)).
39
+ put('kty', 'OKP').
40
+ put('x', JOSE.urlsafe_encode64(pk))
41
+ elsif okp.bytesize == LEGACY_SK_BYTES
42
+ secret, pk = okp[0, LEGACY_SECRET_BYTES], okp[LEGACY_SECRET_BYTES, LEGACY_SK_BYTES]
43
+ return fields.
44
+ put('crv', 'Ed448ph').
45
+ put('d', JOSE.urlsafe_encode64(secret)).
46
+ put('kty', 'OKP').
47
+ put('x', JOSE.urlsafe_encode64(pk))
48
+ else
49
+ pk = okp
50
+ return fields.
51
+ put('crv', 'Ed448ph').
52
+ put('kty', 'OKP').
53
+ put('x', JOSE.urlsafe_encode64(pk))
54
+ end
55
+ end
56
+
57
+ def to_public_map(fields)
58
+ return to_map(fields).except('d')
59
+ end
60
+
61
+ def to_thumbprint_map(fields)
62
+ return to_public_map(fields).slice('crv', 'kty', 'x')
63
+ end
64
+
65
+ # JOSE::JWK::KTY callbacks
66
+
67
+ def self.generate_key(okp_params)
68
+ secret = nil
69
+ if okp_params.is_a?(Array) and (okp_params.length == 2 or okp_params.length == 3) and okp_params[0] == :okp and okp_params[1] == :Ed448ph
70
+ secret = okp_params[2] if okp_params.length == 3
71
+ elsif okp_params.is_a?(String)
72
+ secret = okp_params
73
+ end
74
+ if secret.nil? or (secret.is_a?(String) and (secret.bytesize == SECRET_BYTES or secret.bytesize == LEGACY_SECRET_BYTES))
75
+ return from_okp([:Ed448ph, JOSE::JWA::Curve448.ed448ph_keypair(secret)[1]])
76
+ else
77
+ raise ArgumentError, "'secret' must be nil or a String of #{SECRET_BYTES} bytes"
78
+ end
79
+ end
80
+
81
+ def generate_key(fields)
82
+ kty, other_fields = JOSE::JWK::KTY_OKP_Ed448ph.generate_key([:okp, :Ed448ph])
83
+ return kty, fields.delete('kid').merge(other_fields)
84
+ end
85
+
86
+ def key_encryptor(fields, key)
87
+ return JOSE::JWK::KTY.key_encryptor(self, fields, key)
88
+ end
89
+
90
+ def sign(message, digest_type)
91
+ raise ArgumentError, "'digest_type' must be :Ed448ph" if digest_type != :Ed448ph
92
+ raise NotImplementedError, "Ed448ph public key cannot be used for signing" if okp.bytesize != SK_BYTES and okp.bytesize != LEGACY_SK_BYTES
93
+ return JOSE::JWA::Curve448.ed448ph_sign(message, okp)
94
+ end
95
+
96
+ def signer(fields = nil, plain_text = nil)
97
+ return JOSE::Map['alg' => 'Ed448ph']
98
+ end
99
+
100
+ def verify(message, digest_type, signature)
101
+ raise ArgumentError, "'digest_type' must be :Ed448ph" if digest_type != :Ed448ph
102
+ pk = okp
103
+ pk = JOSE::JWA::Curve448.ed448ph_secret_to_public(okp) if okp.bytesize == SK_BYTES or okp.bytesize == LEGACY_SK_BYTES
104
+ return JOSE::JWA::Curve448.ed448ph_verify(signature, message, pk)
105
+ end
106
+
107
+ # API functions
108
+
109
+ def self.from_okp(okp)
110
+ if okp.is_a?(Array) and okp.length == 2 and okp[0] == :Ed448ph and okp[1].is_a?(String) and (okp[1].bytesize == PK_BYTES or okp[1].bytesize == SK_BYTES or okp[1].bytesize == LEGACY_SK_BYTES)
111
+ return JOSE::JWK::KTY_OKP_Ed448ph.new(okp[1]), JOSE::Map[]
112
+ else
113
+ raise ArgumentError, "'okp' must be an Array in the form of [:Ed448ph, String]"
114
+ end
115
+ end
116
+
117
+ def to_okp
118
+ return [:Ed448ph, okp]
119
+ end
120
+
121
+ end