lib/lockbox.rb in lockbox-0.1.0 vs lib/lockbox.rb in lockbox-0.1.1
- old
+ new
@@ -1,11 +1,8 @@
-# dependencies
-require "openssl"
-require "securerandom"
-
# modules
require "lockbox/box"
+require "lockbox/encryptor"
require "lockbox/utils"
require "lockbox/version"
# integrations
require "lockbox/carrier_wave_extensions" if defined?(CarrierWave)
@@ -18,39 +15,66 @@
class << self
attr_accessor :default_options
end
self.default_options = {algorithm: "aes-gcm"}
- def initialize(key: nil, algorithm: nil, previous_versions: nil)
- default_options = self.class.default_options
- key ||= default_options[:key]
- algorithm ||= default_options[:algorithm]
- previous_versions ||= default_options[:previous_versions]
+ def initialize(**options)
+ options = self.class.default_options.merge(options)
+ previous_versions = options.delete(:previous_versions)
@boxes =
- [Box.new(key, algorithm: algorithm)] +
- Array(previous_versions).map { |v| Box.new(v[:key], algorithm: v[:algorithm]) }
+ [Box.new(options)] +
+ Array(previous_versions).map { |v| Box.new(v) }
end
- def encrypt(*args)
- @boxes.first.encrypt(*args)
+ def encrypt(message, **options)
+ message = check_string(message, "message")
+ @boxes.first.encrypt(message, **options)
end
def decrypt(ciphertext, **options)
- raise TypeError, "can't convert ciphertext to string" unless ciphertext.respond_to?(:to_str)
+ ciphertext = check_string(ciphertext, "ciphertext")
# ensure binary
- ciphertext = ciphertext.to_str
if ciphertext.encoding != Encoding::BINARY
# dup to prevent mutation
ciphertext = ciphertext.dup.force_encoding(Encoding::BINARY)
end
@boxes.each_with_index do |box, i|
begin
return box.decrypt(ciphertext, **options)
- rescue DecryptionError, RbNaCl::LengthError, RbNaCl::CryptoError
- raise DecryptionError, "Decryption failed" if i == @boxes.size - 1
+ rescue => e
+ error_classes = [DecryptionError]
+ error_classes << RbNaCl::LengthError if defined?(RbNaCl::LengthError)
+ error_classes << RbNaCl::CryptoError if defined?(RbNaCl::CryptoError)
+ if error_classes.any? { |ec| e.is_a?(ec) }
+ raise DecryptionError, "Decryption failed" if i == @boxes.size - 1
+ else
+ raise e
+ end
end
end
+ end
+
+ def self.generate_key_pair
+ require "rbnacl"
+ # encryption and decryption servers exchange public keys
+ # this produces smaller ciphertext than sealed box
+ alice = RbNaCl::PrivateKey.generate
+ bob = RbNaCl::PrivateKey.generate
+ # alice is sending message to bob
+ # use bob first in both cases to prevent keys being swappable
+ {
+ encryption_key: (bob.public_key.to_bytes + alice.to_bytes).unpack("H*").first,
+ decryption_key: (bob.to_bytes + alice.public_key.to_bytes).unpack("H*").first
+ }
+ end
+
+ private
+
+ def check_string(str, name)
+ str = str.read if str.respond_to?(:read)
+ raise TypeError, "can't convert #{name} to string" unless str.respond_to?(:to_str)
+ str.to_str
end
end