README.md in lockbox-0.1.0 vs README.md in lockbox-0.1.1
- old
+ new
@@ -1,30 +1,34 @@
# Lockbox
:lock: File encryption for Ruby and Rails
-Supports Active Storage and CarrierWave
+- Supports Active Storage and CarrierWave
+- Uses AES-GCM by default for [authenticated encryption](https://tonyarcieri.com/all-the-crypto-code-youve-ever-written-is-probably-broken)
+- Makes key rotation easy
-Uses AES-GCM by default for [authenticated encryption](https://tonyarcieri.com/all-the-crypto-code-youve-ever-written-is-probably-broken)
+Check out [this post](https://ankane.org/sensitive-data-rails) for more info on securing sensitive data with Rails
+[![Build Status](https://travis-ci.org/ankane/lockbox.svg?branch=master)](https://travis-ci.org/ankane/lockbox)
+
## Installation
Add this line to your application’s Gemfile:
```ruby
gem 'lockbox'
```
## Key Generation
-Generate an encryption key.
+Generate an encryption key
```ruby
SecureRandom.hex(32)
```
-Store the key with your other secrets (typically Rails secrets or an environment variable).
+Store the key with your other secrets. This is typically Rails credentials or an environment variable ([dotenv](https://github.com/bkeepers/dotenv) is great for this). Be sure to use different keys in development and production. Keys don’t need to be hex-encoded, but it’s often easier to store them this way.
Alternatively, you can use a [key management service](#key-management) to manage your keys.
## Files
@@ -35,17 +39,17 @@
```
Encrypt
```ruby
-box.encrypt(File.binread("license.jpg"))
+ciphertext = box.encrypt(File.binread("license.jpg"))
```
Decrypt
```ruby
-box.decrypt(File.binread("license.jpg.enc"))
+box.decrypt(ciphertext)
```
## Active Storage
Add to your model:
@@ -133,15 +137,15 @@
## Algorithms
### AES-GCM
-The default algorithm is AES-GCM with a 256-bit key. Rotate the key every 2 billion files to minimize the chance of a [nonce collision](https://www.cryptologie.net/article/402/is-symmetric-security-solved/).
+The default algorithm is AES-GCM with a 256-bit key. Rotate the key every 2 billion files to minimize the chance of a [nonce collision](https://www.cryptologie.net/article/402/is-symmetric-security-solved/), which will leak the key.
### XChaCha20
-[Install Libsodium](https://github.com/crypto-rb/rbnacl/wiki/Installing-libsodium) and add [rbnacl](https://github.com/crypto-rb/rbnacl) to your application’s Gemfile:
+[Install Libsodium](https://github.com/crypto-rb/rbnacl/wiki/Installing-libsodium) >= 1.0.12 and add [rbnacl](https://github.com/crypto-rb/rbnacl) to your application’s Gemfile:
```ruby
gem 'rbnacl'
```
@@ -168,10 +172,47 @@
Lockbox.default_options = {algorithm: "xchacha20"}
```
You can also pass an algorithm to `previous_versions` for key rotation.
+## Hybrid Cryptography
+
+[Hybrid cryptography](https://en.wikipedia.org/wiki/Hybrid_cryptosystem) allows servers to encrypt data without being able to decrypt it.
+
+[Install Libsodium](https://github.com/crypto-rb/rbnacl/wiki/Installing-libsodium) and add [rbnacl](https://github.com/crypto-rb/rbnacl) to your application’s Gemfile:
+
+```ruby
+gem 'rbnacl'
+```
+
+Generate a key pair with:
+
+```ruby
+Lockbox.generate_key_pair
+```
+
+Store the keys with your other secrets. Then use:
+
+```ruby
+# files
+box = Lockbox.new(algorithm: "hybrid", encryption_key: encryption_key, decryption_key: decryption_key)
+
+# Active Storage
+class User < ApplicationRecord
+ attached_encrypted :license, algorithm: "hybrid", encryption_key: encryption_key, decryption_key: decryption_key
+end
+
+# CarrierWave
+class LicenseUploader < CarrierWave::Uploader::Base
+ encrypt algorithm: "hybrid", encryption_key: encryption_key, decryption_key: decryption_key
+end
+```
+
+Make sure `decryption_key` is `nil` on servers that shouldn’t decrypt.
+
+This uses X25519 for key exchange and XSalsa20-Poly1305 for encryption.
+
## Key Management
You can use a key management service to manage your keys with [KMS Encrypted](https://github.com/ankane/kms_encrypted).
For Active Storage, use:
@@ -189,9 +230,68 @@
encrypt key: -> { model.kms_key }
end
```
**Note:** KMS Encrypted’s key rotation does not know to rotate encrypted files, so avoid calling `record.rotate_kms_key!` on models with file uploads for now.
+
+## Compatibility
+
+It’s easy to read encrypted files in another language if needed.
+
+Here are [some examples](docs/Compatibility.md).
+
+The format for AES-GCM is:
+
+- nonce (IV) - 12 bytes
+- ciphertext - variable length
+- authentication tag - 16 bytes
+
+For XChaCha20, use the appropriate [Libsodium library](https://libsodium.gitbook.io/doc/bindings_for_other_languages).
+
+## Database Fields
+
+Lockbox can also be used with [attr_encrypted](https://github.com/attr-encrypted/attr_encrypted) for database fields. This gives you:
+
+1. Easy key rotation
+2. XChaCha20
+3. Hybrid cryptography
+4. No need for separate IV columns
+
+Add to your Gemfile:
+
+```ruby
+gem 'attr_encrypted'
+```
+
+Create a migration to add a new column for the encrypted data. We don’t need a separate IV column, as this will be included in the encrypted data.
+
+```ruby
+class AddEncryptedPhoneToUsers < ActiveRecord::Migration[5.2]
+ def change
+ add_column :users, :encrypted_phone, :string
+ end
+end
+```
+
+All Lockbox options are supported.
+
+```ruby
+class User < ApplicationRecord
+ attr_encrypted :phone, encryptor: Lockbox::Encryptor, key: key, algorithm: "xchacha20", previous_versions: [{key: previous_key}]
+
+ attribute :encrypted_phone_iv # prevent attr_encrypted error
+end
+```
+
+For hybrid cryptography, use:
+
+```ruby
+class User < ApplicationRecord
+ attr_encrypted :phone, encryptor: Lockbox::Encryptor, algorithm: "hybrid", encryption_key: encryption_key, decryption_key: decryption_key
+
+ attribute :encrypted_phone_iv # prevent attr_encrypted error
+end
+```
## Reference
Pass associated data to encryption and decryption