Add the following code to your project's shard.yml under:
to use in production
- OR -
development_dependencies to use in development
Crystal bindings for the libsodium API
☑ Indicate specs are compared against test vectors from another source.
Several features in libsodium are already provided by Crystal:
||I don't know much about crypto.|
||I want to encrypt + authenticate data using public key encryption.|
||I want anonymously send encrypted data. (No signatures)|
||I want to sign or verify messages. (No encryption)|
||I have a shared key and want to encrypt + authenticate data.|
||I have a shared key and want encrypt + authenticate streamed data.|
||I want to hash data fast and securely.|
||I want to hash data really fast and less securely. (Not implemented yet)|
||I want to hash a password and store it.|
||I want to derive a key from a password.|
||I have a high quality master key and want to make subkeys.|
||What goes with guacamole?|
|Everything else||I want to design my own crypto protocol and probably do it wrong.|
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
dependencies: sodium.cr: github: didactic-drunk/sodium.cr
examples for help on using these classes in a complete application.
specs provide the best examples of how to use or misuse individual classes.
You may call
.close on any object that retains keying material to wipe it's key(s) earlier.
Objects with a
.close method also respond to
Class.open and wipe when the block returns.
# TODO Sodium::CryptoBox::SecretKey.open(sec_key, pub_key) do |secret_key| ... Do crypto operations ... end # sec_key is wiped # public keys aren't wiped.
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 nonce, encrypted = 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 = Sodium.decrypt(encrypted, nonce, alice.public, bob.secret) String.new(decrypted) # => "Hello World!" end
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!"
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
key = Sodium::SecretKey.new message = "foobar" encrypted, nonce = key.encrypt message # On the other side. key = Sodium::SecretKey.new key message = key.decrypt encrypted, nonce
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.hexdigest digest.reset # Reuse existing object to hash again. digest.update data output = d.hexdigest
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
pwhash = Sodium::Pwhash.new pwhash.memlimit = Sodium::Pwhash::MEMLIMIT_MIN pwhash.opslimit = Sodium::Pwhash::OPSLIMIT_MIN pass = "1234" hash = pwhash.hash_str pass pwhash.verify hash, pass
examples/pwhash_selector.cr to help choose ops/mem limits.
Example output: Ops limit →