pkcs7-cryptographer 0.2.2 → 1.1.1
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/.rubocop.yml +4 -1
- data/Gemfile.lock +17 -1
- data/README.md +60 -10
- data/lib/pkcs7/cryptographer/entity.rb +8 -7
- data/lib/pkcs7/cryptographer/initializers.rb +9 -0
- data/lib/pkcs7/cryptographer/version.rb +1 -1
- data/lib/pkcs7/cryptographer.rb +81 -7
- data/pkcs7-cryptographer.gemspec +4 -1
- metadata +31 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d8e03b7542f2787153a2243935c5a0c748abae6fec0e066ce08ee158f21cf75f
|
4
|
+
data.tar.gz: 25baf89c080fb55f909e3d92d22e1ec05810e2ed91d00d47e83e0f6460c75f32
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 527dc589baa95742d7b81d825373efac10f136791f5d97e4970565a3e01e5e5f2c004731d13b59150174858865c295b93ffb8e8210c9ebb714eb0d9840254935
|
7
|
+
data.tar.gz: 4e5595dca5adeb1daa3b58a00aeaeb463011c6e86e2a2036a1ba4afeba1268d141d8cf04212be08abdd287636aa6838a1bde49ad0ddd17ea6e647a1718b30895
|
data/.rubocop.yml
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,15 +1,26 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
pkcs7-cryptographer (
|
4
|
+
pkcs7-cryptographer (1.1.1)
|
5
|
+
activesupport (>= 6.1.4.1)
|
5
6
|
|
6
7
|
GEM
|
7
8
|
remote: https://rubygems.org/
|
8
9
|
specs:
|
10
|
+
activesupport (6.1.4.1)
|
11
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
12
|
+
i18n (>= 1.6, < 2)
|
13
|
+
minitest (>= 5.1)
|
14
|
+
tzinfo (~> 2.0)
|
15
|
+
zeitwerk (~> 2.3)
|
9
16
|
ast (2.4.2)
|
10
17
|
coderay (1.1.3)
|
18
|
+
concurrent-ruby (1.1.9)
|
11
19
|
diff-lcs (1.4.4)
|
20
|
+
i18n (1.8.10)
|
21
|
+
concurrent-ruby (~> 1.0)
|
12
22
|
method_source (1.0.0)
|
23
|
+
minitest (5.14.4)
|
13
24
|
parallel (1.20.1)
|
14
25
|
parser (3.0.0.0)
|
15
26
|
ast (~> 2.4.1)
|
@@ -50,7 +61,11 @@ GEM
|
|
50
61
|
rubocop (~> 1.0)
|
51
62
|
rubocop-ast (>= 1.1.0)
|
52
63
|
ruby-progressbar (1.11.0)
|
64
|
+
timecop (0.9.4)
|
65
|
+
tzinfo (2.0.4)
|
66
|
+
concurrent-ruby (~> 1.0)
|
53
67
|
unicode-display_width (2.0.0)
|
68
|
+
zeitwerk (2.4.2)
|
54
69
|
|
55
70
|
PLATFORMS
|
56
71
|
x86_64-darwin-19
|
@@ -64,6 +79,7 @@ DEPENDENCIES
|
|
64
79
|
rubocop (= 1.12.0)
|
65
80
|
rubocop-rake (= 0.5.1)
|
66
81
|
rubocop-rspec (= 2.2.0)
|
82
|
+
timecop (= 0.9.4)
|
67
83
|
|
68
84
|
BUNDLED WITH
|
69
85
|
2.2.3
|
data/README.md
CHANGED
@@ -4,13 +4,12 @@
|
|
4
4
|

|
5
5
|
|
6
6
|
|
7
|
-
|
8
|
-
Cryptographer is an small utility to encrypt and decrypt messages
|
7
|
+
Cryptographer is an small utility to encrypt, sign and decrypt messages
|
9
8
|
using PKCS7.
|
10
9
|
|
11
10
|
PKCS7 is used to store signed and encrypted data.This specific implementation
|
12
|
-
uses aes-256-cbc as chipher in the encryption process. If you want to read
|
13
|
-
information about the involved data structures and theory around this,
|
11
|
+
uses `aes-256-cbc` as chipher in the encryption process. If you want to read
|
12
|
+
more information about the involved data structures and theory around this,
|
14
13
|
please visit:
|
15
14
|
|
16
15
|
- https://ruby-doc.org/stdlib-3.0.0/libdoc/openssl/rdoc/OpenSSL.html
|
@@ -37,6 +36,8 @@ Or install it yourself as:
|
|
37
36
|
```
|
38
37
|
## Usage
|
39
38
|
|
39
|
+
### Using bare PKCS7::Cryptographer
|
40
|
+
|
40
41
|
After installing the gem you will have the `PKCS7::Cryptographer` available.
|
41
42
|
|
42
43
|
`PKCS7::Cryptographer` is a class that provides two public methods:
|
@@ -44,12 +45,13 @@ After installing the gem you will have the `PKCS7::Cryptographer` available.
|
|
44
45
|
- `sign_and_encrypt`
|
45
46
|
- `decrypt_and_verify`
|
46
47
|
|
47
|
-
|
48
|
+
If you want to use the barebones cryptographer, you can. Please look at the
|
49
|
+
following example:
|
48
50
|
|
49
51
|
|
50
|
-
### Using bare PKCS7::Cryptographer
|
51
52
|
|
52
53
|
```ruby
|
54
|
+
require 'pkcs7/cryptographer'
|
53
55
|
|
54
56
|
# This script assumes you have a read_file method to read the certificates and
|
55
57
|
# keys.
|
@@ -71,7 +73,7 @@ Read the following examples to get a better undertanding:
|
|
71
73
|
# Only the client can read the message since the required public
|
72
74
|
# certificate to read it is the client certificate.
|
73
75
|
|
74
|
-
# It could be read if the CA_STORE of the reader has certificate of the
|
76
|
+
# It could be read if the CA_STORE of the reader has the certificate of the
|
75
77
|
# CA that signed the client certificate as trusted.
|
76
78
|
|
77
79
|
cryptographer = PKCS7::Cryptographer.new
|
@@ -84,6 +86,8 @@ Read the following examples to get a better undertanding:
|
|
84
86
|
public_certificate: CLIENT_CERTIFICATE
|
85
87
|
)
|
86
88
|
|
89
|
+
# encrypted_data is a PEM formatted string
|
90
|
+
|
87
91
|
# READ MESSAGE IN CLIENT
|
88
92
|
# ----------------------------------------------------------------------------
|
89
93
|
# Store of trusted certificates
|
@@ -103,8 +107,16 @@ Read the following examples to get a better undertanding:
|
|
103
107
|
|
104
108
|
### Using PKCS7::Cryptographer::Entity
|
105
109
|
|
110
|
+
There is a possibility to use entities to communicate using encrypted data. In
|
111
|
+
order to use it you have to import the entities implementation.
|
112
|
+
|
113
|
+
Please look at the following example:
|
114
|
+
|
106
115
|
```ruby
|
107
116
|
|
117
|
+
require 'pkcs7/cryptographer'
|
118
|
+
require 'pkcs7/cryptographer/entity'
|
119
|
+
|
108
120
|
# This script assumes you have a read_file method to read the certificates and
|
109
121
|
# keys. If you have any question about how to generate the keys/certificates
|
110
122
|
# check this post: https://mariadb.com/kb/en/certificate-creation-with-openssl/
|
@@ -129,24 +141,62 @@ Read the following examples to get a better undertanding:
|
|
129
141
|
)
|
130
142
|
|
131
143
|
client_entity = PKCS7::Cryptographer::Entity.new(
|
132
|
-
certificate: CLIENT_CERTIFICATE
|
144
|
+
certificate: CLIENT_CERTIFICATE
|
133
145
|
)
|
134
146
|
|
135
147
|
# SEND MESSAGE TO THE CLIENT
|
136
148
|
# ----------------------------------------------------------------------------
|
137
149
|
data = "Victor Ibarbo"
|
138
|
-
encrypted_data = ca_entity.encrypt_data(data: data,
|
150
|
+
encrypted_data = ca_entity.encrypt_data(data: data, receiver: client_entity)
|
139
151
|
|
140
152
|
# READ MESSAGE IN CLIENT
|
141
153
|
# ----------------------------------------------------------------------------
|
142
154
|
decrypted_data = client_entity.decrypt_data(
|
143
155
|
data: encrypted_data,
|
144
|
-
|
156
|
+
sender: ca_entity
|
145
157
|
)
|
146
158
|
|
147
159
|
# decrypted_data returns: "Victor Ibarbo"
|
148
160
|
```
|
149
161
|
|
162
|
+
When using entities, all the complexity of knowing which PKI credentials to
|
163
|
+
send to the cryptographer dissapears. You only need to initialize the
|
164
|
+
entities and use the methods to indicate to whom the message will be sent.
|
165
|
+
|
166
|
+
If you want to verify if certain entity you defined "trust" another one, use the
|
167
|
+
`trustable_entity?(<the other entity>)`.
|
168
|
+
|
169
|
+
```ruby
|
170
|
+
ca_entity = PKCS7::Cryptographer::Entity.new(
|
171
|
+
key: CA_KEY,
|
172
|
+
certificate: CA_CERTIFICATE,
|
173
|
+
ca_store: CA_STORE
|
174
|
+
)
|
175
|
+
|
176
|
+
client_entity = PKCS7::Cryptographer::Entity.new(
|
177
|
+
certificate: CLIENT_CERTIFICATE
|
178
|
+
)
|
179
|
+
|
180
|
+
ca_entity.trustable_entity?(client_entity)
|
181
|
+
|
182
|
+
# Returns true because the client certificate was signed by the root
|
183
|
+
# certificate of the ca_authority.
|
184
|
+
```
|
185
|
+
|
186
|
+
When sending data to an entity, you will most of the time initialize the entity
|
187
|
+
only with the `certificate` keyword arguments. So, initializing a receiver will
|
188
|
+
most of the time looks like this:
|
189
|
+
|
190
|
+
```ruby
|
191
|
+
client_entity = PKCS7::Cryptographer::Entity.new(
|
192
|
+
certificate: CLIENT_CERTIFICATE
|
193
|
+
)
|
194
|
+
```
|
195
|
+
|
196
|
+
The entity above can't encrypt messages or decrypt them, if you want to decrypt
|
197
|
+
and encrypt the entity should have its the key (private key), certificate and
|
198
|
+
the list of trusted certificates of the entity (ca_store).
|
199
|
+
|
150
200
|
## Development
|
151
201
|
|
152
202
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
@@ -32,24 +32,24 @@ module PKCS7
|
|
32
32
|
@ca_store.verify(entity.certificate)
|
33
33
|
end
|
34
34
|
|
35
|
-
def encrypt_data(data:,
|
36
|
-
perform_safely(
|
35
|
+
def encrypt_data(data:, receiver:)
|
36
|
+
perform_safely(receiver) do
|
37
37
|
@cryptographer.sign_and_encrypt(
|
38
38
|
data: data,
|
39
39
|
key: @key,
|
40
40
|
certificate: @certificate,
|
41
|
-
public_certificate:
|
41
|
+
public_certificate: receiver.certificate
|
42
42
|
)
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
-
def decrypt_data(data:,
|
47
|
-
perform_safely(
|
46
|
+
def decrypt_data(data:, sender:)
|
47
|
+
perform_safely(sender) do
|
48
48
|
@cryptographer.decrypt_and_verify(
|
49
49
|
data: data,
|
50
50
|
key: @key,
|
51
51
|
certificate: @certificate,
|
52
|
-
public_certificate:
|
52
|
+
public_certificate: sender.certificate,
|
53
53
|
ca_store: @ca_store
|
54
54
|
)
|
55
55
|
end
|
@@ -61,7 +61,8 @@ module PKCS7
|
|
61
61
|
|
62
62
|
def perform_safely(entity)
|
63
63
|
return false unless trustable_entity?(entity)
|
64
|
-
return false unless @key
|
64
|
+
return false unless @key
|
65
|
+
|
65
66
|
yield
|
66
67
|
end
|
67
68
|
end
|
@@ -8,6 +8,11 @@ module PKCS7
|
|
8
8
|
# certificate, key or encrypted message string.
|
9
9
|
###
|
10
10
|
module Initializers
|
11
|
+
# PRIVATE METHODS
|
12
|
+
# ------------------------------------------------------------------------
|
13
|
+
|
14
|
+
private
|
15
|
+
|
11
16
|
def x509_certificate(certificate)
|
12
17
|
wrap_in_class_or_return(certificate, OpenSSL::X509::Certificate)
|
13
18
|
end
|
@@ -16,6 +21,10 @@ module PKCS7
|
|
16
21
|
wrap_in_class_or_return(key, OpenSSL::PKey::RSA)
|
17
22
|
end
|
18
23
|
|
24
|
+
def certificate_signing_request(request)
|
25
|
+
wrap_in_class_or_return(request, OpenSSL::X509::Request)
|
26
|
+
end
|
27
|
+
|
19
28
|
def pkcs7(pkcs7)
|
20
29
|
wrap_in_class_or_return(pkcs7, OpenSSL::PKCS7)
|
21
30
|
end
|
data/lib/pkcs7/cryptographer.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "openssl"
|
4
|
+
require "active_support/all"
|
4
5
|
require_relative "cryptographer/version"
|
5
6
|
require_relative "cryptographer/initializers"
|
6
7
|
|
@@ -17,6 +18,10 @@ module PKCS7
|
|
17
18
|
class Cryptographer
|
18
19
|
include PKCS7::Cryptographer::Initializers
|
19
20
|
|
21
|
+
# CONSTANS
|
22
|
+
# --------------------------------------------------------------------------
|
23
|
+
CYPHER_ALGORITHM = "aes-256-cbc"
|
24
|
+
|
20
25
|
# PUBLIC METHODS
|
21
26
|
# --------------------------------------------------------------------------
|
22
27
|
|
@@ -39,12 +44,7 @@ module PKCS7
|
|
39
44
|
certificate = x509_certificate(certificate)
|
40
45
|
public_certificate = x509_certificate(public_certificate)
|
41
46
|
signed_data = OpenSSL::PKCS7.sign(certificate, key, data)
|
42
|
-
|
43
|
-
encrypted_data = OpenSSL::PKCS7.encrypt(
|
44
|
-
[public_certificate],
|
45
|
-
signed_data.to_pem,
|
46
|
-
OpenSSL::Cipher.new("aes-256-cbc")
|
47
|
-
)
|
47
|
+
encrypted_data = encrypt(public_certificate, signed_data)
|
48
48
|
|
49
49
|
encrypted_data.to_pem
|
50
50
|
end
|
@@ -72,11 +72,85 @@ module PKCS7
|
|
72
72
|
public_certificate = x509_certificate(public_certificate)
|
73
73
|
encrypted_data = pkcs7(data)
|
74
74
|
decrypted_data = encrypted_data.decrypt(key, certificate)
|
75
|
+
|
75
76
|
signed_data = OpenSSL::PKCS7.new(decrypted_data)
|
77
|
+
verified = verified_signature?(signed_data, public_certificate, ca_store)
|
76
78
|
|
77
|
-
return false unless
|
79
|
+
return false unless verified
|
78
80
|
|
79
81
|
signed_data.data
|
80
82
|
end
|
83
|
+
|
84
|
+
def sign_certificate(
|
85
|
+
csr:,
|
86
|
+
key:,
|
87
|
+
certificate:,
|
88
|
+
valid_until: Time.current + 10.years
|
89
|
+
)
|
90
|
+
valid_until.to_time.utc
|
91
|
+
check_csr(csr)
|
92
|
+
|
93
|
+
sign_csr(csr, key, certificate, valid_until)
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
def encrypt(
|
99
|
+
public_certificate,
|
100
|
+
signed_data,
|
101
|
+
cypher_algorithm = CYPHER_ALGORITHM
|
102
|
+
)
|
103
|
+
OpenSSL::PKCS7.encrypt(
|
104
|
+
[public_certificate],
|
105
|
+
signed_data.to_der,
|
106
|
+
OpenSSL::Cipher.new(cypher_algorithm),
|
107
|
+
OpenSSL::PKCS7::BINARY
|
108
|
+
)
|
109
|
+
end
|
110
|
+
|
111
|
+
def verified_signature?(signed_data, public_certificate, ca_store)
|
112
|
+
signed_data.verify(
|
113
|
+
[public_certificate],
|
114
|
+
ca_store,
|
115
|
+
nil,
|
116
|
+
OpenSSL::PKCS7::NOINTERN | OpenSSL::PKCS7::NOCHAIN
|
117
|
+
)
|
118
|
+
end
|
119
|
+
|
120
|
+
def check_csr(signing_request)
|
121
|
+
csr = OpenSSL::X509::Request.new signing_request
|
122
|
+
raise "CSR can not be verified" unless csr.verify(csr.public_key)
|
123
|
+
end
|
124
|
+
|
125
|
+
def sign_csr(request, key, issuer_certificate, valid_until)
|
126
|
+
request = certificate_signing_request(request)
|
127
|
+
key = rsa_key(key)
|
128
|
+
issuer_certificate = x509_certificate(issuer_certificate)
|
129
|
+
|
130
|
+
csr_cert = build_certificate_from_csr(
|
131
|
+
request,
|
132
|
+
issuer_certificate,
|
133
|
+
valid_until
|
134
|
+
)
|
135
|
+
csr_cert.sign(key, OpenSSL::Digest.new("SHA1")) # TODO: review this one
|
136
|
+
x509_certificate(csr_cert.to_pem)
|
137
|
+
end
|
138
|
+
|
139
|
+
def build_certificate_from_csr(
|
140
|
+
signing_request,
|
141
|
+
issuer_certificate,
|
142
|
+
valid_until
|
143
|
+
)
|
144
|
+
certificate = OpenSSL::X509::Certificate.new
|
145
|
+
certificate.serial = Time.now.to_i
|
146
|
+
certificate.version = 2 # TODO: Check what to put here
|
147
|
+
certificate.not_before = Time.current
|
148
|
+
certificate.not_after = valid_until
|
149
|
+
certificate.subject = signing_request.subject
|
150
|
+
certificate.public_key = signing_request.public_key
|
151
|
+
certificate.issuer = issuer_certificate.subject
|
152
|
+
|
153
|
+
certificate
|
154
|
+
end
|
81
155
|
end
|
82
156
|
end
|
data/pkcs7-cryptographer.gemspec
CHANGED
@@ -13,7 +13,7 @@ Gem::Specification.new do |spec|
|
|
13
13
|
"Utility to encrypt and decrypt messages using OpenSSL::PKCS7"
|
14
14
|
spec.homepage = "https://github.com/dmuneras/pkcs7-cryptographer"
|
15
15
|
spec.license = "MIT"
|
16
|
-
spec.required_ruby_version = Gem::Requirement.new(">= 2.
|
16
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
|
17
17
|
|
18
18
|
spec.metadata["homepage_uri"] = spec.homepage
|
19
19
|
spec.metadata["source_code_uri"] = "https://github.com/dmuneras/pkcs7-cryptographer"
|
@@ -27,6 +27,8 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
28
28
|
spec.require_paths = ["lib"]
|
29
29
|
|
30
|
+
spec.add_dependency "activesupport", ">= 6.1.4.1"
|
31
|
+
|
30
32
|
spec.add_development_dependency "bundler", ">= 2"
|
31
33
|
spec.add_development_dependency "pry"
|
32
34
|
spec.add_development_dependency "rake", "~> 13.0"
|
@@ -34,4 +36,5 @@ Gem::Specification.new do |spec|
|
|
34
36
|
spec.add_development_dependency "rubocop", "1.12.0"
|
35
37
|
spec.add_development_dependency "rubocop-rake", "0.5.1"
|
36
38
|
spec.add_development_dependency "rubocop-rspec", "2.2.0"
|
39
|
+
spec.add_development_dependency "timecop", "0.9.4"
|
37
40
|
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pkcs7-cryptographer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Daniel Munera Sanchez
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-09-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 6.1.4.1
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 6.1.4.1
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: bundler
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,6 +122,20 @@ dependencies:
|
|
108
122
|
- - '='
|
109
123
|
- !ruby/object:Gem::Version
|
110
124
|
version: 2.2.0
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: timecop
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - '='
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 0.9.4
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - '='
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: 0.9.4
|
111
139
|
description: Utility to encrypt and decrypt messages using OpenSSL::PKCS7
|
112
140
|
email:
|
113
141
|
- dmunera119@gmail.com
|
@@ -146,7 +174,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
146
174
|
requirements:
|
147
175
|
- - ">="
|
148
176
|
- !ruby/object:Gem::Version
|
149
|
-
version: 2.
|
177
|
+
version: 2.5.0
|
150
178
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
151
179
|
requirements:
|
152
180
|
- - ">="
|