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 +4 -4
- data/.github/workflows/build.yml +37 -0
- data/.gitignore +3 -0
- data/.rspec +1 -0
- data/.rubocop.yml +4 -4
- data/Appraisals +13 -0
- data/CHANGELOG.md +71 -0
- data/Gemfile +5 -2
- data/Gemfile.lock +22 -8
- data/README.md +45 -13
- data/gemfiles/.bundle/config +2 -0
- data/gemfiles/openssl_2_0.gemfile +13 -0
- data/gemfiles/openssl_2_1.gemfile +13 -0
- data/gemfiles/openssl_2_2.gemfile +13 -0
- data/lib/openssl/signature_algorithm.rb +1 -0
- data/lib/openssl/signature_algorithm/base.rb +24 -10
- data/lib/openssl/signature_algorithm/ecdsa.rb +80 -12
- data/lib/openssl/signature_algorithm/eddsa.rb +48 -0
- data/lib/openssl/signature_algorithm/rsa.rb +43 -0
- data/lib/openssl/signature_algorithm/rsapkcs1.rb +2 -13
- data/lib/openssl/signature_algorithm/rsapss.rb +3 -15
- data/lib/openssl/signature_algorithm/version.rb +1 -1
- data/openssl-signature_algorithm.gemspec +6 -9
- metadata +30 -13
- data/.travis.yml +0 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b8ab663827b9c60f9719579871f55a1b12001374d444e9b9194d2708395ba8af
|
4
|
+
data.tar.gz: 8af2c52eea842562e1122bd8824bb8eb79ed8923648d24414b11d7a7d0b9adea
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
data/.rspec
CHANGED
data/.rubocop.yml
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
AllCops:
|
2
|
-
TargetRubyVersion: 2.
|
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
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 "
|
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.
|
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.
|
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.
|
21
|
+
parser (2.7.0.5)
|
14
22
|
ast (~> 2.4.0)
|
15
23
|
rainbow (3.0.0)
|
16
|
-
rake (
|
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.
|
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.
|
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 (~>
|
59
|
+
rake (~> 13.0)
|
46
60
|
rspec (~> 3.0)
|
47
|
-
rubocop (~> 0.
|
61
|
+
rubocop (~> 0.80.1)
|
48
62
|
|
49
63
|
BUNDLED WITH
|
50
|
-
2.
|
64
|
+
2.2.8
|
data/README.md
CHANGED
@@ -1,11 +1,18 @@
|
|
1
1
|
# OpenSSL::SignatureAlgorithm
|
2
2
|
|
3
|
-
|
3
|
+
> ECDSA, EdDSA, RSA-PSS and RSA-PKCS#1 signature algorithms for ruby
|
4
4
|
|
5
|
-
|
5
|
+
Sign and verify using signature algorithm wrappers, instead of key objects.
|
6
6
|
|
7
|
-
|
8
|
-
|
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
|
+
[](https://rubygems.org/gems/openssl-signature_algorithm)
|
15
|
+
[](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
|
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
|
-
|
68
|
+
verify_key_string = signing_key.verify_key.serialize
|
40
69
|
|
41
70
|
# Verifier
|
42
|
-
|
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
|
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
|
-
|
88
|
+
verify_key_string = signing_key.verify_key.serialize
|
59
89
|
|
60
90
|
# Verifier
|
61
|
-
|
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
|
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
|
-
|
108
|
+
verify_key_string = signing_key.verify_key.serialize
|
78
109
|
|
79
110
|
# Verifier
|
80
|
-
|
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,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: "../"
|
@@ -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 :
|
10
|
-
attr_accessor :verify_key
|
13
|
+
attr_reader :signing_key, :verify_key
|
11
14
|
|
12
|
-
def
|
13
|
-
|
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
|
17
|
-
|
23
|
+
def compatible_verify_key?(verify_key)
|
24
|
+
verify_key.respond_to?(:verify)
|
18
25
|
end
|
19
26
|
|
20
|
-
def
|
21
|
-
|
27
|
+
def sign(data)
|
28
|
+
signing_key.sign(hash_function, data)
|
22
29
|
end
|
23
30
|
|
24
31
|
def verify(signature, verification_data)
|
25
|
-
|
26
|
-
|
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
|
21
|
-
|
22
|
-
|
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
|
-
|
29
|
-
"
|
30
|
-
"
|
31
|
-
"
|
32
|
-
|
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(
|
59
|
+
@signing_key = SigningKey.new(curve)
|
36
60
|
end
|
37
61
|
|
38
|
-
def
|
39
|
-
|
40
|
-
|
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/
|
4
|
+
require "openssl/signature_algorithm/rsa"
|
5
5
|
|
6
6
|
module OpenSSL
|
7
7
|
module SignatureAlgorithm
|
8
|
-
class RSAPKCS1 <
|
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/
|
4
|
+
require "openssl/signature_algorithm/rsa"
|
5
5
|
|
6
6
|
module OpenSSL
|
7
7
|
module SignatureAlgorithm
|
8
|
-
class RSAPSS <
|
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::
|
20
|
+
) || raise(OpenSSL::SignatureAlgorithm::SignatureVerificationError, "Signature verification failed")
|
33
21
|
end
|
34
22
|
|
35
23
|
def mgf1_hash_function
|
@@ -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 = "
|
13
|
-
spec.description =
|
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.
|
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:
|
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:
|
12
|
-
dependencies:
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
-
-
|
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.
|
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.
|
83
|
+
rubygems_version: 3.2.8
|
67
84
|
signing_key:
|
68
85
|
specification_version: 4
|
69
|
-
summary:
|
86
|
+
summary: ECDSA, EdDSA, RSA-PSS and RSA-PKCS#1 algorithms for ruby
|
70
87
|
test_files: []
|