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 to encrypt + authenticate data and authenticate additional plaintext 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: 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.
### 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
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
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
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
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
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
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
examples/pwhash_selector.cr to help choose ops/mem limits.
Example output: Ops limit →