No commit activity in last 3 years
No release in over 3 years
Utility to encrypt and decrypt messages using OpenSSL::PKCS7
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

>= 0
~> 13.0
~> 3.2
= 1.12.0
= 0.9.4

Runtime

>= 6.1.4.1
 Project Readme

PKCS7 Cryptographer

Gem Version main workflow

Cryptographer is an small utility to encrypt, sign and decrypt messages using PKCS7.

PKCS7 is used to store signed and encrypted data.This specific implementation uses aes-256-cbc as cipher in the encryption process. If you want to read more information about the involved data structures and theory around this, please visit:

Installation

Add this line to your application's Gemfile:

gem 'pkcs7-cryptographer'

And then execute:

  $ bundle install

Or install it yourself as:

  $ gem install pkcs7-cryptographer

Usage

Using bare PKCS7::Cryptographer

After installing the gem you will have the PKCS7::Cryptographer available.

PKCS7::Cryptographer is a class that provides a few public methods:

  • sign
  • sign_and_encrypt
  • decrypt_and_verify

If you want to use the barebones cryptographer, you can. Please look at the following example:

  require 'pkcs7/cryptographer'

  # This script assumes you have a read_file method to read the certificates and
  # keys.

  # What we are going to do is signing an encrypting a message from the CA
  # Authority and read it from the Client:

  # Certificate Authority PKI data
  CA_KEY = read_file("ca.key")
  CA_CERTIFICATE = read_file("ca.crt")

  # Client PKI data
  CLIENT_CERTIFICATE = read_file("client.crt")
  CLIENT_KEY = read_file("client.key")

  cryptographer = PKCS7::Cryptographer.new

  # SIGN MESSAGE FOR THE CLIENT
  # ----------------------------------------------------------------------------
  # Sign a message in the CA Authority API to be sent to the Client.

  # It could be read if the CA_STORE of the reader has the certificate of the
  # CA that signed the client certificate as trusted.

  # You can provide optional arguments:
  #
  # * `:certs` like this:
  #   ```
  #   certs: [OpenSSL::X509::Certificate.new(some_sert_content)]
  #   ```
  #
  # * `:flags` like this:
  #   ```
  #   flags: OpenSSL::PKCS7::BINARY | OpenSSL::PKCS7::NOCHAIN
  #   ```

  # Client <------------------------- CA Authority API
  signed_data = cryptographer.sign(
    data: "Atletico Nacional de Medellin",
    key: CA_KEY,
    certificate: CA_CERTIFICATE
  )

  # signed_data is a PEM formatted string

  # SIGN AND ENCRYPT MESSAGE FOR THE CLIENT
  # ----------------------------------------------------------------------------
  # Sign and encrypt a message in the CA Authority API to be sent to the Client.
  # Only the client can read the message since the required public
  # certificate to read it is the client certificate.

  # It could be read if the CA_STORE of the reader has the certificate of the
  # CA that signed the client certificate as trusted.

  # You also can provide optional argument `:certs` and `:flags`
  # as described above.

  # Client <------------------------- CA Authority API
  encrypted_data = cryptographer.sign_and_encrypt(
    data: "Atletico Nacional de Medellin",
    key: CA_KEY,
    certificate: CA_CERTIFICATE,
    public_certificate: CLIENT_CERTIFICATE
  )

  # encrypted_data is a PEM formatted string

  # DECRYPT AND VERIFY MESSAGE IN THE CLIENT
  # ----------------------------------------------------------------------------
  # Store of trusted certificates
  CA_STORE = OpenSSL::X509::Store.new
  CA_STORE.add_cert(OpenSSL::X509::Certificate.new(CA_CERTIFICATE))

  decrypted_data = cryptographer.decrypt_and_verify(
    data: encrypted_data,
    key: CLIENT_KEY,
    certificate: CLIENT_CERTIFICATE,
    public_certificate: CA_CERTIFICATE,
    ca_store: CA_STORE
  )

  # decrypted_data returns: "Atletico Nacional de Medellin"

Using PKCS7::Cryptographer::Entity

There is a possibility to use entities to communicate using encrypted data. In order to use it you have to import the entities implementation.

Please look at the following example:

  require 'pkcs7/cryptographer'
  require 'pkcs7/cryptographer/entity'

  # This script assumes you have a read_file method to read the certificates and
  # keys. If you have any question about how to generate the keys/certificates
  # check this post: https://mariadb.com/kb/en/certificate-creation-with-openssl/

  # What we are going to do is sending a message from the CA Authority and read
  # it from the Client:

  # Certificate Authority PKI data
  CA_KEY = read_file("ca.key")
  CA_CERTIFICATE = read_file("ca.crt")

  # Client PKI data
  CLIENT_CERTIFICATE = read_file("client.crt")

  CA_STORE = OpenSSL::X509::Store.new
  CA_STORE.add_cert(OpenSSL::X509::Certificate.new(CA_CERTIFICATE))

  ca_entity = PKCS7::Cryptographer::Entity.new(
    key: CA_KEY,
    certificate: CA_CERTIFICATE,
    ca_store: CA_STORE
  )

  client_entity = PKCS7::Cryptographer::Entity.new(
    certificate: CLIENT_CERTIFICATE
  )

  # SEND MESSAGE TO THE CLIENT
  # ----------------------------------------------------------------------------
  data = "Victor Ibarbo"
  encrypted_data = ca_entity.encrypt_data(data: data, receiver: client_entity)

  # READ MESSAGE IN CLIENT
  # ----------------------------------------------------------------------------
  decrypted_data = client_entity.decrypt_data(
    data: encrypted_data,
    sender: ca_entity
  )

  # decrypted_data returns: "Victor Ibarbo"

When using entities, all the complexity of knowing which PKI credentials to send to the cryptographer disappears. You only need to initialize the entities and use the methods to indicate to whom the message will be sent.

If you want to verify if certain entity you defined "trust" another one, use the trustable_entity?(<the other entity>).

  ca_entity = PKCS7::Cryptographer::Entity.new(
    key: CA_KEY,
    certificate: CA_CERTIFICATE,
    ca_store: CA_STORE
  )

  client_entity = PKCS7::Cryptographer::Entity.new(
    certificate: CLIENT_CERTIFICATE
  )

  ca_entity.trustable_entity?(client_entity)

  # Returns true because the client certificate was signed by the root
  # certificate of the ca_authority.

When sending data to an entity, you will most of the time initialize the entity only with the certificate keyword arguments. So, initializing a receiver will most of the time looks like this:

  client_entity = PKCS7::Cryptographer::Entity.new(
    certificate: CLIENT_CERTIFICATE
  )

The entity above can't encrypt messages or decrypt them, if you want to decrypt and encrypt the entity should have its the key (private key), certificate and the list of trusted certificates of the entity (ca_store).

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and the created tag, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/dmuneras/pkcs7-cryptographer. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.

License

The gem is available as open source under the terms of the MIT License.

Code of Conduct

Everyone interacting in the PKCS7::Cryptographer project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.