lib/blind_index.rb in blind_index-0.2.1 vs lib/blind_index.rb in blind_index-0.3.0

- old
+ new

@@ -6,24 +6,64 @@ require "blind_index/version" module BlindIndex class Error < StandardError; end - def self.generate_bidx(value, key:, iterations:, expression: nil, **options) - key = key.call if key.respond_to?(:call) + class << self + attr_accessor :default_options + end + self.default_options = { + iterations: 10000, + algorithm: :pbkdf2_hmac, + insecure_key: false, + encode: true + } - raise BlindIndex::Error, "Missing key for blind index" unless key + def self.generate_bidx(value, key:, **options) + options = default_options.merge(options) # apply expression - value = expression.call(value) if expression + value = options[:expression].call(value) if options[:expression] unless value.nil? - # generate hash - digest = OpenSSL::Digest::SHA256.new - value = OpenSSL::PKCS5.pbkdf2_hmac(value.to_s, key, iterations, digest.digest_length, digest) + algorithm = options[:algorithm].to_sym - # encode - [value].pack("m") + key = key.call if key.respond_to?(:call) + raise BlindIndex::Error, "Missing key for blind index" unless key + + key = key.to_s + unless options[:insecure_key] && algorithm == :pbkdf2_hmac + raise BlindIndex::Error, "Key must use binary encoding" if key.encoding != Encoding::BINARY + # raise BlindIndex::Error, "Key must not be ASCII" if key.bytes.all? { |b| b < 128 } + raise BlindIndex::Error, "Key must be 32 bytes" if key.bytesize != 32 + end + + # gist to compare algorithm results + # https://gist.github.com/ankane/fe3ac63fbf1c4550ee12554c664d2b8c + value = + case algorithm + when :scrypt + # n, p (keep r at 8) + SCrypt::Engine.scrypt(value.to_s, key, 4096, 8, 1, 32) + when :argon2 + # t_cost, m_cost + [Argon2::Engine.hash_argon2i(value.to_s, key, 2, 12)].pack("H*") + when :pbkdf2_hmac + OpenSSL::PKCS5.pbkdf2_hmac(value.to_s, key, options[:iterations], 32, "sha256") + else + raise BlindIndex::Error, "Unknown algorithm" + end + + encode = options[:encode] + if encode + if encode.respond_to?(:call) + encode.call(value) + else + [value].pack("m") + end + else + value + end end end end ActiveSupport.on_load(:active_record) do