openssl-signature_algorithm 0.1.1 → 1.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 973a01f83e137fb88da90dee332beee6e310b0b9e2e3e7a2b1e542483af0e6ef
4
- data.tar.gz: 93e691f2283a6d1acbd0448a647ba90f73171fc56a39a4fc05be88aca5be23f5
3
+ metadata.gz: b8ab663827b9c60f9719579871f55a1b12001374d444e9b9194d2708395ba8af
4
+ data.tar.gz: 8af2c52eea842562e1122bd8824bb8eb79ed8923648d24414b11d7a7d0b9adea
5
5
  SHA512:
6
- metadata.gz: a91b04513d6ea59199bba52668fd76958ddea756012375db5b567dd67db86874c6ccb2aca08b7ad33480c33683266e417bb455ebeebc5f067de24fa648d3eb7b
7
- data.tar.gz: 26458502e1b9c12acf6b9652ce79b35572e28175a105f0fe0dc35eb87584039a47208417d079a5d3a2442e7407cc8b2943d7adbb6bb539bd29d9895063f04140
6
+ metadata.gz: 364884d8b267251a5f354d09cfbca71f64f33c7cc6eebac031b42074ab59eff1ed588b202e60f1bb06d392c175bb20c3b69563fda04a6210fe89b1facbb09333
7
+ data.tar.gz: 1a02dbd91e0d8e2dcc5d1e81bf8fe328d989f367f86224abaf77719b3fd3326785f7c5ac94b6adb3c0b3bdc3ab0add2d64ab2dba9479454c0f482c77ac7bc82a
@@ -0,0 +1,37 @@
1
+ # This workflow uses actions that are not certified by GitHub.
2
+ # They are provided by a third-party and are governed by
3
+ # separate terms of service, privacy policy, and support
4
+ # documentation.
5
+ # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
6
+ # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
7
+
8
+ name: build
9
+
10
+ on: push
11
+
12
+ jobs:
13
+ test:
14
+ runs-on: ubuntu-20.04
15
+ strategy:
16
+ fail-fast: false
17
+ matrix:
18
+ ruby-version:
19
+ - 3.0.0
20
+ - 2.7.2
21
+ - 2.6.6
22
+ - 2.5.8
23
+ - 2.4.10
24
+ gemfile:
25
+ - openssl_2_2
26
+ - openssl_2_1
27
+ - openssl_2_0
28
+ env:
29
+ BUNDLE_GEMFILE: gemfiles/${{ matrix.gemfile }}.gemfile
30
+ steps:
31
+ - uses: actions/checkout@v2
32
+ - run: rm Gemfile.lock
33
+ - uses: ruby/setup-ruby@v1
34
+ with:
35
+ ruby-version: ${{ matrix.ruby-version }}
36
+ bundler-cache: true
37
+ - run: bundle exec rake
data/.gitignore CHANGED
@@ -9,3 +9,6 @@
9
9
 
10
10
  # rspec failure tracking
11
11
  .rspec_status
12
+ .byebug_history
13
+
14
+ /gemfiles/*.gemfile.lock
data/.rspec CHANGED
@@ -1,3 +1,4 @@
1
1
  --format documentation
2
2
  --color
3
3
  --require spec_helper
4
+ --order random
data/.rubocop.yml CHANGED
@@ -1,6 +1,9 @@
1
1
  AllCops:
2
- TargetRubyVersion: 2.5
2
+ TargetRubyVersion: 2.4
3
3
  DisabledByDefault: true
4
+ Exclude:
5
+ - "gemfiles/**/*"
6
+ - "vendor/bundle/**/*"
4
7
 
5
8
  Bundler:
6
9
  Enabled: true
@@ -26,9 +29,6 @@ Security:
26
29
  Style/BlockComments:
27
30
  Enabled: true
28
31
 
29
- Style/BracesAroundHashParameters:
30
- Enabled: true
31
-
32
32
  Style/CaseEquality:
33
33
  Enabled: true
34
34
 
data/Appraisals ADDED
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ appraise "openssl_2_2" do
4
+ gem "openssl", "~> 2.2.0"
5
+ end
6
+
7
+ appraise "openssl_2_1" do
8
+ gem "openssl", "~> 2.1.0"
9
+ end
10
+
11
+ appraise "openssl_2_0" do
12
+ gem "openssl", "~> 2.0.0"
13
+ end
data/CHANGELOG.md CHANGED
@@ -1,5 +1,69 @@
1
1
  # Changelog
2
2
 
3
+ ## [v1.1.0] - 2021-02-11
4
+
5
+ ### Added
6
+
7
+ - EdDSA support added (requires adding the `ed25519` gem to your `Gemfile`) ([@santiagorodriguez96])
8
+
9
+ ## [v1.0.0] - 2020-07-08
10
+
11
+ ### Added
12
+
13
+ - ECDSA with **secp256k1** curve support added:
14
+ ```rb
15
+ OpenSSL::SignatureAlgorithm::ECDSA.new(curve: "secp256k1")
16
+ ```
17
+ - Algorithm **arguments** are now **optional**. The following works:
18
+
19
+ ```rb
20
+ OpenSSL::SignatureAlgorithm::ECDSA.new
21
+ # defaults to ECDSA with SHA-256 and NIST P256 curve
22
+ # Same as OpenSSL::SignatureAlgorithm::ECDSA.new(hash_function: "SHA256", curve: "prime256v1")
23
+
24
+ OpenSSL::SignatureAlgorithm::RSAPSS.new
25
+ # defaults to SHA-256
26
+ # Same as OpenSSL::SignatureAlgorithm::RSAPSS.new(hash_function: "SHA256")
27
+
28
+ OpenSSL::SignatureAlgorithm::RSAPKCS1.new
29
+ # defaults to SHA-256
30
+ # Same as OpenSSL::SignatureAlgorithm::RSAPSS.new(hash_function: "SHA256")
31
+ ```
32
+
33
+ ### Changed
34
+
35
+ - Algorithm **instantiation** changed. The positional argument `digest_length` is replaced with keyword arguments, `hash_function:` for RSA algorithms and `hash_function:` and `curve:` for ECDSA. None are required arguments, you get sane defaults if you don't provide any arguments. Code migration examples:
36
+ ```rb
37
+ # Change this
38
+ # OpenSSL::SignatureAlgorithm::ECDSA.new("256")
39
+ # to
40
+ OpenSSL::SignatureAlgorithm::ECDSA.new(hash_function: "SHA256")
41
+ ```
42
+ ```rb
43
+ # Change this
44
+ # OpenSSL::SignatureAlgorithm::RSAPSS.new("384")
45
+ # to
46
+ OpenSSL::SignatureAlgorithm::RSAPSS.new(hash_function: "SHA384")
47
+ ```
48
+
49
+ ## [v0.4.0] - 2020-01-31
50
+
51
+ ### Added
52
+
53
+ - `VerifyKey` serialization and deserialization for easy transmission over the network
54
+
55
+ ## [v0.3.0] - 2020-01-30
56
+
57
+ ### Added
58
+
59
+ - Support ruby v2.4 (without RSA-PSS)
60
+
61
+ ## [v0.2.0] - 2020-01-29
62
+
63
+ ### Added
64
+
65
+ - `OpenSSL::SignatureAlgorithm::ECDSA#verify` now supports raw (non DER) signatures
66
+
3
67
  ## [v0.1.1] - 2020-01-29
4
68
 
5
69
  ### Fixed
@@ -14,5 +78,12 @@
14
78
  - `OpenSSL::SignatureAlgorithm::RSAPSS`
15
79
  - `OpenSSL::SignatureAlgorithm::RSAPKCS1`
16
80
 
81
+ [v1.1.0]: https://github.com/cedarcode/openssl-signature_algorithm/compare/v1.0.0...v1.1.0/
82
+ [v1.0.0]: https://github.com/cedarcode/openssl-signature_algorithm/compare/v0.4.0...v1.0.0/
83
+ [v0.4.0]: https://github.com/cedarcode/openssl-signature_algorithm/compare/v0.3.0...v0.4.0/
84
+ [v0.3.0]: https://github.com/cedarcode/openssl-signature_algorithm/compare/v0.2.0...v0.3.0/
85
+ [v0.2.0]: https://github.com/cedarcode/openssl-signature_algorithm/compare/v0.1.1...v0.2.0/
17
86
  [v0.1.1]: https://github.com/cedarcode/openssl-signature_algorithm/compare/v0.1.0...v0.1.1/
18
87
  [v0.1.0]: https://github.com/cedarcode/openssl-signature_algorithm/compare/41887c277dc7fa0c884ccf8924cf990ff76784d9...v0.1.0/
88
+
89
+ [@santiagorodriguez96]: https://github.com/santiagorodriguez96
data/Gemfile CHANGED
@@ -5,6 +5,9 @@ source "https://rubygems.org"
5
5
  # Specify your gem's dependencies in openssl-signature_algorithm.gemspec
6
6
  gemspec
7
7
 
8
- gem "rake", "~> 12.0"
8
+ gem "appraisal", "~> 2.2"
9
+ gem "byebug", "~> 11.0"
10
+ gem "ed25519", "~> 1.2"
11
+ gem "rake", "~> 13.0"
9
12
  gem "rspec", "~> 3.0"
10
- gem "rubocop", "~> 0.79.0"
13
+ gem "rubocop", "~> 0.80.1"
data/Gemfile.lock CHANGED
@@ -1,50 +1,64 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- openssl-signature_algorithm (0.1.1)
4
+ openssl-signature_algorithm (1.0.0)
5
+ openssl (~> 2.0)
5
6
 
6
7
  GEM
7
8
  remote: https://rubygems.org/
8
9
  specs:
10
+ appraisal (2.2.0)
11
+ bundler
12
+ rake
13
+ thor (>= 0.14.0)
9
14
  ast (2.4.0)
15
+ byebug (11.1.1)
10
16
  diff-lcs (1.3)
17
+ ed25519 (1.2.4)
11
18
  jaro_winkler (1.5.4)
19
+ openssl (2.2.0)
12
20
  parallel (1.19.1)
13
- parser (2.7.0.2)
21
+ parser (2.7.0.5)
14
22
  ast (~> 2.4.0)
15
23
  rainbow (3.0.0)
16
- rake (12.3.3)
24
+ rake (13.0.1)
25
+ rexml (3.2.4)
17
26
  rspec (3.9.0)
18
27
  rspec-core (~> 3.9.0)
19
28
  rspec-expectations (~> 3.9.0)
20
29
  rspec-mocks (~> 3.9.0)
21
30
  rspec-core (3.9.1)
22
31
  rspec-support (~> 3.9.1)
23
- rspec-expectations (3.9.0)
32
+ rspec-expectations (3.9.1)
24
33
  diff-lcs (>= 1.2.0, < 2.0)
25
34
  rspec-support (~> 3.9.0)
26
35
  rspec-mocks (3.9.1)
27
36
  diff-lcs (>= 1.2.0, < 2.0)
28
37
  rspec-support (~> 3.9.0)
29
38
  rspec-support (3.9.2)
30
- rubocop (0.79.0)
39
+ rubocop (0.80.1)
31
40
  jaro_winkler (~> 1.5.1)
32
41
  parallel (~> 1.10)
33
42
  parser (>= 2.7.0.1)
34
43
  rainbow (>= 2.2.2, < 4.0)
44
+ rexml
35
45
  ruby-progressbar (~> 1.7)
36
46
  unicode-display_width (>= 1.4.0, < 1.7)
37
47
  ruby-progressbar (1.10.1)
48
+ thor (1.0.1)
38
49
  unicode-display_width (1.6.1)
39
50
 
40
51
  PLATFORMS
41
52
  ruby
42
53
 
43
54
  DEPENDENCIES
55
+ appraisal (~> 2.2)
56
+ byebug (~> 11.0)
57
+ ed25519 (~> 1.2)
44
58
  openssl-signature_algorithm!
45
- rake (~> 12.0)
59
+ rake (~> 13.0)
46
60
  rspec (~> 3.0)
47
- rubocop (~> 0.79.0)
61
+ rubocop (~> 0.80.1)
48
62
 
49
63
  BUNDLED WITH
50
- 2.1.4
64
+ 2.2.8
data/README.md CHANGED
@@ -1,11 +1,18 @@
1
1
  # OpenSSL::SignatureAlgorithm
2
2
 
3
- This tiny library introduces `OpenSSL::SignatureAlgorithm::ECDSA`, `OpenSSL::SignatureAlgorithm::RSAPSS` and `OpenSSL::SignatureAlgorithm::RSAPKCS1`, so that you can reason in terms of signature algorithms when signing and/or verifying signatures―instead of keys.
3
+ > ECDSA, EdDSA, RSA-PSS and RSA-PKCS#1 signature algorithms for ruby
4
4
 
5
- This provides a higher level of abstraction, on top of `openssl`'s gem `OpenSSL::PKey::EC`, `OpenSSL::PKey::EC::Point` and `OpenSSL::PKey::RSA`.
5
+ Sign and verify using signature algorithm wrappers, instead of key objects.
6
6
 
7
- [![Gem](https://img.shields.io/gem/v/openssl-signature_algorithm.svg?style=flat-square)](https://rubygems.org/gems/openssl-signature_algorithm)
8
- [![Travis](https://img.shields.io/travis/cedarcode/openssl-signature_algorithm.svg?style=flat-square)](https://travis-ci.org/cedarcode/openssl-signature_algorithm)
7
+ Provides `OpenSSL::SignatureAlgorithm::ECDSA`, `OpenSSL::SignatureAlgorithm::RSAPSS`
8
+ and `OpenSSL::SignatureAlgorithm::RSAPKCS1` ruby object wrappers on top of `OpenSSL::PKey::EC`
9
+ and `OpenSSL::PKey::RSA`, so that you can reason in terms of the algorithms and do less when
10
+ signing or verifying signatures.
11
+
12
+ Loosely inspired by [rbnacl](https://github.com/RubyCrypto/rbnacl)'s [Digital Signatures](https://github.com/RubyCrypto/rbnacl/wiki/Digital-Signatures) interface.
13
+
14
+ [![Gem](https://img.shields.io/gem/v/openssl-signature_algorithm.svg?style=flat-square&color=informational)](https://rubygems.org/gems/openssl-signature_algorithm)
15
+ [![Actions Build](https://github.com/cedarcode/openssl-signature_algorithm/workflows/build/badge.svg)](https://github.com/cedarcode/openssl-signature_algorithm/actions)
9
16
 
10
17
  ## Installation
11
18
 
@@ -31,15 +38,38 @@ Or install it yourself as:
31
38
  to_be_signed = "to-be-signed"
32
39
 
33
40
  # Signer
34
- algorithm = OpenSSL::SignatureAlgorithm::ECDSA.new("256")
41
+ algorithm = OpenSSL::SignatureAlgorithm::ECDSA.new
42
+ signing_key = algorithm.generate_signing_key
43
+ signature = algorithm.sign(to_be_signed)
44
+
45
+ # Signer sends verify key to Verifier
46
+ verify_key_string = signing_key.verify_key.serialize
47
+
48
+ # Verifier
49
+ verify_key = OpenSSL::SignatureAlgorithm::ECDSA::VerifyKey.deserialize(verify_key_string)
50
+ algorithm = OpenSSL::SignatureAlgorithm::ECDSA.new
51
+ algorithm.verify_key = verify_key
52
+ algorithm.verify(signature, to_be_signed)
53
+ ```
54
+
55
+ ### EdDSA
56
+
57
+ Requires adding the `ed25519` gem to your `Gemfile`
58
+
59
+ ```ruby
60
+ to_be_signed = "to-be-signed"
61
+
62
+ # Signer
63
+ algorithm = OpenSSL::SignatureAlgorithm::EdDSA.new
35
64
  signing_key = algorithm.generate_signing_key
36
65
  signature = algorithm.sign(to_be_signed)
37
66
 
38
67
  # Signer sends verify key to Verifier
39
- verify_key = signing_key.verify_key
68
+ verify_key_string = signing_key.verify_key.serialize
40
69
 
41
70
  # Verifier
42
- algorithm = OpenSSL::SignatureAlgorithm::ECDSA.new("256")
71
+ verify_key = OpenSSL::SignatureAlgorithm::EdDSA::VerifyKey.deserialize(verify_key_string)
72
+ algorithm = OpenSSL::SignatureAlgorithm::EdDSA.new
43
73
  algorithm.verify_key = verify_key
44
74
  algorithm.verify(signature, to_be_signed)
45
75
  ```
@@ -50,15 +80,16 @@ algorithm.verify(signature, to_be_signed)
50
80
  to_be_signed = "to-be-signed"
51
81
 
52
82
  # Signer
53
- algorithm = OpenSSL::SignatureAlgorithm::RSAPSS.new("256")
83
+ algorithm = OpenSSL::SignatureAlgorithm::RSAPSS.new
54
84
  signing_key = algorithm.generate_signing_key
55
85
  signature = algorithm.sign(to_be_signed)
56
86
 
57
87
  # Signer sends verify key to Verifier
58
- verify_key = signing_key.verify_key
88
+ verify_key_string = signing_key.verify_key.serialize
59
89
 
60
90
  # Verifier
61
- algorithm = OpenSSL::SignatureAlgorithm::RSAPSS.new("256")
91
+ verify_key = OpenSSL::SignatureAlgorithm::RSAPSS::VerifyKey.deserialize(verify_key_string)
92
+ algorithm = OpenSSL::SignatureAlgorithm::RSAPSS.new
62
93
  algorithm.verify_key = verify_key
63
94
  algorithm.verify(signature, to_be_signed)
64
95
  ```
@@ -69,15 +100,16 @@ algorithm.verify(signature, to_be_signed)
69
100
  to_be_signed = "to-be-signed"
70
101
 
71
102
  # Signer
72
- algorithm = OpenSSL::SignatureAlgorithm::RSAPKCS1.new("256")
103
+ algorithm = OpenSSL::SignatureAlgorithm::RSAPKCS1.new
73
104
  signing_key = algorithm.generate_signing_key
74
105
  signature = algorithm.sign(to_be_signed)
75
106
 
76
107
  # Signer sends verify key to Verifier
77
- verify_key = signing_key.verify_key
108
+ verify_key_string = signing_key.verify_key.serialize
78
109
 
79
110
  # Verifier
80
- algorithm = OpenSSL::SignatureAlgorithm::RSAPKCS1.new("256")
111
+ verify_key = OpenSSL::SignatureAlgorithm::RSAPKCS1::VerifyKey.deserialize(verify_key_string)
112
+ algorithm = OpenSSL::SignatureAlgorithm::RSAPKCS1.new
81
113
  algorithm.verify_key = verify_key
82
114
  algorithm.verify(signature, to_be_signed)
83
115
  ```
@@ -0,0 +1,2 @@
1
+ ---
2
+ BUNDLE_RETRY: "1"
@@ -0,0 +1,13 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "appraisal", "~> 2.2"
6
+ gem "byebug", "~> 11.0"
7
+ gem "rake", "~> 13.0"
8
+ gem "rspec", "~> 3.0"
9
+ gem "rubocop", "~> 0.80.1"
10
+ gem "ed25519", "~> 1.2"
11
+ gem "openssl", "~> 2.0.0"
12
+
13
+ gemspec path: "../"
@@ -0,0 +1,13 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "appraisal", "~> 2.2"
6
+ gem "byebug", "~> 11.0"
7
+ gem "rake", "~> 13.0"
8
+ gem "rspec", "~> 3.0"
9
+ gem "rubocop", "~> 0.80.1"
10
+ gem "ed25519", "~> 1.2"
11
+ gem "openssl", "~> 2.1.0"
12
+
13
+ gemspec path: "../"
@@ -0,0 +1,13 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "appraisal", "~> 2.2"
6
+ gem "byebug", "~> 11.0"
7
+ gem "rake", "~> 13.0"
8
+ gem "rspec", "~> 3.0"
9
+ gem "rubocop", "~> 0.80.1"
10
+ gem "ed25519", "~> 1.2"
11
+ gem "openssl", "~> 2.2.0"
12
+
13
+ gemspec path: "../"
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "openssl/signature_algorithm/ecdsa"
4
+ require "openssl/signature_algorithm/eddsa"
4
5
  require "openssl/signature_algorithm/error"
5
6
  require "openssl/signature_algorithm/rsapss"
6
7
  require "openssl/signature_algorithm/rsapkcs1"
@@ -5,25 +5,39 @@ require "openssl/signature_algorithm/error"
5
5
 
6
6
  module OpenSSL
7
7
  module SignatureAlgorithm
8
+ class SignatureVerificationError < Error; end
9
+ class UnsupportedParameterError < Error; end
10
+ class VerifyKeyError < Error; end
11
+
8
12
  class Base
9
- attr_reader :digest_length, :signing_key
10
- attr_accessor :verify_key
13
+ attr_reader :signing_key, :verify_key
11
14
 
12
- def initialize(digest_length)
13
- @digest_length = digest_length
15
+ def verify_key=(key)
16
+ if compatible_verify_key?(key)
17
+ @verify_key = key
18
+ else
19
+ raise(OpenSSL::SignatureAlgorithm::VerifyKeyError, "Incompatible verify key for algorithm")
20
+ end
14
21
  end
15
22
 
16
- def sign(data)
17
- signing_key.sign(hash_function, data)
23
+ def compatible_verify_key?(verify_key)
24
+ verify_key.respond_to?(:verify)
18
25
  end
19
26
 
20
- def hash_function
21
- OpenSSL::Digest.new("sha#{digest_length}")
27
+ def sign(data)
28
+ signing_key.sign(hash_function, data)
22
29
  end
23
30
 
24
31
  def verify(signature, verification_data)
25
- verify_key.verify(hash_function, signature, verification_data) ||
26
- raise(OpenSSL::SignatureAlgorithm::Error, "Signature verification failed")
32
+ formatted_signature =
33
+ if respond_to?(:formatted_signature, true)
34
+ formatted_signature(signature)
35
+ else
36
+ signature
37
+ end
38
+
39
+ verify_key.verify(hash_function, formatted_signature, verification_data) ||
40
+ raise(OpenSSL::SignatureAlgorithm::SignatureVerificationError, "Signature verification failed")
27
41
  end
28
42
  end
29
43
  end
@@ -6,6 +6,8 @@ require "openssl/signature_algorithm/base"
6
6
  module OpenSSL
7
7
  module SignatureAlgorithm
8
8
  class ECDSA < Base
9
+ BYTE_LENGTH = 8
10
+
9
11
  class SigningKey < OpenSSL::PKey::EC
10
12
  def initialize(*args)
11
13
  super(*args).generate_key
@@ -17,27 +19,93 @@ module OpenSSL
17
19
  end
18
20
 
19
21
  class VerifyKey < OpenSSL::PKey::EC::Point
20
- def verify(*args)
21
- ec_key = OpenSSL::PKey::EC.new(group)
22
- ec_key.public_key = self
22
+ def self.deserialize(pem_string)
23
+ new(OpenSSL::PKey::EC.new(pem_string).public_key)
24
+ end
23
25
 
26
+ def serialize
27
+ ec_key.to_pem
28
+ end
29
+
30
+ def ec_key
31
+ @ec_key ||=
32
+ begin
33
+ ec_key = OpenSSL::PKey::EC.new(group)
34
+ ec_key.public_key = self
35
+
36
+ ec_key
37
+ end
38
+ end
39
+
40
+ def verify(*args)
24
41
  ec_key.verify(*args)
25
42
  end
26
43
  end
27
44
 
28
- CURVE_BY_DIGEST_LENGTH = {
29
- "256" => "prime256v1",
30
- "384" => "secp384r1",
31
- "512" => "secp521r1"
32
- }.freeze
45
+ ACCEPTED_PARAMETERS = [
46
+ { curve: "prime256v1", hash_function: "SHA256" },
47
+ { curve: "secp384r1", hash_function: "SHA384" },
48
+ { curve: "secp521r1", hash_function: "SHA512" },
49
+ { curve: "secp256k1", hash_function: "SHA256" }
50
+ ].freeze
51
+
52
+ attr_reader :curve, :hash_function
53
+
54
+ def initialize(curve: nil, hash_function: nil)
55
+ @curve, @hash_function = pick_parameters(curve, hash_function)
56
+ end
33
57
 
34
58
  def generate_signing_key
35
- @signing_key = SigningKey.new(curve_name)
59
+ @signing_key = SigningKey.new(curve)
36
60
  end
37
61
 
38
- def curve_name
39
- CURVE_BY_DIGEST_LENGTH[digest_length] ||
40
- raise(OpenSSL::SignatureAlgorithm::Error, "Unsupported digest length #{digest_length}")
62
+ def compatible_verify_key?(key)
63
+ super && key.respond_to?(:group) && key.group.curve_name == curve
64
+ end
65
+
66
+ private
67
+
68
+ # Borrowed from jwt rubygem.
69
+ # https://github.com/jwt/ruby-jwt/blob/7a6a3f1dbaff806993156d1dff9c217bb2523ff8/lib/jwt/security_utils.rb#L34-L39
70
+ #
71
+ # Hopefully this will be provided by openssl rubygem in the future.
72
+ def formatted_signature(signature)
73
+ n = (verify_key_length.to_f / BYTE_LENGTH).ceil
74
+
75
+ if signature.size == n * 2
76
+ r = signature[0..(n - 1)]
77
+ s = signature[n..-1]
78
+
79
+ OpenSSL::ASN1::Sequence.new([r, s].map { |int| OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(int, 2)) }).to_der
80
+ else
81
+ signature
82
+ end
83
+ end
84
+
85
+ def verify_key_length
86
+ verify_key.group.degree
87
+ end
88
+
89
+ def pick_parameters(curve, hash_function)
90
+ parameters = ACCEPTED_PARAMETERS.detect do |params|
91
+ if curve
92
+ if hash_function
93
+ params[:curve] == curve && params[:hash_function] == hash_function
94
+ else
95
+ params[:curve] == curve
96
+ end
97
+ elsif hash_function
98
+ params[:hash_function] == hash_function
99
+ else
100
+ true
101
+ end
102
+ end
103
+
104
+ if parameters
105
+ [parameters[:curve], parameters[:hash_function]]
106
+ else
107
+ raise(OpenSSL::SignatureAlgorithm::UnsupportedParameterError, "Unsupported algorithm parameters")
108
+ end
41
109
  end
42
110
  end
43
111
  end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ gem "ed25519", ">= 1.0.0"
5
+ require "ed25519"
6
+ rescue LoadError
7
+ warn "OpenSSL::SignatureAlgorithm::EdDSA requires the ed25519 gem, version 1.0 or higher. "\
8
+ "Please add it to your Gemfile: `gem \"ed25519\", \"~> 1.0\"`"
9
+ raise
10
+ end
11
+
12
+ require "openssl/signature_algorithm/base"
13
+
14
+ module OpenSSL
15
+ module SignatureAlgorithm
16
+ class EdDSA < Base
17
+ class SigningKey < ::Ed25519::SigningKey
18
+ def verify_key
19
+ VerifyKey.new(keypair[32, 32])
20
+ end
21
+ end
22
+
23
+ class VerifyKey < ::Ed25519::VerifyKey
24
+ def self.deserialize(key_bytes)
25
+ new(key_bytes)
26
+ end
27
+
28
+ def serialize
29
+ to_bytes
30
+ end
31
+ end
32
+
33
+ def generate_signing_key
34
+ @signing_key = SigningKey.generate
35
+ end
36
+
37
+ def sign(data)
38
+ signing_key.sign(data)
39
+ end
40
+
41
+ def verify(signature, verification_data)
42
+ verify_key.verify(signature, verification_data)
43
+ rescue ::Ed25519::VerifyError
44
+ raise(OpenSSL::SignatureAlgorithm::SignatureVerificationError, "Signature verification failed")
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "openssl"
4
+ require "openssl/signature_algorithm/base"
5
+
6
+ module OpenSSL
7
+ module SignatureAlgorithm
8
+ class RSA < Base
9
+ class SigningKey < OpenSSL::PKey::RSA
10
+ def verify_key
11
+ VerifyKey.new(public_key.to_pem)
12
+ end
13
+ end
14
+
15
+ class VerifyKey < OpenSSL::PKey::RSA
16
+ class << self
17
+ alias_method :deserialize, :new
18
+ end
19
+
20
+ def serialize
21
+ to_pem
22
+ end
23
+ end
24
+
25
+ ACCEPTED_HASH_FUNCTIONS = ["SHA256", "SHA384", "SHA512"].freeze
26
+ DEFAULT_KEY_SIZE = 2048
27
+
28
+ attr_reader :hash_function
29
+
30
+ def initialize(hash_function: self.class::ACCEPTED_HASH_FUNCTIONS.first)
31
+ if self.class::ACCEPTED_HASH_FUNCTIONS.include?(hash_function)
32
+ @hash_function = hash_function
33
+ else
34
+ raise(OpenSSL::SignatureAlgorithm::UnsupportedParameterError, "Unsupported hash function '#{hash_function}'")
35
+ end
36
+ end
37
+
38
+ def generate_signing_key(size: DEFAULT_KEY_SIZE)
39
+ @signing_key = SigningKey.new(size)
40
+ end
41
+ end
42
+ end
43
+ end
@@ -1,22 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "openssl"
4
- require "openssl/signature_algorithm/base"
4
+ require "openssl/signature_algorithm/rsa"
5
5
 
6
6
  module OpenSSL
7
7
  module SignatureAlgorithm
8
- class RSAPKCS1 < Base
9
- class SigningKey < OpenSSL::PKey::RSA
10
- def verify_key
11
- public_key
12
- end
13
- end
14
-
15
- DEFAULT_KEY_SIZE = 2048
16
-
17
- def generate_signing_key(size: DEFAULT_KEY_SIZE)
18
- @signing_key = SigningKey.new(size)
19
- end
8
+ class RSAPKCS1 < RSA
20
9
  end
21
10
  end
22
11
  end
@@ -1,23 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "openssl"
4
- require "openssl/signature_algorithm/base"
4
+ require "openssl/signature_algorithm/rsa"
5
5
 
6
6
  module OpenSSL
7
7
  module SignatureAlgorithm
8
- class RSAPSS < Base
9
- class SigningKey < OpenSSL::PKey::RSA
10
- def verify_key
11
- public_key
12
- end
13
- end
14
-
15
- DEFAULT_KEY_SIZE = 2048
16
-
17
- def generate_signing_key(size: DEFAULT_KEY_SIZE)
18
- @signing_key = SigningKey.new(size)
19
- end
20
-
8
+ class RSAPSS < RSA
21
9
  def sign(data)
22
10
  signing_key.sign_pss(hash_function, data, salt_length: :max, mgf1_hash: mgf1_hash_function)
23
11
  end
@@ -29,7 +17,7 @@ module OpenSSL
29
17
  verification_data,
30
18
  salt_length: :auto,
31
19
  mgf1_hash: mgf1_hash_function
32
- ) || raise(OpenSSL::SignatureAlgorithm::Error, "Signature verification failed")
20
+ ) || raise(OpenSSL::SignatureAlgorithm::SignatureVerificationError, "Signature verification failed")
33
21
  end
34
22
 
35
23
  def mgf1_hash_function
@@ -2,6 +2,6 @@
2
2
 
3
3
  module OpenSSL
4
4
  module SignatureAlgorithm
5
- VERSION = "0.1.1"
5
+ VERSION = "1.1.0"
6
6
  end
7
7
  end
@@ -5,20 +5,15 @@ require_relative 'lib/openssl/signature_algorithm/version'
5
5
  Gem::Specification.new do |spec|
6
6
  spec.name = "openssl-signature_algorithm"
7
7
  spec.version = OpenSSL::SignatureAlgorithm::VERSION
8
- spec.authors = ["Gonzalo"]
8
+ spec.authors = ["Gonzalo Rodriguez"]
9
9
  spec.email = ["gonzalo@cedarcode.com"]
10
10
  spec.license = "Apache-2.0"
11
11
 
12
- spec.summary = "Signature Algorithm abstraction for openssl ruby gem"
13
- spec.description = <<-DESC
14
- This tiny library introduces `OpenSSL::SignatureAlgorithm::ECDSA`,
15
- `OpenSSL::SignatureAlgorithm::RSAPSS` and `OpenSSL::SignatureAlgorithm::RSAPKCS1`,
16
- so that you can reason in terms of signature algorithms when signing and/or
17
- verifying signatures―instead of keys.
18
- DESC
12
+ spec.summary = "ECDSA, EdDSA, RSA-PSS and RSA-PKCS#1 algorithms for ruby"
13
+ spec.description = spec.summary
19
14
 
20
15
  spec.homepage = "https://github.com/cedarcode/openssl-signature_algorithm"
21
- spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
16
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
22
17
 
23
18
  spec.metadata["homepage_uri"] = spec.homepage
24
19
  spec.metadata["source_code_uri"] = spec.homepage
@@ -32,4 +27,6 @@ Gem::Specification.new do |spec|
32
27
  spec.bindir = "exe"
33
28
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
34
29
  spec.require_paths = ["lib"]
30
+
31
+ spec.add_runtime_dependency "openssl", "~> 2.0"
35
32
  end
metadata CHANGED
@@ -1,30 +1,41 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openssl-signature_algorithm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
- - Gonzalo
7
+ - Gonzalo Rodriguez
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-01-29 00:00:00.000000000 Z
12
- dependencies: []
13
- description: |2
14
- This tiny library introduces `OpenSSL::SignatureAlgorithm::ECDSA`,
15
- `OpenSSL::SignatureAlgorithm::RSAPSS` and `OpenSSL::SignatureAlgorithm::RSAPKCS1`,
16
- so that you can reason in terms of signature algorithms when signing and/or
17
- verifying signatures―instead of keys.
11
+ date: 2021-02-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: openssl
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ description: ECDSA, EdDSA, RSA-PSS and RSA-PKCS#1 algorithms for ruby
18
28
  email:
19
29
  - gonzalo@cedarcode.com
20
30
  executables: []
21
31
  extensions: []
22
32
  extra_rdoc_files: []
23
33
  files:
34
+ - ".github/workflows/build.yml"
24
35
  - ".gitignore"
25
36
  - ".rspec"
26
37
  - ".rubocop.yml"
27
- - ".travis.yml"
38
+ - Appraisals
28
39
  - CHANGELOG.md
29
40
  - Gemfile
30
41
  - Gemfile.lock
@@ -33,10 +44,16 @@ files:
33
44
  - Rakefile
34
45
  - bin/console
35
46
  - bin/setup
47
+ - gemfiles/.bundle/config
48
+ - gemfiles/openssl_2_0.gemfile
49
+ - gemfiles/openssl_2_1.gemfile
50
+ - gemfiles/openssl_2_2.gemfile
36
51
  - lib/openssl/signature_algorithm.rb
37
52
  - lib/openssl/signature_algorithm/base.rb
38
53
  - lib/openssl/signature_algorithm/ecdsa.rb
54
+ - lib/openssl/signature_algorithm/eddsa.rb
39
55
  - lib/openssl/signature_algorithm/error.rb
56
+ - lib/openssl/signature_algorithm/rsa.rb
40
57
  - lib/openssl/signature_algorithm/rsapkcs1.rb
41
58
  - lib/openssl/signature_algorithm/rsapss.rb
42
59
  - lib/openssl/signature_algorithm/version.rb
@@ -56,15 +73,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
56
73
  requirements:
57
74
  - - ">="
58
75
  - !ruby/object:Gem::Version
59
- version: 2.5.0
76
+ version: 2.4.0
60
77
  required_rubygems_version: !ruby/object:Gem::Requirement
61
78
  requirements:
62
79
  - - ">="
63
80
  - !ruby/object:Gem::Version
64
81
  version: '0'
65
82
  requirements: []
66
- rubygems_version: 3.1.2
83
+ rubygems_version: 3.2.8
67
84
  signing_key:
68
85
  specification_version: 4
69
- summary: Signature Algorithm abstraction for openssl ruby gem
86
+ summary: ECDSA, EdDSA, RSA-PSS and RSA-PKCS#1 algorithms for ruby
70
87
  test_files: []
data/.travis.yml DELETED
@@ -1,8 +0,0 @@
1
- ---
2
- language: ruby
3
- cache: bundler
4
- rvm:
5
- - 2.7.0
6
- - 2.6.5
7
- - 2.5.7
8
- before_install: gem install bundler -v 2.1.4