jwt-eddsa 0.2.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.release-please-manifest.json +3 -0
- data/.rubocop.yml +1 -0
- data/CHANGELOG.md +26 -1
- data/LICENSE +1 -1
- data/README.md +6 -2
- data/Rakefile +9 -0
- data/lib/jwt/eddsa/algo.rb +34 -0
- data/lib/jwt/eddsa/jwk/okp.rb +121 -0
- data/lib/jwt/eddsa/version.rb +2 -2
- data/lib/jwt/eddsa.rb +3 -29
- data/release-please-config.json +9 -0
- metadata +23 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8a9054ac4598241fed14b327b76854fb9dd57034947c2dc94d7ffd70a3b9667f
|
4
|
+
data.tar.gz: 79ace7fb4cde12fa7fef53cdec3631be1b1be4c7f9e2acd40976b15228050152
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 55ffed5f3d15b636699d1eb8c20058a9d99c5f854de01efe1b06481aacee9f8e086fea6700c4ebc5e19e62139e3d4c9b31c81b160eab7e240cb2244c8a8e15da
|
7
|
+
data.tar.gz: d5f6976cba0e2eec62baae85abdad9c175937c90787a74d627b950e57a641869e2a562ef6e246b9b32e34379ab411e1e55d726d1130644eee667e637844485e1
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,30 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## [0.5.0](https://github.com/anakinj/jwt-eddsa/compare/v0.4.0...v0.5.0) (2024-08-02)
|
4
|
+
|
5
|
+
|
6
|
+
### Features
|
7
|
+
|
8
|
+
* Initial release ([d7ce4d3](https://github.com/anakinj/jwt-eddsa/commit/d7ce4d3885a1fbe0e268a672a52d4ed8b7c558d2))
|
9
|
+
* Release using release-please ([d450241](https://github.com/anakinj/jwt-eddsa/commit/d45024107095270ad6bafc0a638f154c0cb4d763))
|
10
|
+
* Still trying to configure release-please ([fcfe5cc](https://github.com/anakinj/jwt-eddsa/commit/fcfe5cc0c5ff18ea296a64d78db3fe073d667190))
|
11
|
+
|
12
|
+
## [0.4.0](https://github.com/anakinj/jwt-eddsa/compare/jwt-eddsa-v0.3.0...jwt-eddsa/v0.4.0) (2024-08-02)
|
13
|
+
|
14
|
+
|
15
|
+
### Features
|
16
|
+
|
17
|
+
* Initial release ([d7ce4d3](https://github.com/anakinj/jwt-eddsa/commit/d7ce4d3885a1fbe0e268a672a52d4ed8b7c558d2))
|
18
|
+
* Release using release-please ([d450241](https://github.com/anakinj/jwt-eddsa/commit/d45024107095270ad6bafc0a638f154c0cb4d763))
|
19
|
+
* Still trying to configure release-please ([fcfe5cc](https://github.com/anakinj/jwt-eddsa/commit/fcfe5cc0c5ff18ea296a64d78db3fe073d667190))
|
20
|
+
|
21
|
+
## [0.3.0](https://github.com/anakinj/jwt-eddsa/compare/v0.2.0...v0.3.0) (2024-08-02)
|
22
|
+
|
23
|
+
|
24
|
+
### Features
|
25
|
+
|
26
|
+
* Initial release ([d7ce4d3](https://github.com/anakinj/jwt-eddsa/commit/d7ce4d3885a1fbe0e268a672a52d4ed8b7c558d2))
|
27
|
+
|
3
28
|
## [v0.0.1](https://github.com/anakinj/jwt-eddsa/tree/v0.0.1) (NEXT)
|
4
29
|
|
5
30
|
[Full Changelog](https://github.com/jwt/ruby-jwt/compare/v2.8.2...main)
|
@@ -11,4 +36,4 @@
|
|
11
36
|
|
12
37
|
**Fixes and enhancements:**
|
13
38
|
|
14
|
-
- Your contribution here
|
39
|
+
- Your contribution here
|
data/LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
# jwt-eddsa
|
2
2
|
|
3
|
-
|
3
|
+
[![Gem Version](https://badge.fury.io/rb/jwt-eddsa.svg)](https://badge.fury.io/rb/jwt-eddsa)
|
4
|
+
[![Build Status](https://github.com/anakinj/jwt-eddsa/workflows/test/badge.svg?branch=main)](https://github.com/jwt/ruby-jwt/actions)
|
5
|
+
|
6
|
+
A library extending the ruby-jwt gem with EdDSA algorithms. Based on [RFC 8037](https://datatracker.ietf.org/doc/html/rfc8037).
|
4
7
|
|
5
8
|
**NOTE: This gem is still WIP**
|
6
9
|
|
@@ -13,6 +16,7 @@ Plan is to replace rbnacl with something else in the near future.
|
|
13
16
|
Will only work with the WIP branch, so adding the following to your the Gemfile should do the trick:
|
14
17
|
```
|
15
18
|
gem "jwt", github: "anakinj/ruby-jwt", branch: "extendable-algos"
|
19
|
+
gem "jwt-eddsa"
|
16
20
|
```
|
17
21
|
|
18
22
|
```
|
@@ -31,7 +35,7 @@ payload, header = JWT.decode(token, private_key.verify_key, true, algorithm: "Ed
|
|
31
35
|
|
32
36
|
```
|
33
37
|
bundle install
|
34
|
-
bundle exec
|
38
|
+
bundle exec rake
|
35
39
|
```
|
36
40
|
|
37
41
|
## Contributing
|
data/Rakefile
CHANGED
@@ -10,3 +10,12 @@ require "rubocop/rake_task"
|
|
10
10
|
RuboCop::RakeTask.new
|
11
11
|
|
12
12
|
task default: %i[spec rubocop]
|
13
|
+
|
14
|
+
task :check_version do
|
15
|
+
require_relative "lib/jwt/eddsa/version"
|
16
|
+
version = ENV.fetch("GEM_VERSION", nil)
|
17
|
+
|
18
|
+
raise "Version mismatch: #{JWT::EdDSA::VERSION} != #{version}" if version != JWT::EdDSA::VERSION
|
19
|
+
end
|
20
|
+
|
21
|
+
Rake::Task[:build].enhance([:check_version]) if ENV["CI"]
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JWT
|
4
|
+
module EdDSA
|
5
|
+
# EdDSA algorithm implementation
|
6
|
+
module Algo
|
7
|
+
include JWT::JWA::Algorithm
|
8
|
+
|
9
|
+
register_algorithm("EdDSA")
|
10
|
+
|
11
|
+
class << self
|
12
|
+
def sign(_algorithm, msg, key)
|
13
|
+
unless key.is_a?(RbNaCl::Signatures::Ed25519::SigningKey)
|
14
|
+
raise_sign_error!("Key given is a #{key.class} but needs to be a " \
|
15
|
+
"RbNaCl::Signatures::Ed25519::SigningKey")
|
16
|
+
end
|
17
|
+
|
18
|
+
key.sign(msg)
|
19
|
+
end
|
20
|
+
|
21
|
+
def verify(_algorithm, public_key, signing_input, signature)
|
22
|
+
unless public_key.is_a?(RbNaCl::Signatures::Ed25519::VerifyKey)
|
23
|
+
raise_verify_error!("Key given is a #{public_key.class} but needs to be a " \
|
24
|
+
"RbNaCl::Signatures::Ed25519::VerifyKey")
|
25
|
+
end
|
26
|
+
|
27
|
+
public_key.verify(signature, signing_input)
|
28
|
+
rescue RbNaCl::CryptoError
|
29
|
+
false
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module JWT
|
4
|
+
module EdDSA
|
5
|
+
module JWK
|
6
|
+
# https://datatracker.ietf.org/doc/html/rfc8037
|
7
|
+
class OKP < ::JWT::JWK::KeyBase
|
8
|
+
KTY = "OKP"
|
9
|
+
KTYS = [KTY, JWT::EdDSA::JWK::OKP, RbNaCl::Signatures::Ed25519::SigningKey,
|
10
|
+
RbNaCl::Signatures::Ed25519::VerifyKey].freeze
|
11
|
+
OKP_PUBLIC_KEY_ELEMENTS = %i[kty n x].freeze
|
12
|
+
OKP_PRIVATE_KEY_ELEMENTS = %i[d].freeze
|
13
|
+
|
14
|
+
def initialize(key, params = nil, options = {})
|
15
|
+
params ||= {}
|
16
|
+
# For backwards compatibility when kid was a String
|
17
|
+
params = { kid: params } if params.is_a?(String)
|
18
|
+
|
19
|
+
key_params = extract_key_params(key)
|
20
|
+
|
21
|
+
params = params.transform_keys(&:to_sym)
|
22
|
+
check_jwk_params!(key_params, params)
|
23
|
+
super(options, key_params.merge(params))
|
24
|
+
end
|
25
|
+
|
26
|
+
def verify_key
|
27
|
+
return @verify_key if defined?(@verify_key)
|
28
|
+
|
29
|
+
@verify_key = verify_key_from_parameters
|
30
|
+
end
|
31
|
+
|
32
|
+
def signing_key
|
33
|
+
return @signing_key if defined?(@signing_key)
|
34
|
+
|
35
|
+
@signing_key = signing_key_from_parameters
|
36
|
+
end
|
37
|
+
|
38
|
+
def key_digest
|
39
|
+
::JWT::JWK::Thumbprint.new(self).to_s
|
40
|
+
end
|
41
|
+
|
42
|
+
def private?
|
43
|
+
!signing_key.nil?
|
44
|
+
end
|
45
|
+
|
46
|
+
def members
|
47
|
+
OKP_PUBLIC_KEY_ELEMENTS.each_with_object({}) { |i, h| h[i] = self[i] }
|
48
|
+
end
|
49
|
+
|
50
|
+
def export(options = {})
|
51
|
+
exported = parameters.clone
|
52
|
+
unless private? && options[:include_private] == true
|
53
|
+
exported.reject! do |k, _|
|
54
|
+
OKP_PRIVATE_KEY_ELEMENTS.include?(k)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
exported
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def extract_key_params(key) # rubocop:disable Metrics/MethodLength
|
63
|
+
case key
|
64
|
+
when JWT::JWK::KeyBase
|
65
|
+
key.export(include_private: true)
|
66
|
+
when RbNaCl::Signatures::Ed25519::SigningKey
|
67
|
+
@signing_key = key
|
68
|
+
@verify_key = key.verify_key
|
69
|
+
parse_okp_key_params(@verify_key, @signing_key)
|
70
|
+
when RbNaCl::Signatures::Ed25519::VerifyKey
|
71
|
+
@signing_key = nil
|
72
|
+
@verify_key = key
|
73
|
+
parse_okp_key_params(@verify_key)
|
74
|
+
when Hash
|
75
|
+
key.transform_keys(&:to_sym)
|
76
|
+
else
|
77
|
+
raise ArgumentError,
|
78
|
+
"key must be of type RbNaCl::Signatures::Ed25519::SigningKey, " \
|
79
|
+
"RbNaCl::Signatures::Ed25519::VerifyKey " \
|
80
|
+
"or Hash with key parameters"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def check_jwk_params!(key_params, _given_params)
|
85
|
+
return if key_params[:kty] == KTY
|
86
|
+
|
87
|
+
raise JWT::JWKError,
|
88
|
+
"Incorrect 'kty' value: #{key_params[:kty]}, expected #{KTY}"
|
89
|
+
end
|
90
|
+
|
91
|
+
def parse_okp_key_params(verify_key, signing_key = nil)
|
92
|
+
params = {
|
93
|
+
kty: KTY,
|
94
|
+
crv: "Ed25519",
|
95
|
+
x: ::Base64.urlsafe_encode64(verify_key.to_bytes, padding: false)
|
96
|
+
}
|
97
|
+
|
98
|
+
params[:d] = ::Base64.urlsafe_encode64(signing_key.to_bytes, padding: false) if signing_key
|
99
|
+
|
100
|
+
params
|
101
|
+
end
|
102
|
+
|
103
|
+
def verify_key_from_parameters
|
104
|
+
RbNaCl::Signatures::Ed25519::VerifyKey.new(::Base64.urlsafe_decode64(self[:x]))
|
105
|
+
end
|
106
|
+
|
107
|
+
def signing_key_from_parameters
|
108
|
+
return nil unless self[:d]
|
109
|
+
|
110
|
+
RbNaCl::Signatures::Ed25519::SigningKey.new(::Base64.urlsafe_decode64(self[:d]))
|
111
|
+
end
|
112
|
+
|
113
|
+
class << self
|
114
|
+
def import(jwk_data)
|
115
|
+
new(jwk_data)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
data/lib/jwt/eddsa/version.rb
CHANGED
data/lib/jwt/eddsa.rb
CHANGED
@@ -1,33 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "jwt"
|
4
|
-
require_relative "eddsa/version"
|
5
|
-
|
6
|
-
module JWT
|
7
|
-
# EdDSA algorithm implementation
|
8
|
-
module Eddsa
|
9
|
-
include JWT::JWA::Algorithm
|
10
|
-
|
11
|
-
register_algorithm("EdDSA")
|
12
|
-
|
13
|
-
class << self
|
14
|
-
def sign(_algorithm, msg, key)
|
15
|
-
unless key.is_a?(RbNaCl::Signatures::Ed25519::SigningKey)
|
16
|
-
raise_sign_error!("Key given is a #{key.class} but needs to be a RbNaCl::Signatures::Ed25519::SigningKey")
|
17
|
-
end
|
18
4
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
def verify(_algorithm, public_key, signing_input, signature)
|
23
|
-
unless public_key.is_a?(RbNaCl::Signatures::Ed25519::VerifyKey)
|
24
|
-
raise_verify_error!("Key given is a #{public_key.class} but needs to be a RbNaCl::Signatures::Ed25519::VerifyKey")
|
25
|
-
end
|
26
|
-
|
27
|
-
public_key.verify(signature, signing_input)
|
28
|
-
rescue RbNaCl::CryptoError
|
29
|
-
false
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
5
|
+
require_relative "eddsa/version"
|
6
|
+
require_relative "eddsa/jwk/okp"
|
7
|
+
require_relative "eddsa/algo"
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jwt-eddsa
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joakim Antman
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-08-
|
11
|
+
date: 2024-08-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: base64
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: jwt
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -38,13 +52,14 @@ dependencies:
|
|
38
52
|
- - "~>"
|
39
53
|
- !ruby/object:Gem::Version
|
40
54
|
version: '6.0'
|
41
|
-
description:
|
55
|
+
description: Extends the ruby-jwt gem with EdDSA signing, verification and JWK importing/exporting
|
42
56
|
email:
|
43
57
|
- antmanj@gmail.com
|
44
58
|
executables: []
|
45
59
|
extensions: []
|
46
60
|
extra_rdoc_files: []
|
47
61
|
files:
|
62
|
+
- ".release-please-manifest.json"
|
48
63
|
- ".rspec"
|
49
64
|
- ".rubocop.yml"
|
50
65
|
- ".ruby-version"
|
@@ -54,14 +69,17 @@ files:
|
|
54
69
|
- README.md
|
55
70
|
- Rakefile
|
56
71
|
- lib/jwt/eddsa.rb
|
72
|
+
- lib/jwt/eddsa/algo.rb
|
73
|
+
- lib/jwt/eddsa/jwk/okp.rb
|
57
74
|
- lib/jwt/eddsa/version.rb
|
75
|
+
- release-please-config.json
|
58
76
|
homepage: https://github.com/anakinj/jwt-eddsa
|
59
77
|
licenses:
|
60
78
|
- MIT
|
61
79
|
metadata:
|
62
80
|
homepage_uri: https://github.com/anakinj/jwt-eddsa
|
63
81
|
source_code_uri: https://github.com/anakinj/jwt-eddsa
|
64
|
-
changelog_uri: https://github.com/anakinj/jwt-
|
82
|
+
changelog_uri: https://github.com/anakinj/jwt-eddsa/blob/v0.5.0/CHANGELOG.md
|
65
83
|
rubygems_mfa_required: 'true'
|
66
84
|
post_install_message:
|
67
85
|
rdoc_options: []
|
@@ -81,5 +99,5 @@ requirements: []
|
|
81
99
|
rubygems_version: 3.5.11
|
82
100
|
signing_key:
|
83
101
|
specification_version: 4
|
84
|
-
summary:
|
102
|
+
summary: jwt EdDSA algorithm extension
|
85
103
|
test_files: []
|