5.9 KiB
5.9 KiB
cox
Updated Crystal bindings for the libsodium API
Features
- Public-Key Cryptography
- Crypto Box Easy
- Sealed Box
- Combined Signatures
- Detached Signatures
- Secret-Key Cryptography
- Secret Box
- Combined mode
- Detached mode
- Streaming
- XChaCha20 Poly1305
- AEAD
- AES256-GCM (Requires hardware acceleration)
- XChaCha20-Poly1305-IETF
- ChaCha20-Poly1305-IETF
- ChaCha20-Poly1305
- Secret Box
- Hashing
- Password Hashing
- Argon2 (Use for new applications)
- Scrypt (For compatibility with older applications)
- Other
- Advanced
- Stream Ciphers
- XSalsa20
- Salsa20
- XChaCha20
- ChaCha20 Ietf
- ChaCha20
- One time auth
- Padding
- Stream Ciphers
☑ Indicate specs are compared against test vectors from another source.
Several features in libsodium are already provided by Crystal:
- Random (Use Random::Secure)
- SHA-2 (Use OpenSSL::Digest)
- HMAC SHA-2 (Use OpenSSL::HMAC)
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
Usage
require "cox"
data = "Hello World!"
# Alice is the sender
alice = Cox::KeyPair.new
# Bob is the recipient
bob = Cox::KeyPair.new
# Encrypt a message for Bob using his public key, signing it with Alice's
# secret key
nonce, encrypted = Cox.encrypt(data, bob.public, alice.secret)
# 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!"
Public key signing
message = "Hello World!"
signing_pair = Cox::SignKeyPair.new
# Sign the message
signature = Cox.sign_detached(message, signing_pair.secret)
# And verify
Cox.verify_detached(signature, message, signing_pair.public) # => true
Secret Key Encryption
key = Cox::SecretKey.random
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
- Fork it ( https://github.com/didactic-drunk/cox/fork )
- Create your feature branch (git checkout -b my-new-feature)
- Commit your changes (git commit -am 'Add some feature')
- Push to the branch (git push origin my-new-feature)
- Create a new Pull Request
Contributors
- andrewhamon Andrew Hamon - creator, former maintainer
- dorkrawk Dave Schwantes - contributor
- didactic-drunk - current maintainer