pkcs7-cryptographer 0.1.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c3b2d20fdc0a9804d2e748fbb952795720231ac668903f8e7bc3843194147c5f
4
- data.tar.gz: 8fe66251f456e340ef033201d4e865920780c89d5c46fc16af49095eb9a373b9
3
+ metadata.gz: a02040b2706a005f695860704e338946e5cb68c6dcbf92fc7a2bb9c17b9425b2
4
+ data.tar.gz: 52a840fb9394002e9400e31a0d4960b0fefcfcab4466ce2535c3afcd2915932a
5
5
  SHA512:
6
- metadata.gz: e7285b506e68a68533b7623d83d54a8ab2335505c10fe161784ea6040207fe935890f02e44745b49568605d8fb81653a5ab2b6db1dea59374f666b0103e0076c
7
- data.tar.gz: 89710d821aa0f16cc5e695d2506718738b5c8c05f3a7bbfb76eb7ef333cbe4abf604016616ca09487150fb8827aad1c0cf0670c4164f659666576b2dd73402a1
6
+ metadata.gz: 83d51e4785b3eff57409208a09956c29826e2dde08c75a7b87e340f70b129f2f80614b4c5792e159618354ae97059eff2febd58a01ce08c460758fba0feb9e52
7
+ data.tar.gz: 139e5b0e31cdfeed9c67468f92a21dc2f9f36bc3f207fe941df54194e199f43b2681e79072b5e1ea67f33696dd5422c4bf34595377845ea579cccb22487f85fe
data/.rubocop.yml CHANGED
@@ -1,6 +1,9 @@
1
+ require:
2
+ - rubocop-rake
3
+ - rubocop-rspec
4
+
1
5
  AllCops:
2
6
  NewCops: enable
3
- SuggestExtensions: false
4
7
  Style/StringLiterals:
5
8
  Enabled: true
6
9
  EnforcedStyle: double_quotes
@@ -13,4 +16,13 @@ Layout/LineLength:
13
16
  Max: 80
14
17
 
15
18
  Metrics/BlockLength:
16
- IgnoredMethods: ['describe', 'context']
19
+ IgnoredMethods: ['describe', 'context']
20
+
21
+ RSpec/MultipleMemoizedHelpers:
22
+ Enabled: false
23
+
24
+ RSpec/NestedGroups:
25
+ Max: 6
26
+
27
+ RSpec/ExampleLength:
28
+ Max: 10
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- pkcs7-cryptographer (0.1.0)
4
+ pkcs7-cryptographer (1.0.1)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -33,19 +33,24 @@ GEM
33
33
  diff-lcs (>= 1.2.0, < 2.0)
34
34
  rspec-support (~> 3.10.0)
35
35
  rspec-support (3.10.2)
36
- rubocop (0.93.1)
36
+ rubocop (1.12.0)
37
37
  parallel (~> 1.10)
38
- parser (>= 2.7.1.5)
38
+ parser (>= 3.0.0.0)
39
39
  rainbow (>= 2.2.2, < 4.0)
40
- regexp_parser (>= 1.8)
40
+ regexp_parser (>= 1.8, < 3.0)
41
41
  rexml
42
- rubocop-ast (>= 0.6.0)
42
+ rubocop-ast (>= 1.2.0, < 2.0)
43
43
  ruby-progressbar (~> 1.7)
44
- unicode-display_width (>= 1.4.0, < 2.0)
44
+ unicode-display_width (>= 1.4.0, < 3.0)
45
45
  rubocop-ast (1.4.1)
46
46
  parser (>= 2.7.1.5)
47
+ rubocop-rake (0.5.1)
48
+ rubocop
49
+ rubocop-rspec (2.2.0)
50
+ rubocop (~> 1.0)
51
+ rubocop-ast (>= 1.1.0)
47
52
  ruby-progressbar (1.11.0)
48
- unicode-display_width (1.7.0)
53
+ unicode-display_width (2.0.0)
49
54
 
50
55
  PLATFORMS
51
56
  x86_64-darwin-19
@@ -56,7 +61,9 @@ DEPENDENCIES
56
61
  pry
57
62
  rake (~> 13.0)
58
63
  rspec (~> 3.2)
59
- rubocop (~> 0.80)
64
+ rubocop (= 1.12.0)
65
+ rubocop-rake (= 0.5.1)
66
+ rubocop-rspec (= 2.2.0)
60
67
 
61
68
  BUNDLED WITH
62
69
  2.2.3
data/README.md CHANGED
@@ -1,11 +1,16 @@
1
1
  # PKCS7::Cryptographer
2
2
 
3
- Cryptographer is an small utility that allows to encrypt and decrypt messages
3
+ [![Gem Version](https://badge.fury.io/rb/pkcs7-cryptographer.svg)](https://badge.fury.io/rb/pkcs7-cryptographer)
4
+ ![main workflow](https://github.com/dmuneras/pkcs7-cryptographer/actions/workflows/main.yml/badge.svg)
5
+
6
+
7
+ Cryptographer is an small utility to encrypt, sign and decrypt messages
4
8
  using PKCS7.
5
9
 
6
- PKCS7 is used to store signed and encrypted data.It uses aes-256-cbc
7
- as chipher in the encryption process. If you want to read more information about
8
- the involved data structures and theory around this, please visit:
10
+ PKCS7 is used to store signed and encrypted data.This specific implementation
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,
13
+ please visit:
9
14
 
10
15
  - https://ruby-doc.org/stdlib-3.0.0/libdoc/openssl/rdoc/OpenSSL.html
11
16
  - https://tools.ietf.org/html/rfc5652
@@ -20,30 +25,39 @@ gem 'pkcs7-cryptographer'
20
25
 
21
26
  And then execute:
22
27
 
28
+ ```sh
23
29
  $ bundle install
30
+ ```
24
31
 
25
32
  Or install it yourself as:
26
33
 
34
+ ```sh
27
35
  $ gem install pkcs7-cryptographer
28
-
36
+ ```
29
37
  ## Usage
30
38
 
39
+ ### Using bare PKCS7::Cryptographer
40
+
31
41
  After installing the gem you will have the `PKCS7::Cryptographer` available.
32
42
 
33
- `PKCS7::Cryptographer` is a class that provides to public methods:
43
+ `PKCS7::Cryptographer` is a class that provides two public methods:
34
44
 
35
45
  - `sign_and_encrypt`
36
46
  - `decrypt_and_verify`
37
47
 
38
- Read the following example to get a better undertanding:
48
+ If you want to use the barebones cryptographer, you can. Please look at the
49
+ following example:
50
+
51
+
39
52
 
40
53
  ```ruby
54
+ require 'pkcs7/cryptographer'
41
55
 
42
56
  # This script assumes you have a read_file method to read the certificates and
43
57
  # keys.
44
58
 
45
- # What we are going to do is sign an encrypt a message from the CA Authority
46
- # and read it from the Client:
59
+ # What we are going to do is signing an encrypting a message from the CA
60
+ # Authority and read it from the Client:
47
61
 
48
62
  # Certificate Authority PKI data
49
63
  CA_KEY = read_file("ca.key")
@@ -59,9 +73,11 @@ Read the following example to get a better undertanding:
59
73
  # Only the client can read the message since the required public
60
74
  # certificate to read it is the client certificate.
61
75
 
62
- # 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
63
77
  # CA that signed the client certificate as trusted.
64
78
 
79
+ cryptographer = PKCS7::Cryptographer.new
80
+
65
81
  # Client <------------------------- CA Authority API
66
82
  encrypted_data = cryptographer.sign_and_encrypt(
67
83
  data: "Atletico Nacional de Medellin",
@@ -70,6 +86,8 @@ Read the following example to get a better undertanding:
70
86
  public_certificate: CLIENT_CERTIFICATE
71
87
  )
72
88
 
89
+ # encrypted_data is a PEM formatted string
90
+
73
91
  # READ MESSAGE IN CLIENT
74
92
  # ----------------------------------------------------------------------------
75
93
  # Store of trusted certificates
@@ -87,6 +105,98 @@ Read the following example to get a better undertanding:
87
105
  # decrypted_data returns: "Atletico Nacional de Medellin"
88
106
  ```
89
107
 
108
+ ### Using PKCS7::Cryptographer::Entity
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
+
115
+ ```ruby
116
+
117
+ require 'pkcs7/cryptographer'
118
+ require 'pkcs7/cryptographer/entity'
119
+
120
+ # This script assumes you have a read_file method to read the certificates and
121
+ # keys. If you have any question about how to generate the keys/certificates
122
+ # check this post: https://mariadb.com/kb/en/certificate-creation-with-openssl/
123
+
124
+ # What we are going to do is sending a message from the CA Authority and read
125
+ # it from the Client:
126
+
127
+ # Certificate Authority PKI data
128
+ CA_KEY = read_file("ca.key")
129
+ CA_CERTIFICATE = read_file("ca.crt")
130
+
131
+ # Client PKI data
132
+ CLIENT_CERTIFICATE = read_file("client.crt")
133
+
134
+ CA_STORE = OpenSSL::X509::Store.new
135
+ CA_STORE.add_cert(OpenSSL::X509::Certificate.new(CA_CERTIFICATE))
136
+
137
+ ca_entity = PKCS7::Cryptographer::Entity.new(
138
+ key: CA_KEY,
139
+ certificate: CA_CERTIFICATE,
140
+ ca_store: CA_STORE
141
+ )
142
+
143
+ client_entity = PKCS7::Cryptographer::Entity.new(
144
+ certificate: CLIENT_CERTIFICATE
145
+ )
146
+
147
+ # SEND MESSAGE TO THE CLIENT
148
+ # ----------------------------------------------------------------------------
149
+ data = "Victor Ibarbo"
150
+ encrypted_data = ca_entity.encrypt_data(data: data, receiver: client_entity)
151
+
152
+ # READ MESSAGE IN CLIENT
153
+ # ----------------------------------------------------------------------------
154
+ decrypted_data = client_entity.decrypt_data(
155
+ data: encrypted_data,
156
+ sender: ca_entity
157
+ )
158
+
159
+ # decrypted_data returns: "Victor Ibarbo"
160
+ ```
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
+
90
200
  ## Development
91
201
 
92
202
  After checking out the repo, run `bin/setup` to install dependencies. Then, run
data/bin/console CHANGED
@@ -3,6 +3,7 @@
3
3
 
4
4
  require "bundler/setup"
5
5
  require "pkcs7/cryptographer"
6
+ require "pkcs7/cryptographer/entity"
6
7
 
7
8
  # You can add fixtures and/or initialization code here to make experimenting
8
9
  # with your gem easier. You can also use a different console, if you like.
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "openssl"
4
4
  require_relative "cryptographer/version"
5
+ require_relative "cryptographer/initializers"
5
6
 
6
7
  module PKCS7
7
8
  ###
@@ -14,6 +15,8 @@ module PKCS7
14
15
  # - https://tools.ietf.org/html/rfc5652
15
16
  ###
16
17
  class Cryptographer
18
+ include PKCS7::Cryptographer::Initializers
19
+
17
20
  # PUBLIC METHODS
18
21
  # --------------------------------------------------------------------------
19
22
 
@@ -36,12 +39,7 @@ module PKCS7
36
39
  certificate = x509_certificate(certificate)
37
40
  public_certificate = x509_certificate(public_certificate)
38
41
  signed_data = OpenSSL::PKCS7.sign(certificate, key, data)
39
-
40
- encrypted_data = OpenSSL::PKCS7.encrypt(
41
- [public_certificate],
42
- signed_data.to_pem,
43
- OpenSSL::Cipher.new("aes-256-cbc")
44
- )
42
+ encrypted_data = encrypt(public_certificate, signed_data)
45
43
 
46
44
  encrypted_data.to_pem
47
45
  end
@@ -69,31 +67,33 @@ module PKCS7
69
67
  public_certificate = x509_certificate(public_certificate)
70
68
  encrypted_data = pkcs7(data)
71
69
  decrypted_data = encrypted_data.decrypt(key, certificate)
70
+
72
71
  signed_data = OpenSSL::PKCS7.new(decrypted_data)
72
+ verified = verified_signature?(signed_data, public_certificate, ca_store)
73
73
 
74
- return false unless signed_data.verify([public_certificate], ca_store)
74
+ return false unless verified
75
75
 
76
76
  signed_data.data
77
77
  end
78
78
 
79
- # PRIVATE METHODS
80
- # --------------------------------------------------------------------------
81
79
  private
82
80
 
83
- def x509_certificate(certificate)
84
- wrap_in_class_or_return(certificate, OpenSSL::X509::Certificate)
85
- end
86
-
87
- def rsa_key(key)
88
- wrap_in_class_or_return(key, OpenSSL::PKey::RSA)
89
- end
90
-
91
- def pkcs7(pkcs7)
92
- wrap_in_class_or_return(pkcs7, OpenSSL::PKCS7)
81
+ def encrypt(public_certificate, signed_data)
82
+ OpenSSL::PKCS7.encrypt(
83
+ [public_certificate],
84
+ signed_data.to_der,
85
+ OpenSSL::Cipher.new("aes-256-cbc"),
86
+ OpenSSL::PKCS7::BINARY
87
+ )
93
88
  end
94
89
 
95
- def wrap_in_class_or_return(data, klass)
96
- data.instance_of?(klass) ? data : klass.new(data)
90
+ def verified_signature?(signed_data, public_certificate, ca_store)
91
+ signed_data.verify(
92
+ [public_certificate],
93
+ ca_store,
94
+ nil,
95
+ OpenSSL::PKCS7::NOINTERN | OpenSSL::PKCS7::NOCHAIN
96
+ )
97
97
  end
98
98
  end
99
99
  end
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "initializers"
4
+
5
+ module PKCS7
6
+ class Cryptographer
7
+ ###
8
+ # Define an entity abel to decrypt or encrypt messages to send them to other
9
+ # entities. It uses a Cryptographer to do the dirty work and just provide a
10
+ # more human readable way to read an pass messages between trustable
11
+ # entities.
12
+ ###
13
+ class Entity
14
+ include PKCS7::Cryptographer::Initializers
15
+
16
+ attr_reader :certificate
17
+
18
+ # PUBLIC METHODS
19
+ # ------------------------------------------------------------------------
20
+ def initialize(
21
+ certificate:,
22
+ key: nil,
23
+ ca_store: OpenSSL::X509::Store.new
24
+ )
25
+ @key = key ? rsa_key(key) : nil
26
+ @certificate = x509_certificate(certificate)
27
+ @cryptographer = PKCS7::Cryptographer.new
28
+ @ca_store = ca_store
29
+ end
30
+
31
+ def trustable_entity?(entity)
32
+ @ca_store.verify(entity.certificate)
33
+ end
34
+
35
+ def encrypt_data(data:, receiver:)
36
+ perform_safely(receiver) do
37
+ @cryptographer.sign_and_encrypt(
38
+ data: data,
39
+ key: @key,
40
+ certificate: @certificate,
41
+ public_certificate: receiver.certificate
42
+ )
43
+ end
44
+ end
45
+
46
+ def decrypt_data(data:, sender:)
47
+ perform_safely(sender) do
48
+ @cryptographer.decrypt_and_verify(
49
+ data: data,
50
+ key: @key,
51
+ certificate: @certificate,
52
+ public_certificate: sender.certificate,
53
+ ca_store: @ca_store
54
+ )
55
+ end
56
+ end
57
+
58
+ # PRIVATE METHODS
59
+ # ------------------------------------------------------------------------
60
+ private
61
+
62
+ def perform_safely(entity)
63
+ return false unless trustable_entity?(entity)
64
+ return false unless @key
65
+
66
+ yield
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PKCS7
4
+ class Cryptographer
5
+ ###
6
+ # Provides a set of methods to initialize OpenSSL objects if necessary. It
7
+ # allow consumers to pass either the OpenSSL ruby objects or the
8
+ # certificate, key or encrypted message string.
9
+ ###
10
+ module Initializers
11
+ # PRIVATE METHODS
12
+ # ------------------------------------------------------------------------
13
+
14
+ private
15
+
16
+ def x509_certificate(certificate)
17
+ wrap_in_class_or_return(certificate, OpenSSL::X509::Certificate)
18
+ end
19
+
20
+ def rsa_key(key)
21
+ wrap_in_class_or_return(key, OpenSSL::PKey::RSA)
22
+ end
23
+
24
+ def pkcs7(pkcs7)
25
+ wrap_in_class_or_return(pkcs7, OpenSSL::PKCS7)
26
+ end
27
+
28
+ def wrap_in_class_or_return(data, klass)
29
+ data.instance_of?(klass) ? data : klass.new(data)
30
+ end
31
+ end
32
+ end
33
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module PKCS7
4
4
  class Cryptographer
5
- VERSION = "0.1.0"
5
+ VERSION = "1.0.1"
6
6
  end
7
7
  end
@@ -31,5 +31,7 @@ Gem::Specification.new do |spec|
31
31
  spec.add_development_dependency "pry"
32
32
  spec.add_development_dependency "rake", "~> 13.0"
33
33
  spec.add_development_dependency "rspec", "~> 3.2"
34
- spec.add_development_dependency "rubocop", "~> 0.80"
34
+ spec.add_development_dependency "rubocop", "1.12.0"
35
+ spec.add_development_dependency "rubocop-rake", "0.5.1"
36
+ spec.add_development_dependency "rubocop-rspec", "2.2.0"
35
37
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pkcs7-cryptographer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.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-03-24 00:00:00.000000000 Z
11
+ date: 2021-04-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -70,16 +70,44 @@ dependencies:
70
70
  name: rubocop
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - "~>"
73
+ - - '='
74
74
  - !ruby/object:Gem::Version
75
- version: '0.80'
75
+ version: 1.12.0
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - "~>"
80
+ - - '='
81
+ - !ruby/object:Gem::Version
82
+ version: 1.12.0
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop-rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '='
88
+ - !ruby/object:Gem::Version
89
+ version: 0.5.1
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '='
95
+ - !ruby/object:Gem::Version
96
+ version: 0.5.1
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop-rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '='
102
+ - !ruby/object:Gem::Version
103
+ version: 2.2.0
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '='
81
109
  - !ruby/object:Gem::Version
82
- version: '0.80'
110
+ version: 2.2.0
83
111
  description: Utility to encrypt and decrypt messages using OpenSSL::PKCS7
84
112
  email:
85
113
  - dmunera119@gmail.com
@@ -100,6 +128,8 @@ files:
100
128
  - bin/console
101
129
  - bin/setup
102
130
  - lib/pkcs7/cryptographer.rb
131
+ - lib/pkcs7/cryptographer/entity.rb
132
+ - lib/pkcs7/cryptographer/initializers.rb
103
133
  - lib/pkcs7/cryptographer/version.rb
104
134
  - pkcs7-cryptographer.gemspec
105
135
  homepage: https://github.com/dmuneras/pkcs7-cryptographer