Home

Awesome

sodium.cr

Crystal CI GitHub release GitHub commits since latest release (by date) for a branch Docs

Crystal bindings for the libsodium API

Goals

Features

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

Several features in libsodium are already provided by Crystal:

What should I use for my application?

Class
Only use CryptoBox::SecretKey Sign::SecretKey Aead::XChaCha20Poly1305Ietf SecretBoxI don't know much about crypto.
Sodium::CryptoBox::SecretKey .boxI want to encrypt + authenticate data using public key encryption.
Sodium::CryptoBox::SecretKey .encryptI want anonymously send encrypted data. (No signatures)
Sodium::Sign::SecretKeyI want to sign or verify messages. (No encryption)
Sodium::Cipher::Aead::XChaCha20Poly1305Ietf (new applications) Sodium::SecretBox (compatibility with older applications)I have a shared key and want to encrypt + authenticate data.
Sodium::Cipher::Aead::XChaCha20Poly1305IetfI have a shared key and want to encrypt + authenticate data and authenticate additional plaintext data.
Sodium::Cipher::SecretStreamI have a shared key and want encrypt + authenticate streamed data.
Sodium::Digest::Blake2bI want to hash data fast and securely.
Sodium::Digest::SipHashI want to hash data really fast and less securely. (Not implemented yet)
Sodium::Password::HashI want to hash a password and store it.
Sodium::Password::KeyI want to derive a key from a password.
Sodium::KdfI have a high quality master key and want to make subkeys.
Sodium::Cipher::ChalsaWhat goes with guacamole?
Everything elseI want to design my own crypto protocol and probably do it wrong.

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:
  sodium:
    github: didactic-drunk/sodium.cr

Usage

See examples for help on using these classes in a complete application.

The specs provide the best examples of how to use or misuse individual classes.


### CryptoBox authenticated easy encryption
```crystal
require "sodium"

data = "Hello World!"

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

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

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

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

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

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

Unauthenticated public key encryption

data = "Hello World!"

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

# Encrypt a message for Bob using his public key
encrypted = bob.public_key.encrypt data

# Decrypt the message using Bob's secret key
decrypted = bob.decrypt encrypted
String.new(decrypted) # => "Hello World!"

Public key signing

message = "Hello World!"

secret_key = Sodium::Sign::SecretKey.new

# Sign the message
signature = secret_key.sign_detached message

# Send secret_key.public_key to the recipient

# On the recipient
public_key = Sodium::Sign::PublicKey.new key_bytes

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

Secret Key Encryption

box = Sodium::SecretBox.new

message = "foobar"
encrypted, nonce = box.encrypt message

# On the other side.
box = Sodium::SecretKey.new key
message = box.decrypt encrypted, nonce: nonce

Blake2b

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

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

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

Key derivation

kdf = Sodium::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 based keys

pwcreate = Sodium::Password::Key::Create.new

# Take approximately 1 second to derive a key.
pwcreate.tcost = 1.0

pass = "1234"
key, params = pwcreate.create_key pass
# Store `params` or `params.to_h` for later.

# Derive the same key from the stored params.
pwkey = Sodium::Password::Key.from_params params.to_h
key = pekey.derive_key pass

Password Hashing

pwhash = Sodium::Password::Hash.new

pwhash.mem = Sodium::Password::MEMLIMIT_MIN
pwhash.ops = Sodium::Password::OPSLIMIT_MIN

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

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

Example output: Ops limit →

1416642561024409616384655362621441048576
8K0.542s2.114s
32K0.513s2.069s
128K0.530s2.121s
512K0.566s2.237s
2048K0.567s2.290s
8192K0.670s2.542s
32768K0.684s2.777s
131072K0.805s3.106s
524288K0.504s1.135s3.661s
2097152K2.119s
Memory

Contributing

  1. Fork it ( https://github.com/didactic-drunk/sodium.cr/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

Project History

Contributors