class LogStash::Filters::Cipher

This filter parses a source and apply a cipher or decipher before storing it in the target.

Public Instance Methods

filter(event) click to toggle source
# File lib/logstash/filters/cipher.rb, line 130
def filter(event)
  source = event.get(@source)
  if (source.nil? || source.empty?)
    @logger.debug("Event to filter, event 'source' field: " + @source + " was null(nil) or blank, doing nothing")
    return
  end

  result = case(@mode)
           when "encrypt" then do_encrypt(source)
           when "decrypt" then do_decrypt(source)
           else
             @logger.error("Invalid cipher mode. Valid values are \"encrypt\" or \"decrypt\"", :mode => @mode)
             raise "Internal Error, aborting."
           end

  event.set(@target, result)
  filter_matched(event) unless result.nil?
rescue => e
  @logger.error("An error occurred while #{@mode}ing.", :exception => e.message)
  event.tag("_cipherfiltererror")
end
register() click to toggle source
# File lib/logstash/filters/cipher.rb, line 117
def register
  require 'base64' if @base64
  if cipher_reuse_enabled?
    @reusable_cipher = Concurrent::ThreadLocalVar.new
    @cipher_reuse_count = Concurrent::ThreadLocalVar.new
  end

  if @key.value.length != @key_size
    @logger.debug("key length is " + @key.length.to_s + ", padding it to " + @key_size.to_s + " with '" + @key_pad.to_s + "'")
    @key = @key.class.new(@key.value[0,@key_size].ljust(@key_size,@key_pad))
  end
end

Private Instance Methods

cipher_reuse_enabled?() click to toggle source
# File lib/logstash/filters/cipher.rb, line 154
def cipher_reuse_enabled?
  @max_cipher_reuse > 1
end
cleanup_reusable_cipher() click to toggle source
# File lib/logstash/filters/cipher.rb, line 236
def cleanup_reusable_cipher
  if @cipher_reuse_count.value >= @max_cipher_reuse
    @logger.debug("shared cipher: max_cipher_reuse[#{@max_cipher_reuse}] reached for #{Thread.current}, total_cipher_uses = #{@cipher_reuse_count.value}") if @logger.debug?
    destroy_reusable_cipher
  else
    @logger.debug("shared cipher: resetting for #{Thread.current}")
    @reusable_cipher.value.reset
  end
end
destroy_reusable_cipher() click to toggle source
# File lib/logstash/filters/cipher.rb, line 246
def destroy_reusable_cipher
  @reusable_cipher.value = nil
  @cipher_reuse_count.value = 0
end
do_decrypt(ciphertext_with_iv) click to toggle source

@param ciphertext_with_iv [String] @return [String] plaintext

# File lib/logstash/filters/cipher.rb, line 177
def do_decrypt(ciphertext_with_iv)
  ciphertext_with_iv = Base64.strict_decode64(ciphertext_with_iv) if @base64 == true
  encoded_iv = ciphertext_with_iv.byteslice(0..@iv_random_length)
  ciphertext = ciphertext_with_iv.byteslice(@iv_random_length..-1)

  with_cipher do |cipher|
    cipher.iv = encoded_iv
    plaintext = cipher.update(ciphertext) + cipher.final
    plaintext.force_encoding("UTF-8")
    plaintext
  end
end
do_encrypt(plaintext) click to toggle source

@param plaintext [String] @return [String]: ciphertext

# File lib/logstash/filters/cipher.rb, line 161
def do_encrypt(plaintext)
  with_cipher do |cipher|
    random_iv = OpenSSL::Random.random_bytes(@iv_random_length)
    cipher.iv = random_iv

    ciphertext = random_iv + cipher.update(plaintext) + cipher.final

    ciphertext = Base64.strict_encode64(ciphertext).encode("utf-8") if @base64 == true

    ciphertext
  end
end
get_or_init_reusable_cipher() click to toggle source
# File lib/logstash/filters/cipher.rb, line 225
def get_or_init_reusable_cipher
  if @reusable_cipher.value.nil?
    @logger.debug("shared cipher: initializing for #{Thread.current}")
    @reusable_cipher.value = init_cipher
    @cipher_reuse_count.value = 0
  end

  @cipher_reuse_count.value += 1
  @reusable_cipher.value
end
init_cipher() click to toggle source

@return [OpenSSL::Cipher]

# File lib/logstash/filters/cipher.rb, line 253
def init_cipher
  cipher = OpenSSL::Cipher.new(@algorithm)

  cipher.public_send(@mode)

  cipher.key = @key.value

  cipher.padding = @cipher_padding if @cipher_padding

  if @logger.trace?
    @logger.trace("Cipher initialisation done", :mode => @mode,
                                                :key => @key.value,
                                                :iv_random_length => @iv_random_length,
                                                :iv_random => @iv_random,
                                                :cipher_padding => @cipher_padding)
  end

  cipher
end
with_cipher() { |init_cipher| ... } click to toggle source

Returns a new or freshly-reset cipher, bypassing cipher reuse if it is not enabled

@yieldparam [OpenSSL::Cipher] @yieldreturn [Object]: the object that this method should return @return [Object]: the object that was returned by the yielded block

# File lib/logstash/filters/cipher.rb, line 196
def with_cipher
  return yield(init_cipher) unless cipher_reuse_enabled?

  with_reusable_cipher do |reusable_cipher|
    yield reusable_cipher
  end
end
with_reusable_cipher() { |cipher| ... } click to toggle source

Returns a new or freshly-reset cipher.

@yieldparam [OpenSSL::Cipher] @yieldreturn [Object]: the object that this method should return @return [Object]: the object that was returned by the yielded block

# File lib/logstash/filters/cipher.rb, line 210
def with_reusable_cipher
  cipher = get_or_init_reusable_cipher

  result = yield(cipher)

  cleanup_reusable_cipher

  return result
rescue => e
  # when an error is encountered, we cannot trust the state of the cipher object.
  @logger.debug("shared cipher: removing because an exception was raised in #{Thread.current}", :exception => e.message)
  destroy_reusable_cipher
  raise
end