sodium.cr/README.md

8.2 KiB

cox

Build Status Docs

Updated Crystal bindings for the libsodium API

Features

☑ Indicate specs are compared against test vectors from another source.

Several features in libsodium are already provided by Crystal:

Installation

Optionally Install libsodium. A recent version of libsodium is automatically downloaded and compiled if you don't install your own version.

Add this to your application's shard.yml:

dependencies:
  cox:
    github: didactic-drunk/cox

What should I use for my application?

Class
CryptoBox Sign SecretBox I don't know much about crypto.
Cox::CryptoBox::PrivateKey I want to encrypt + authenticate data using public key encryption.
Cox::Sign::PrivateKey I want to sign or verify messages without encryption.
Cox::SecretBox I have a shared key and want to encrypt + authenticate data.
AEAD I have a shared key and want encrypt + authenticate streamed data. (not implemented yet)
Cox::Blake2b I want to hash data fast and securely.
Cox::SipHash I want to hash data really fast and less securely. (not implemented yet)
Cox::Pwhash I want to hash a password and store it.
Cox::Pwhash I want to derive a key from a password.
Cox::Kdf I have a high quality master key and want to make subkeys.
Cox::Cipher::Chalsa What goes with guacamole?
Everything else I want to design my own crypto protocol and probably do it wrong.

Usage

The specs provide the best examples of how to use or misuse this shard.

CryptoBox easy encryption

require "cox"

data = "Hello World!"

# Alice is the sender
alice = Cox::CryptoBox::SecretKey.new

# Bob is the recipient
bob = Cox::CryptoBox::SecretKey.new

# Precompute a shared secret between alice and bob.
pair = alice.pair bob.public_key

# Encrypt a message for Bob using his public key, signing it with Alice's
# secret key
nonce, encrypted = pair.encrypt data

# Precompute within a block.  The shared secret is wiped when the block exits.
bob.pair alice.public_key do |pair|
  # Decrypt the message using Bob's secret key, and verify its signature against
  # Alice's public key
  decrypted = Cox.decrypt(encrypted, nonce, alice.public, bob.secret)

  String.new(decrypted) # => "Hello World!"
end

Public key signing

message = "Hello World!"

secret_key = Cox::Sign::SecretKey.new

# Sign the message
signature = secret_key.sign_detached message

# Send secret_key.public_key to the recipient

public_key = Cox::Sign::PublicKey.new key_bytes

# raises Cox::Error::VerificationFailed on failure.
public_key.verify_detached message, signature

Secret Key Encryption

key = Cox::SecretKey.new

message = "foobar"
encrypted, nonce = key.encrypt_easy message

# On the other side.
key = Cox::SecretKey.new key
message = key.decrypt_easy encrypted, nonce

Blake2b

key = Bytes.new Cox::Blake2B::KEY_SIZE
salt = Bytes.new Cox::Blake2B::SALT_SIZE
personal = Bytes.new Cox::Blake2B::PERSONAL_SIZE
out_size = 64 # bytes between Cox::Blake2B::OUT_SIZE_MIN and Cox::Blake2B::OUT_SIZE_MAX
data = "data".to_slice

# output_size, key, salt, and personal are optional.
digest = Cox::Blake2b.new out_size, key: key, salt: salt, personal: personal
digest.update data
output = d.hexdigest

digest.reset # Reuse existing object to hash again.
digest.update data
output = d.hexdigest

Key derivation

kdf = Cox::Kdf.new

# kdf.derive(8_byte_context, subkey_id, subkey_size)
subkey1 = kdf.derive "context1", 0, 16
subkey2 = kdf.derive "context1", 1, 16
subkey3 = kdf.derive "context2", 0, 32
subkey4 = kdf.derive "context2", 1, 64

Password Hashing

pwhash = Cox::Pwhash.new

pwhash.memlimit = Cox::Pwhash::MEMLIMIT_MIN
pwhash.opslimit = Cox::Pwhash::OPSLIMIT_MIN

pass = "1234"
hash = pwhash.hash_str pass
pwhash.verify hash, pass

Use examples/pwhash_selector.cr to help choose ops/mem limits.

Example output: Ops limit →

1 4 16 64 256 1024 4096 16384 65536 262144 1048576
8K 0.542s 2.114s
32K 0.513s 2.069s
128K 0.530s 2.121s
512K 0.566s 2.237s
2048K 0.567s 2.290s
8192K 0.670s 2.542s
32768K 0.684s 2.777s
131072K 0.805s 3.106s
524288K 0.504s 1.135s 3.661s
2097152K 2.119s
Memory

Contributing

  1. Fork it ( https://github.com/didactic-drunk/cox/fork )
  2. Install a formatting check git hook (ln -sf ../../scripts/git/pre-commit .git/hooks)
  3. Create your feature branch (git checkout -b my-new-feature)
  4. Commit your changes (git commit -am 'Add some feature')
  5. Push to the branch (git push origin my-new-feature)
  6. Create a new Pull Request

Contributors