Skip to content

Instantly share code, notes, and snippets.

@jdickey
Created December 28, 2016 16:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jdickey/c4a4cadee0039bac4d68577f28edef07 to your computer and use it in GitHub Desktop.
Save jdickey/c4a4cadee0039bac4d68577f28edef07 to your computer and use it in GitHub Desktop.
Benchmarking RbNaCl signature and encryption/decryption vs GPGME

It's not really fair to compare the speed of Ruby binding to the Networking and Cryptography (NaCl) library with that of the Ruby interface to GnuPG Made Easy (GPGME); their execution profiles and environments are so radically different. RbNaCl is a unified library, whereas GPGME is an interface to a set of libraries that interact with at least one server process (GPG-AGENT). Benchmark timings bear this out; whereas generating signatures or encrypting/decrypting data with RbNaCl benchmarks thousands of iterations per second on our development system, GPGME clocks in at a half-dozen IPS for any operation other than verifying a signature (which is relatively speedy at ~50 iterations/second).

One needs to keep in mind that the signing keys and encrypted data for RbNaCl exist natively in binary form only, requiring conversion using Base64 or equivalent for transport as text; GPGME, being based on the GNU Privacy Guard collection of software, can represent and use essentially anything as text when instructed to do so.

If "all you're doing" is trying to enhance the security of data over-the-wire in an imperfectly-trusted environment, then you'll almost certainly find RbNaCl compelling. If you need to use persistent, personally-identifiable signatures, or sign/encrypt data using multiple signatures (think collaborating authors) or have multiple individuals be able to decrypt encrypted/signed data, then GPG has long been the go-to tool, and ruby-gpgme is your tool of choice in Ruby.

# frozen_string_literal: true
require 'benchmark/ips'
require 'base64'
require 'gpgme'
require 'ice_nine'
require 'json'
require 'rbnacl'
GPG_USERNAME = ENV['GPG_USERNAME'] || 'jdickey@seven-sigma.com'
SERVICE_INFO = IceNine.deep_freeze({
name: 'apidemo',
description: 'API Demonstration Component Service',
api_version: 'v1',
base_url: 'http://demo.example.com:9292/api/',
restricted: false
})
SERVICE_JSON = JSON.dump(SERVICE_INFO).freeze
sig_key = RbNaCl::SigningKey.generate
sig = sig_key.sign(SERVICE_JSON)
vfy_key = sig_key.verify_key
Benchmark.ips do |x|
x.report 'RbNaCl digital signature -- generate keys and signature' do
signing_key = RbNaCl::SigningKey.generate
signature = signing_key.sign(SERVICE_JSON)
verify_key = signing_key.verify_key
end
x.report 'RbNaCl digital signature -- verify signature' do
verify_key = RbNaCl::VerifyKey.new(vfy_key)
verify_key.verify(sig, SERVICE_JSON)
end
x.report 'RbNaCl encryption -- generate keys and data' do
registration_private_key = RbNaCl::PrivateKey.generate
registration_public_key = registration_private_key.public_key
service_private_key = RbNaCl::PrivateKey.generate
service_public_key = service_private_key.public_key
box = RbNaCl::SimpleBox.from_keypair(registration_public_key,
service_private_key)
crypted = box.encrypt(SERVICE_JSON)
ciphertext = Base64.urlsafe_encode64(crypted)
payload = { service: 'apidemo', pubkey: service_public_key,
data: ciphertext }
end
reg_privkey = RbNaCl::PrivateKey.generate
reg_pubkey = reg_privkey.public_key
service_privkey = RbNaCl::PrivateKey.generate
service_pubkey = service_privkey.public_key
outer_box = RbNaCl::SimpleBox.from_keypair(reg_pubkey, service_privkey)
outer_crypted = outer_box.encrypt(SERVICE_JSON)
outer_ciphertext = Base64.urlsafe_encode64(outer_crypted)
outer_payload = { service: 'apidemo', pubkey: service_pubkey,
data: outer_ciphertext }
x.report 'RbNaCl encryption -- decrypt encrypted data' do
box = RbNaCl::SimpleBox.from_keypair(service_pubkey, reg_privkey)
data = Base64.urlsafe_decode64(outer_payload[:data])
cleartext = box.decrypt(data)
parsed_data = JSON.parse(cleartext, symbolize_names: true)
end
x.report 'GPGME digital signature -- generate signature' do
crypto = GPGME::Crypto.new armor: true
signature = crypto.clearsign SERVICE_JSON
end
gpg_crypto = GPGME::Crypto.new armor: true
gpg_signature = gpg_crypto.clearsign SERVICE_JSON
x.report 'GPGME digital signature -- verify signature' do
gpg_signature.seek(0)
gpg_crypto.verify(gpg_signature) do |sigg|
sigg.valid?
end
end
gpg_crypt_opts = IceNine.deep_freeze({ recipients: GPG_USERNAME,
symmetric: false, sign: true,
always_trust: true })
x.report 'GPGME encryption -- encrypt data' do
# gpg_crypto = GPGME::Crypto.new armor: true
crypted = gpg_crypto.encrypt SERVICE_JSON, gpg_crypt_opts
ciphertext = Base64.urlsafe_encode64(crypted.to_s)
end
gpg_crypted = gpg_crypto.encrypt SERVICE_JSON, gpg_crypt_opts
gpg_crypttext = Base64.urlsafe_encode64(gpg_crypted.to_s)
x.report 'GPGME encryption -- decrypt data' do
ciphertext = Base64.urlsafe_decode64(gpg_crypttext)
cleartext = gpg_crypto.decrypt(ciphertext)
end
end
Warming up --------------------------------------
RbNaCl digital signature -- generate keys and signature
759.000 i/100ms
RbNaCl digital signature -- verify signature
542.000 i/100ms
RbNaCl encryption -- generate keys and data
341.000 i/100ms
RbNaCl encryption -- decrypt encrypted data
1.248k i/100ms
GPGME digital signature -- generate signature
1.000 i/100ms
GPGME digital signature -- verify signature
5.000 i/100ms
GPGME encryption -- encrypt data
1.000 i/100ms
GPGME encryption -- decrypt data
1.000 i/100ms
Calculating -------------------------------------
RbNaCl digital signature -- generate keys and signature
7.715k (± 3.9%) i/s - 38.709k in 5.025783s
RbNaCl digital signature -- verify signature
5.481k (± 3.6%) i/s - 27.642k in 5.050461s
RbNaCl encryption -- generate keys and data
3.460k (± 4.9%) i/s - 17.391k in 5.039210s
RbNaCl encryption -- decrypt encrypted data
12.935k (± 4.1%) i/s - 64.896k in 5.026134s
GPGME digital signature -- generate signature
7.239 (± 0.0%) i/s - 37.000 in 5.117677s
GPGME digital signature -- verify signature
53.012 (± 3.8%) i/s - 265.000 in 5.007300s
GPGME encryption -- encrypt data
6.243 (± 0.0%) i/s - 32.000 in 5.130376s
GPGME encryption -- decrypt data
6.550 (± 0.0%) i/s - 33.000 in 5.043187s
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment