Skip to content

Commit

Permalink
Remove dependency on ed25519 gem
Browse files Browse the repository at this point in the history
  • Loading branch information
oneiros authored and nomadium committed Dec 2, 2024
1 parent 5c42420 commit 4622a74
Show file tree
Hide file tree
Showing 9 changed files with 20 additions and 86 deletions.
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ gem "rake", "~> 13.0"

gem "rspec", "~> 3.0"

gem "securerandom"

gem "standard", "~> 1.3"

gem "simplecov", require: false, group: :test
4 changes: 2 additions & 2 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ PATH
remote: .
specs:
linzer (0.6.1)
ed25519 (~> 1.3, >= 1.3.0)
openssl (~> 3.0, >= 3.0.0)
rack (>= 2.2, < 4.0)
starry (~> 0.2)
Expand All @@ -15,7 +14,6 @@ GEM
base64 (0.2.0)
diff-lcs (1.5.1)
docile (1.4.0)
ed25519 (1.3.0)
json (2.7.2)
language_server-protocol (3.17.0.3)
lint_roller (1.1.0)
Expand Down Expand Up @@ -60,6 +58,7 @@ GEM
rubocop (>= 1.48.1, < 2.0)
rubocop-ast (>= 1.30.0, < 2.0)
ruby-progressbar (1.13.0)
securerandom (0.4.0)
simplecov (0.22.0)
docile (~> 1.1)
simplecov-html (~> 0.11)
Expand Down Expand Up @@ -92,6 +91,7 @@ DEPENDENCIES
linzer!
rake (~> 13.0)
rspec (~> 3.0)
securerandom
simplecov
standard (~> 1.3)

Expand Down
9 changes: 3 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,10 @@ response = http.post("/some_uri", "data", headers.merge(signature.to_h))
### To verify a valid signature:

```ruby
test_ed25519_key_pub = Base64.strict_encode64(key.material.verify_key.to_bytes)
# => "EUra7KsJ8B/lSZJVhDaopMycmZ6T7KtJqKVNJTHKIw0="
test_ed25519_key_pub = key.material.public_to_pem
# => "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEAK1ZrC4JqC356pRsUiLVJdFZ3dAjo909VfWs1li33MCQ=\n-----END PUBLIC KEY-----\n"

raw_pubkey = Base64.strict_decode64(test_ed25519_key_pub)
# => "\xB1rM\xFFR\x1F\xDDw\x00\x89\..."

pubkey = Linzer.new_ed25519_public_key(raw_pubkey, "some-key-ed25519")
pubkey = Linzer.new_ed25519_public_key(test_ed25519_key_pub, "some-key-ed25519")
# => #<Linzer::Ed25519::Key:0x00000fe19b9384b0

# if you have to, there is a helper method to build a request object on the server side
Expand Down
9 changes: 2 additions & 7 deletions lib/linzer/ed25519.rb
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
# frozen_string_literal: true

require "ed25519"

module Linzer
module Ed25519
class Key < Linzer::Key
def sign(data)
material.sign(data)
material.sign(nil, data)
end

def verify(signature, data)
verify_key = material.is_a?(::Ed25519::SigningKey) ? material.verify_key : material
verify_key.verify(signature, data)
rescue ::Ed25519::VerifyError
false
material.verify(nil, signature, data)
end
end
end
Expand Down
7 changes: 3 additions & 4 deletions lib/linzer/key/helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,17 @@ def new_hmac_sha256_key(material, key_id = nil)
end

def generate_ed25519_key(key_id = nil)
material = ::Ed25519::SigningKey.generate
material = OpenSSL::PKey.generate_key("ed25519")
Linzer::Ed25519::Key.new(material, id: key_id)
end

def new_ed25519_key(material, key_id = nil)
key = ::Ed25519::SigningKey.new(material)
key = OpenSSL::PKey.read(material)
Linzer::Ed25519::Key.new(key, id: key_id)
end

def new_ed25519_public_key(material, key_id = nil)
key = ::Ed25519::VerifyKey.new(material)
Linzer::Ed25519::Key.new(key, id: key_id)
new_ed25519_key(material, key_id)
end

# https://www.rfc-editor.org/rfc/rfc4492.html#appendix-A
Expand Down
1 change: 0 additions & 1 deletion linzer.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ Gem::Specification.new do |spec|
spec.require_paths = ["lib"]

spec.add_runtime_dependency "openssl", "~> 3.0", ">= 3.0.0"
spec.add_runtime_dependency "ed25519", "~> 1.3", ">= 1.3.0"
spec.add_runtime_dependency "starry", "~> 0.2"
spec.add_runtime_dependency "rack", ">= 2.2", "< 4.0"
spec.add_runtime_dependency "uri", "~> 1.0", ">= 1.0.2"
Expand Down
67 changes: 4 additions & 63 deletions spec/ed25519_spec.rb
Original file line number Diff line number Diff line change
@@ -1,26 +1,5 @@
# frozen_string_literal: true

def decode_asn1_blob_from_rfc_examples(key)
Linzer::RFC9421::Examples
.public_send(key)
.lines
.reject { |l| l.start_with?("-----") }
.shift
.chomp
.yield_self { |str| Base64.strict_decode64(str) }
.yield_self { |str| OpenSSL::ASN1.decode(str) }
end

def load_ed25519_pubkey_from_rfc_examples
asn_seq = decode_asn1_blob_from_rfc_examples(:test_key_ed25519_pub)
asn_seq.value[1].value
end

def load_ed25519_private_key_from_rfc_examples
asn_seq = decode_asn1_blob_from_rfc_examples(:test_key_ed25519)
asn_seq.value[2].value[2..]
end

RSpec.describe Linzer::Signer do
context "with Ed25519" do
let(:request) do
Expand All @@ -29,31 +8,8 @@ def load_ed25519_private_key_from_rfc_examples
Linzer.new_request(:post, path, {}, request_data[:headers])
end

# B.1.4. Example Ed25519 Test Key
#
# -----BEGIN PUBLIC KEY-----
# MCowBQYDK2VwAyEAJrQLj5P/89iXES9+vFgrIy29clF9CC/oPPsw3c5D0bs=
# -----END PUBLIC KEY-----
#
# -----BEGIN PRIVATE KEY-----
# MC4CAQAwBQYDK2VwBCIEIJ+DYvh6SEqVTm50DFtMDoQikTmiCqirVv9mWG9qfSnF
# -----END PRIVATE KEY-----
#
# ed25519 ruby library works with raw byte strings, so you have
# to extract them from the PKCS #8 encoded file PEM format.
#
# XXX: should I write a helper method for that?
# XXX: if such a helper is needed, the helper method above
# XXX: decode_asn1_blob_from_rfc_examples can be used as starting point.
#
# $ openssl asn1parse -in private.pem -offset 14
# 0:d=0 hl=2 l= 32 prim: OCTET STRING [HEX DUMP]:9F8362F87A484A954E6E740C5B4C0E84229139A20AA8AB56FF66586F6A7D29C5
#
# %w[9F8362F87A484A954E6E740C5B4C0E84229139A20AA8AB56FF66586F6A7D29C5].pack("H*")
# => "\x9F\x83b\xF8zHJ\x95Nnt\f[L\x0E\x84\"\x919\xA2\n\xA8\xABV\xFFfXoj})\xC5"
#
let(:test_key_ed25519) do
load_ed25519_private_key_from_rfc_examples
Linzer::RFC9421::Examples.test_key_ed25519
end

let(:key_id) { "test-key-ed25519" }
Expand All @@ -77,8 +33,8 @@ def load_ed25519_private_key_from_rfc_examples
end

it "derives public key from private key" do
pubkey = key.material.verify_key.to_bytes
expect(pubkey).to eq(load_ed25519_pubkey_from_rfc_examples)
pubkey = key.material.public_to_pem
expect(pubkey).to eq(Linzer::RFC9421::Examples.test_key_ed25519_pub)
end
end
end
Expand All @@ -91,22 +47,7 @@ def load_ed25519_private_key_from_rfc_examples
Linzer.new_request(:post, path, {}, request_data[:headers])
end

# $ openssl pkey -pubin -inform pem -in public.pem -noout -text
# ED25519 Public-Key:
# pub:
# 26:b4:0b:8f:93:ff:f3:d8:97:11:2f:7e:bc:58:2b:
# 23:2d:bd:72:51:7d:08:2f:e8:3c:fb:30:dd:ce:43:
# d1:bb
#
# %w[26B40B8F93FFF3D897112F7EBC582B232DBD72517D082FE83CFB30DDCE43D1BB].pack("H*")
# => "&\xB4\v\x8F\x93\xFF\xF3\xD8\x97\x11/~\xBCX+#-\xBDrQ}\b/\xE8<\xFB0\xDD\xCEC\xD1\xBB"
#
# public key can also be derived from private key object,
# as is shown above in the examples:
# key.material.verify_key.to_bytes
# => "&\xB4\v\x8F\x93\xFF\xF3\xD8\x97\x11/~\xBCX+#-\xBDrQ}\b/\xE8<\xFB0\xDD\xCEC\xD1\xBB"

let(:test_key_ed25519_pub) { load_ed25519_pubkey_from_rfc_examples }
let(:test_key_ed25519_pub) { Linzer::RFC9421::Examples.test_key_ed25519_pub }

let(:key_id) { "test-key-ed25519" }

Expand Down
5 changes: 2 additions & 3 deletions spec/readme_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ def build_random_signature(label)
let(:key) { Linzer.generate_ed25519_key }

let(:pubkey) do
exported_pubkey = Base64.strict_encode64(key.material.verify_key.to_bytes)
raw_pubkey = Base64.strict_decode64(exported_pubkey)
Linzer.new_ed25519_public_key(raw_pubkey, "some-key-ed25519")
exported_pubkey = key.material.public_to_pem
Linzer.new_ed25519_public_key(exported_pubkey, "some-key-ed25519")
end

describe "HTTP request examples" do
Expand Down
2 changes: 2 additions & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
require "simplecov"
SimpleCov.start

require "securerandom"

require "linzer"
require_relative "rfc9421_examples"

Expand Down

0 comments on commit 4622a74

Please sign in to comment.