ruby-botan is a Ruby interface to Botan.
Note: Refer to the Botan documentation in addition to the documentation here. In particular, this note from the Botan manual applies here as well:
You should have some knowledge of cryptography before trying to use the library. This is an area where it is very easy to make mistakes, and where things are often subtle and/or counterintuitive. Obviously the library tries to provide things at a high level precisely to minimize the number of ways things can go wrong, but naive use will almost certainly not result in a secure system.
ruby-botan is currently tested to work with:
- Ruby 2.5
- Ruby 2.4
Botan version 2.2 or newer is required.
The samples below are meant to be a brief introduction to the library. Refer to the full documentation for full details.
Also see the examples directory for examples on using various parts of the library.
Botan.hex_encode("\x01\x02\x03\x04")
Botan.hex_decode('01020304')
# shortcut method that uses default RNG to get 10 bytes
Botan::RNG.get(10)
# create a different type of RNG, and reseed from the system RNG
rng = Botan::RNG.new('user')
rng.reseed
rng.get(5)
There are a few different ways to utilize Digest. Which method you choose may depend on whether the data is immediately available in full, or whether it is becoming available over time.
If you simply want to hash some data that you have immediately available in full, you may want to do something like the following.
Botan::Digest::MD5.digest('my data')
Botan::Digest::SHA256.hexdigest('my data')
You may also use a longer form, in case there is not a pre-defined class (like MD5
and SHA256
above). For example:
Botan::Digest.digest('Comb4P(SHA-160,RIPEMD-160)', 'my data')
Botan::Digest.hexdigest('SHA-3(224)', 'my data')
If you have a stream of incoming data that is not readily available that you want to hash, you may proceed in a couple of ways:
# MD5
md5 = Botan::Digest::MD5.new
md5.update('my ')
md5 << 'data'
md5.hexdigest
# Comb4P hash combiner
hash = Botan::Digest.new('Comb4P(SHA-160,RIPEMD-160)')
hash << 'my '
hash << 'data'
hash.hexdigest
# encrypt
enc = Botan::Cipher.encryption('AES-128/CBC/PKCS7')
key = Botan::RNG.get(enc.key_length_max)
iv = Botan::RNG.get(enc.default_nonce_length)
enc.key = key
enc.iv = iv
ciphertext = enc.finish('my data')
# decrypt
dec = Botan::Cipher.decryption('AES-128/CBC/PKCS7')
dec.key = key
dec.iv = iv
plaintext = dec.finish(ciphertext)
The Botan::BCrypt
module supports simple bcrypt password hashing.
# generate password hash
password_input = gets.chomp
password_hash = Botan::BCrypt.hash(password_input, work_factor: 10)
# check password
password_input = gets.chomp
Botan::BCrypt.valid?(password: password_input, phash: password_hash)
The Botan::KDF
module has a few different functions for key derivation.
Botan::KDF.kdf(algo: 'KDF2(SHA-160)', secret: Botan::RNG.get(9), salt: Botan::RNG.get(7), key_length: 32)
Botan::KDF.pbkdf(algo: 'PBKDF2(CMAC(Blowfish))', password: 'some long passphrase', iterations: 150_000, key_length: 16)
Botan::KDF.pbkdf_timed(algo: 'PBKDF2(SHA-256)', password: 'my secret passphrase', key_length: 8, milliseconds: 100)
hmac = Botan::MAC.new('HMAC(SHA-256)')
hmac.key = Botan.hex_decode('0102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20')
hmac << "\x61\x62\x63"
hmac.hexdigest
The Botan::PK
module exposes functionality for public key loading, exporting, encryption, decryption, signing, and verification.
# generate a 4096-bit RSA key
privkey = Botan::PK::PrivateKey.generate('RSA', params: '4096')
# generate an ECDSA key with group secp384r1
privkey = Botan::PK::PrivateKey.generate('ECDSA', params: 'secp384r1')
# generate a 4096-bit ElGamal key
privkey = Botan::PK::PrivateKey.generate('ElGamal', params: 'modp/ietf/4096')
# load a public key
pubkey = Botan::PK::PublicKey.from_data(File.read('some_file.pem'))
# load an encrypted private key
privkey = Botan::PK::PrivateKey.from_data(File.read('some_file.pem'), password: 'my key password')
# load an unencrypted private key
privkey = Botan::PK::PrivateKey.from_data(File.read('some_file.pem'))
# private key export (PEM)
pem = privkey.export_pem(password: 'my secret password')
# public key export (PEM)
pem = pubkey.export_pem
# using defaults
ciphertext = pubkey.encrypt('my data')
plaintext = privkey.decrypt(ciphertext)
data = 'my data'
# using defaults
signature = privkey.sign(data)
valid = pubkey.verify(data: data, signature: signature)
# load from a file
cert = Botan::X509::Certificate.from_file('my cert.crt')
# load from some data in memory
cert = Botan::X509::Certificate.from_data(File.read('my cert.crt'))
# fingerprint
fpr = cert.fingerprint('SHA-256')
# subject's public key
pubkey = cert.subject_public_key