-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
12 changed files
with
358 additions
and
58 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,53 @@ | ||
name: Ruby | ||
--- | ||
name: test | ||
on: | ||
push: | ||
branches: | ||
- "*" | ||
pull_request: | ||
branches: | ||
- "*" | ||
jobs: | ||
lint: | ||
name: RuboCop | ||
timeout-minutes: 30 | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- name: Set up Ruby | ||
uses: ruby/setup-ruby@v1 | ||
with: | ||
ruby-version: "3.3" | ||
bundler-cache: true | ||
- name: Run RuboCop | ||
run: bundle exec rubocop | ||
test: | ||
name: Ruby ${{ matrix.ruby }} | ||
runs-on: ubuntu-latest | ||
strategy: | ||
fail-fast: false | ||
matrix: | ||
ruby: | ||
- "2.5" | ||
- "2.6" | ||
- "2.7" | ||
- "3.0" | ||
- "3.1" | ||
- "3.2" | ||
- "3.3" | ||
steps: | ||
- uses: actions/checkout@v3 | ||
|
||
on: | ||
push: | ||
branches: | ||
- master | ||
- name: Install libsodium | ||
run: | | ||
sudo apt-get update -q | ||
sudo apt-get install libsodium-dev -y | ||
pull_request: | ||
- name: Set up Ruby | ||
uses: ruby/setup-ruby@v1 | ||
with: | ||
ruby-version: ${{ matrix.ruby }} | ||
bundler-cache: true | ||
|
||
jobs: | ||
build: | ||
runs-on: ubuntu-latest | ||
name: Ruby ${{ matrix.ruby }} | ||
strategy: | ||
matrix: | ||
ruby: | ||
- '3.3.0' | ||
|
||
steps: | ||
- uses: actions/checkout@v4 | ||
- name: Set up Ruby | ||
uses: ruby/setup-ruby@v1 | ||
with: | ||
ruby-version: ${{ matrix.ruby }} | ||
bundler-cache: true | ||
- name: Run the default task | ||
run: bundle exec rake | ||
- name: Run tests | ||
run: bundle exec rspec |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,7 +4,7 @@ require_relative "lib/jwt/eddsa/version" | |
|
||
Gem::Specification.new do |spec| | ||
spec.name = "jwt-eddsa" | ||
spec.version = JWT::Eddsa::VERSION | ||
spec.version = JWT::EdDSA::VERSION | ||
spec.authors = ["Joakim Antman"] | ||
spec.email = ["[email protected]"] | ||
|
||
|
@@ -15,7 +15,7 @@ Gem::Specification.new do |spec| | |
|
||
spec.metadata["homepage_uri"] = spec.homepage | ||
spec.metadata["source_code_uri"] = "https://github.com/anakinj/jwt-eddsa" | ||
spec.metadata["changelog_uri"] = "https://github.com/anakinj/jwt-eddsablob/v#{JWT::Eddsa::VERSION}/CHANGELOG.md" | ||
spec.metadata["changelog_uri"] = "https://github.com/anakinj/jwt-eddsablob/v#{JWT::EdDSA::VERSION}/CHANGELOG.md" | ||
|
||
# Specify which files should be added to the gem when it is released. | ||
# The `git ls-files -z` loads the files in the RubyGem that have been added into git. | ||
|
@@ -30,6 +30,7 @@ Gem::Specification.new do |spec| | |
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } | ||
spec.require_paths = ["lib"] | ||
|
||
spec.add_dependency "base64" | ||
spec.add_dependency "jwt", "> 2.8.2" | ||
spec.add_dependency "rbnacl", "~> 6.0" | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,33 +1,7 @@ | ||
# frozen_string_literal: true | ||
|
||
require "jwt" | ||
require_relative "eddsa/version" | ||
|
||
module JWT | ||
# EdDSA algorithm implementation | ||
module Eddsa | ||
include JWT::JWA::Algorithm | ||
|
||
register_algorithm("EdDSA") | ||
|
||
class << self | ||
def sign(_algorithm, msg, key) | ||
unless key.is_a?(RbNaCl::Signatures::Ed25519::SigningKey) | ||
raise_sign_error!("Key given is a #{key.class} but needs to be a RbNaCl::Signatures::Ed25519::SigningKey") | ||
end | ||
|
||
key.sign(msg) | ||
end | ||
|
||
def verify(_algorithm, public_key, signing_input, signature) | ||
unless public_key.is_a?(RbNaCl::Signatures::Ed25519::VerifyKey) | ||
raise_verify_error!("Key given is a #{public_key.class} but needs to be a RbNaCl::Signatures::Ed25519::VerifyKey") | ||
end | ||
|
||
public_key.verify(signature, signing_input) | ||
rescue RbNaCl::CryptoError | ||
false | ||
end | ||
end | ||
end | ||
end | ||
require_relative "eddsa/version" | ||
require_relative "eddsa/jwk/okp" | ||
require_relative "eddsa/algo" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
# frozen_string_literal: true | ||
|
||
module JWT | ||
module EdDSA | ||
# EdDSA algorithm implementation | ||
module Algo | ||
include JWT::JWA::Algorithm | ||
|
||
register_algorithm("EdDSA") | ||
|
||
class << self | ||
def sign(_algorithm, msg, key) | ||
unless key.is_a?(RbNaCl::Signatures::Ed25519::SigningKey) | ||
raise_sign_error!("Key given is a #{key.class} but needs to be a " \ | ||
"RbNaCl::Signatures::Ed25519::SigningKey") | ||
end | ||
|
||
key.sign(msg) | ||
end | ||
|
||
def verify(_algorithm, public_key, signing_input, signature) | ||
unless public_key.is_a?(RbNaCl::Signatures::Ed25519::VerifyKey) | ||
raise_verify_error!("Key given is a #{public_key.class} but needs to be a " \ | ||
"RbNaCl::Signatures::Ed25519::VerifyKey") | ||
end | ||
|
||
public_key.verify(signature, signing_input) | ||
rescue RbNaCl::CryptoError | ||
false | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
# frozen_string_literal: true | ||
|
||
module JWT | ||
module EdDSA | ||
module JWK | ||
# https://datatracker.ietf.org/doc/html/rfc8037 | ||
class OKP < ::JWT::JWK::KeyBase | ||
KTY = "OKP" | ||
KTYS = [KTY, JWT::EdDSA::JWK::OKP, RbNaCl::Signatures::Ed25519::SigningKey, | ||
RbNaCl::Signatures::Ed25519::VerifyKey].freeze | ||
OKP_PUBLIC_KEY_ELEMENTS = %i[kty n x].freeze | ||
OKP_PRIVATE_KEY_ELEMENTS = %i[d].freeze | ||
|
||
def initialize(key, params = nil, options = {}) | ||
params ||= {} | ||
# For backwards compatibility when kid was a String | ||
params = { kid: params } if params.is_a?(String) | ||
|
||
key_params = extract_key_params(key) | ||
|
||
params = params.transform_keys(&:to_sym) | ||
check_jwk_params!(key_params, params) | ||
super(options, key_params.merge(params)) | ||
end | ||
|
||
def verify_key | ||
return @verify_key if defined?(@verify_key) | ||
|
||
@verify_key = verify_key_from_parameters | ||
end | ||
|
||
def signing_key | ||
return @signing_key if defined?(@signing_key) | ||
|
||
@signing_key = signing_key_from_parameters | ||
end | ||
|
||
def key_digest | ||
::JWT::JWK::Thumbprint.new(self).to_s | ||
end | ||
|
||
def private? | ||
!signing_key.nil? | ||
end | ||
|
||
def members | ||
OKP_PUBLIC_KEY_ELEMENTS.each_with_object({}) { |i, h| h[i] = self[i] } | ||
end | ||
|
||
def export(options = {}) | ||
exported = parameters.clone | ||
unless private? && options[:include_private] == true | ||
exported.reject! do |k, _| | ||
OKP_PRIVATE_KEY_ELEMENTS.include?(k) | ||
end | ||
end | ||
exported | ||
end | ||
|
||
private | ||
|
||
def extract_key_params(key) # rubocop:disable Metric/MethodLength | ||
case key | ||
when JWT::JWK::KeyBase | ||
key.export(include_private: true) | ||
when RbNaCl::Signatures::Ed25519::SigningKey | ||
@signing_key = key | ||
@verify_key = key.verify_key | ||
parse_okp_key_params(@verify_key, @signing_key) | ||
when RbNaCl::Signatures::Ed25519::VerifyKey | ||
@signing_key = nil | ||
@verify_key = key | ||
parse_okp_key_params(@verify_key) | ||
when Hash | ||
key.transform_keys(&:to_sym) | ||
else | ||
raise ArgumentError, | ||
"key must be of type RbNaCl::Signatures::Ed25519::SigningKey, " \ | ||
"RbNaCl::Signatures::Ed25519::VerifyKey " \ | ||
"or Hash with key parameters" | ||
end | ||
end | ||
|
||
def check_jwk_params!(key_params, _given_params) | ||
return if key_params[:kty] == KTY | ||
|
||
raise JWT::JWKError, | ||
"Incorrect 'kty' value: #{key_params[:kty]}, expected #{KTY}" | ||
end | ||
|
||
def parse_okp_key_params(verify_key, signing_key = nil) | ||
params = { | ||
kty: KTY, | ||
crv: "Ed25519", | ||
x: ::Base64.urlsafe_encode64(verify_key.to_bytes, padding: false) | ||
} | ||
|
||
params[:d] = ::Base64.urlsafe_encode64(signing_key.to_bytes, padding: false) if signing_key | ||
|
||
params | ||
end | ||
|
||
def verify_key_from_parameters | ||
RbNaCl::Signatures::Ed25519::VerifyKey.new(::Base64.urlsafe_decode64(self[:x])) | ||
end | ||
|
||
def signing_key_from_parameters | ||
return nil unless self[:d] | ||
|
||
RbNaCl::Signatures::Ed25519::SigningKey.new(::Base64.urlsafe_decode64(self[:d])) | ||
end | ||
|
||
class << self | ||
def import(jwk_data) | ||
new(jwk_data) | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,7 @@ | ||
# frozen_string_literal: true | ||
|
||
module JWT | ||
module Eddsa | ||
module EdDSA | ||
VERSION = "0.2.0" | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.