Code Monkey home page Code Monkey logo

crypt_keeper's People

Contributors

campbecf avatar capncavedan avatar ch4s3 avatar dankohn avatar drichert avatar fabiokr avatar itspriddle avatar jesperronn avatar jmazzi avatar johan-smits avatar joshk avatar kevin-j-m avatar mchaisse avatar nikz avatar rwc9u avatar saulcosta avatar scottjbarr avatar serixscorpio avatar tfwright avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

crypt_keeper's Issues

Clean out Travis build matrix to speed up CI

This innocent looking support matrix in .travis.yml is very deceptive

rvm:
  - 1.9.3
  - 2.0.0
  - 2.1.1

gemfile:
  - gemfiles/activerecord_3_1.gemfile
  - gemfiles/activerecord_3_2.gemfile
  - gemfiles/activerecord_4_0.gemfile
  - gemfiles/activerecord_4_1.gemfile
  - gemfiles/activerecord_4_2.gemfile

matrix
  include:
    - rvm: 2.2.0
      gemfile: gemfiles/activerecord_4_2.gemfile

this runs 3x5+1 = 16 jobs and takes 21 minutes before you get feedback after commit.

We also need to add newer ruby versions: 2.3.0 at least, and the upcoming rails 5 version.

Any suggestions as to which jobs should be weeded out to make space for newer versions?

Is salt meant to be used at row or at model level?

Perhaps I'm getting it totally wrong, but is it possible to store the salt as column in the database on a per row level?

I think about other enryption solutions, that store one salt per encrypted record

Just to clarify, why is salt the same for all record of a model?

Thanks in advance!

Best Regards,
Roberto

TypeError: no implicit conversion of nil into String

I'm giving this gem a quick try, I applied this into my model:

crypt_keeper :token, :secret, encryptor: :aes, key: 'super_good_password', salt: 'salt'
2.0.0p353 :001 > AuthToken.first
TypeError: no implicit conversion of nil into String
  gems/aes-0.5.0/lib/aes/aes.rb:76:in `update'
  gems/aes-0.5.0/lib/aes/aes.rb:76:in `decrypt'
  gems/aes-0.5.0/lib/aes/aes.rb:9:in `decrypt'
  bundler/gems/crypt_keeper-1c9050c4c9db/lib/crypt_keeper/provider/aes.rb:34:in `decrypt'
  bundler/gems/crypt_keeper-1c9050c4c9db/lib/crypt_keeper/helper.rb:34:in `load'
  bundler/gems/rails-b23d3ffcd157/activerecord/lib/active_record/attribute_methods/serialization.rb:89:in `unserialize'
  bundler/gems/rails-b23d3ffcd157/activerecord/lib/active_record/attribute_methods/serialization.rb:80:in `unserialized_value'
  bundler/gems/rails-b23d3ffcd157/activerecord/lib/active_record/attribute_methods/serialization.rb:67:in `type_cast'
  bundler/gems/rails-b23d3ffcd157/activerecord/lib/active_record/attribute_methods/read.rb:101:in `block in read_attribute'
  bundler/gems/rails-b23d3ffcd157/activerecord/lib/active_record/attribute_methods/read.rb:84:in `fetch'
  bundler/gems/rails-b23d3ffcd157/activerecord/lib/active_record/attribute_methods/read.rb:84:in `read_attribute'
  bundler/gems/rails-b23d3ffcd157/activerecord/lib/active_record/attribute_methods.rb:272:in `attribute_for_inspect'
  bundler/gems/rails-b23d3ffcd157/activerecord/lib/active_record/core.rb:354:in `block in inspect'
  bundler/gems/rails-b23d3ffcd157/activerecord/lib/active_record/core.rb:352:in `collect'
  bundler/gems/rails-b23d3ffcd157/activerecord/lib/active_record/core.rb:352:in `inspect'
  bundler/gems/rails-b23d3ffcd157/railties/lib/rails/commands/console.rb:90:in `start'

In the fetched row secret is nil, however it was my understanding that this should just return the original value instead of raising: https://github.com/jmazzi/crypt_keeper/blob/master/lib/crypt_keeper/provider/aes.rb#L28

Guidelines for key and salt

I would love to see an example of how to implement the key and salt securely.

How long do they need to be? Should they be the same for each column or generate a random one each time?

Always updating crypt_keeper field

Hi,

I am using crypt keeper with devise on a user model, and I'm encrypting the users email address. The issue is, that even though I don't update the email field (only some other field), the email address field is updated every time. This is causing devise to send out confirmation emails every time I update the user. Is there a way to stop updating these field when they are not changed?

Could not log "sql.active_record" event

Getting this error on my show page after creating a new record:

Could not log "sql.active_record" event. 
ArgumentError: invalid byte sequence in UTF-8 ["/Users/me/.rvm/gems/ruby-2.0.0-p451@App/gems/crypt_keeper-0.18.1/lib/crypt_keeper/log_subscriber/mysql_aes.rb:17:in `gsub'", 
"/Users/me/.rvm/gems/ruby-2.0.0-p451@App/gems/crypt_keeper-0.18.1/lib/crypt_keeper/log_subscriber/mysql_aes.rb:17:in `sql_with_mysql_aes'"

I'm using crypt_keeper :name, :encryptor => :mysql_aes_new, :key => ENV['TOKEN_KEY'], salt: ENV['SALT'], :encoding => 'UTF-8'

Lazy decryption

Hi, i use crypt_keeper and it's really cool, but notice a big amount of
(0.2ms) SELECT AES_DECRYPT([FILTERED])
(0.4ms) SELECT AES_DECRYPT([FILTERED])
(0.2ms) SELECT AES_DECRYPT([FILTERED])
(0.2ms) SELECT AES_DECRYPT([FILTERED])
Requests, as i understand it's for decryption of loaded records, is there any possibility to make keeper more lazy, for example to do request only when i try to access to encrypted data, because usually i do not need that secret stuff

AES New Encryptor doesn't handle empty string

According to the documentation provider/aes_new.rb, the aes_new returns empty string when encounters empty string, instead it raises exception

2.3.0 :036 > @aes_new_encryptor.encrypt("")
ArgumentError: data must not be empty
    from /Users/hanjie/.rvm/gems/ruby-2.3.0/gems/aes-0.5.0/lib/aes/aes.rb:119:in `update'
    from /Users/hanjie/.rvm/gems/ruby-2.3.0/gems/aes-0.5.0/lib/aes/aes.rb:119:in `_encrypt'
    from /Users/hanjie/.rvm/gems/ruby-2.3.0/gems/aes-0.5.0/lib/aes/aes.rb:58:in `encrypt'
    from /Users/hanjie/.rvm/gems/ruby-2.3.0/gems/aes-0.5.0/lib/aes/aes.rb:5:in `encrypt'
    from /Users/hanjie/.rvm/gems/ruby-2.3.0/gems/crypt_keeper-0.20.0/lib/crypt_keeper/provider/aes_new.rb:27:in `encrypt'
    from (irb):36
    from /Users/hanjie/.rvm/gems/ruby-2.3.0/gems/railties-4.1.7/lib/rails/commands/console.rb:90:in `start'
    from /Users/hanjie/.rvm/gems/ruby-2.3.0/gems/railties-4.1.7/lib/rails/commands/console.rb:9:in `start'
    from /Users/hanjie/.rvm/gems/ruby-2.3.0/gems/railties-4.1.7/lib/rails/commands/commands_tasks.rb:69:in `console'
    from /Users/hanjie/.rvm/gems/ruby-2.3.0/gems/railties-4.1.7/lib/rails/commands/commands_tasks.rb:40:in `run_command!'
    from /Users/hanjie/.rvm/gems/ruby-2.3.0/gems/railties-4.1.7/lib/rails/commands.rb:17:in `<top (required)>'
    from bin/rails:4:in `require'
    from bin/rails:4:in `<main>'

Clarify the role of the salt

Right now the README mentions the new salt option only once, in the sample code.

I have to admit I'm confused about the meaning and usage of this new option.
Traditionally salts are pseudo random characters that are not shared across the whole application but instead are stored at the entity level (think password column and password_salt column in a DB) to make unique hashes even if the input data is the same.
Having that in mind, as it is in the code sample the salt is going to be the same for every record, isn't it? If so, what's the point in the first place?

More details than the ones stated in this commit message would be welcome.

Unable to run migration without commenting-out crypt_keeper calls...

When attempting to db:migrate from a clean state (i.e. after db:drop/db:create), I'm getting the following error:

PG::Error: ERROR:  relation "people" does not exist
LINE 4:              WHERE a.attrelid = '"people"'::regclass
                                        ^
:             SELECT a.attname, format_type(a.atttypid, a.atttypmod), d.adsrc, a.attnotnull
              FROM pg_attribute a LEFT JOIN pg_attrdef d
                ON a.attrelid = d.adrelid AND a.attnum = d.adnum
             WHERE a.attrelid = '"people"'::regclass
               AND a.attnum > 0 AND NOT a.attisdropped
             ORDER BY a.attnum

If I comment-out the crypt_keeper call in my model, the migration will complete, as-expected.

Intended behavior: defer relations checks until database has been migrated.

Form fields display encrypted string in Rails 4.2

Hi,
Im having an extrange issue when trying to edit an encrypted field through a form.
Everything works just fine, the data is saved ok and retreived without problems (if I print object.inspect, that field shows un-encrypted), but when I try to show the input with:

<%= f.text_area :protected_field, class: "input-xxlarge text-field-box" %>

The textarea contains the data encrypted.

Everything works fine in Rails 4.1.4. I'm having this issue only with Rails 4.2.1

Exception occurs with empty string

When saving a record where an encrypted field has a value of "" (empty string), as is common when a web form field is left blank, crypt_keeper raises an exception.

I've worked around it by setting the field to nil if it == "" in the controller but this is inelegant for sure.

Is there a cleaner workaround I'm not aware of?

Thanks,
-Dan

AESNew ecryption: support Postgres Text[] types

Given an activerecord table with a text column created with array: true

t.text     "my_column",       default: [], array: true

And

class MyModel < ActiveRecord::Base
  crypt_keeper :my_column, encryptor: :aes_new, key: 'CRYPT_KEEPER_KEY', salt: 'CRYPT_KEEPER_SALT'
 end

MyModel.encrypt_table! fails:

TypeError: no implicit conversion of Array into String
    from /Users/fritz/devprojects/smartpropertysystems/.gems/gems/aes-0.5.0/lib/aes/aes.rb:119:in `update'
    from /Users/fritz/devprojects/smartpropertysystems/.gems/gems/aes-0.5.0/lib/aes/aes.rb:119:in `_encrypt'
    from /Users/fritz/devprojects/smartpropertysystems/.gems/gems/aes-0.5.0/lib/aes/aes.rb:58:in `encrypt'
    from /Users/fritz/devprojects/smartpropertysystems/.gems/gems/aes-0.5.0/lib/aes/aes.rb:5:in `encrypt'

It would be good if CryptKeeper could encrypt each value in the text[] column.

no implicit conversion of Fixnum into String

Hi,
I get the following error when trying to save a record with an integer as value:
"TypeError: no implicit conversion of Fixnum into String".

Model contains:
crypt_keeper :my_field, encryptor: :aes_new, key: 'secret', salt: 'salt'

In Rails console:

m = MyModel.new
m.my_field = 123
m.save
TypeError: no implicit conversion of Fixnum into String

appraisal

does appraisal need to be included? Isn''t it just for testing the gem?

Rails 5.0 beta: Bundler could not find compatible versions for gem "activerecord"

Playing around with the beta of Rails 5.0, and hit this gem compatibility issue:

Bundler could not find compatible versions for gem "activerecord":
  In Gemfile:
    crypt_keeper (~> 0.20) was resolved to 0.20.0, which depends on
      activerecord (< 4.3, >= 3.1)

    rails (~> 5.0.0.beta1) was resolved to 5.0.0.beta1, which depends on
      activerecord (= 5.0.0.beta1)

Happy to investigate how the compatibility of the gem with Rails 5.0 and submit a PR updating the dependencies, if nobody else is working on it already.

Become really transparent for ActiveRecord

Meantime while this gem is really cool, it's not fully transparent for models. I can mention at least two things it affects:

  1. If I want to crypt not-string attribute (integer or date), I'm forced to change db column type to :text, and Rails casting stop to work for me. I need to implement own workarounds (btw, do you know pretty solutions)?
  2. New Rails 4.2 behaviour with form helpers, related to #99. They use attribute_before_type_cast method. So, if I have date encrypted field, and I've figured out typecasting from string to DateTime object, I can't get string value for date. attribute will return DateTime, while attribute_before_type_cast will return encrypted value for me.

So, I need, the best way is to encrypt/decrypt somewhere before attribute_before_type_cast method + provide cool solution for rails casting to integer, date or datetime types. This way the gem will be really transparent, and even more rocks!

Thank you!

Shortly after running MyModel.encrypt_table! the data becomes unrecoverable

I've installed the gem and am using MySQL AES and the encryptor seen in this repository.

I added the line below to the model for which I'm encrypting some columns:

crypt_keeper :field1, :field2, :encryptor => :mysql_aes_new, :key => ENV['SECRET_KEY_BASE'], :salt => 'random string'

After running MyModel.encrypt_table! the data had been encrypted and when trying User.last.field1 it decrypted on-the-fly (which is cryptkeeper working). However, a few hours later when doing the same thing the data was scrambled and seems unrecoverable. I have backups so it's not a problem, but I want to be encrypting this data and this is causing a problem.

Why would this be happening?

NoMethodError: undefined method `decrypt_table!' for

Service.encrypt_table! is fine, but decrypt_table! is undefined.

class Service
(...)
  crypt_keeper :options,
                encryptor: :aes_new,
                key: 'XXXXXXXXXXXXXXXXXXX',
                salt: 'XXXXXXXXXXXXXXXXXXX',
                encoding: 'UTF-8'
(...)
end

[4] pry(main)> Service.crypt_keeper_fields?
=> true
[5] pry(main)> Service.dec
Service.decorate_columns   Service.decrement_counter  Service.decrypt            
[5] pry(main)> Service.encrypt
Service.encrypt         Service.encrypt_table!  
[5] pry(main)> Service.encrypt
Service.encrypt         Service.encrypt_table!  
[5] pry(main)> Service.decrypt
Service.decrypt
[5] pry(main)> Service.decrypt_table!
NoMethodError: undefined method `decrypt_table!' for Service (call 'Service.connection' to establish a connection):Class
from /media/mkalita/storage/efiduty_local/vendor/bundle/ruby/2.2.0/gems/activerecord-4.1.6/lib/active_record/dynamic_matchers.rb:26:in `method_missing'

Problems with UTF-8? incompatible character encodings: ASCII-8BIT and UTF-8

Hi

Minor problem. Thank you for a usefull gem :-)

I am using crypt_keeper (0.13.1) with encryptor aes in an linux, rails 4, ruby 2, sqllite3 project Work fine except when I enter UTF-8 characters in an html from.

Gets ActionView::Template::Error (incompatible character encodings: ASCII-8BIT and UTF-8) when the saved data is displayed after submit.

Works if I remove the attribute from crypt_keeper column list. Verifies that there are no other utf8 encoding problems in my project).
Works if I adds .force_encoding("UTF-8") where the data is displayed in view.

Ok to add .force_encoding("UTF-8") in views, but maybe there is a better solution?!

Kind Regards
Jan

Returned records are always dirty - issues with plaintext accessors and database fields being named the same

I've found a couple issues related to both the plaintext accessor methods and the encrypted database field names being the same, and being converted with callbacks:

  1. The record is always inherently dirty.
  2. Because the record is always dirty, the encrypted attributes get updated on every save, regardless of whether they changed.

An example of where this may cause an issue: if I'm trying to use an auditing library like paper_trail, it's recording the attributes as part of a callback. Because crypt_keeper users a before_save callback to encrypt the fields, it's possible that some libraries will grab the plain-text attribute values.

I find attr_encrypted's approach much less problematic for this case. The database fields are named encrypted_foo, and then it creates accessors foo and foo=. The added benefit is that the attributes are lazy-loaded, which gives a persistent performance benefit. You also don't need to worry about any other callbacks or Observers. Additionally, direct manipulation of an encrypted field, e.g. User.update_column(:encrypted_ssn, '"\\xc30d040..") is more explicitly communicative.

This may be too sweeping of a suggested change for a library that's emphasizing not being too complicated. These aspects may be better as a documentation change, and I could try adapting your pgcrypto() code into a custom attr_encrypted-compatible Encryptor object.

crypt keeper gem touching Rails model when nothing updates, causing updated_at to refresh

I have the snippet below in my User model:

crypt_keeper :secret_field, encryptor: :aes_new, key: ENV['SECRET_KEY_BASE'], salt: 'secret salt'

It's encrypting the data using the specified encryptor just fine, however, when calling the save method on the model it resets the :secret_field on the model causing the updated_at to also be reset.

For example, on another model, the snippet below would do nothing:

client = Client.find(1)
client.save

However, on a model with crypt keeper it updates the encrypted field and then sets the updated_at. How can this be prevented?

`alias_method_chain` deprecated

alias_method_chain is deprecated as of Rails 5.

A potential patch, but looking through logs I noticed that RSpec is complaining about stubbing, so testing that avoids that would be preferable. I'll dig more into it when I have time, for now Rails 5 users will see deprecation notices when the log scrubbers are loaded.

Patch:

commit 194d2a311bdfa9b1b592cfb80b22a156b1917bf5
Author:     Joshua Priddle <[email protected]>
AuthorDate: Thu Sep 22 14:31:31 2016 -0400
Commit:     Joshua Priddle <[email protected]>
CommitDate: Thu Sep 22 14:31:31 2016 -0400

    Prefer Module#prepend over alias_method_chain

diff --git a/lib/crypt_keeper/log_subscriber/mysql_aes.rb b/lib/crypt_keeper/log_subscriber/mysql_aes.rb
index 72af0e1..9dd98cd 100644
--- a/lib/crypt_keeper/log_subscriber/mysql_aes.rb
+++ b/lib/crypt_keeper/log_subscriber/mysql_aes.rb
@@ -4,14 +4,12 @@ require 'active_support/lazy_load_hooks'
 module CryptKeeper
   module LogSubscriber
     module MysqlAes
-      extend ActiveSupport::Concern
-
-      included do
-        alias_method_chain :sql, :mysql_aes
-      end
-
       # Public: Prevents sensitive data from being logged
-      def sql_with_mysql_aes(event)
+      #
+      # event - An ActiveSupport::Notifications::Event
+      #
+      # Returns a boolean.
+      def sql(event)
         filter  = /(aes_(encrypt|decrypt))\(.*\)/i
         payload = event.payload[:sql]
           .encode('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '')
@@ -22,12 +20,12 @@ module CryptKeeper
           "#{$1}([FILTERED])"
         end

-        sql_without_mysql_aes(event)
+        super(event)
       end
     end
   end
 end

 ActiveSupport.on_load :crypt_keeper_mysql_aes_log do
-  ActiveRecord::LogSubscriber.send :include, CryptKeeper::LogSubscriber::MysqlAes
+  ActiveRecord::LogSubscriber.prepend CryptKeeper::LogSubscriber::MysqlAes
 end
diff --git a/lib/crypt_keeper/log_subscriber/postgres_pgp.rb b/lib/crypt_keeper/log_subscriber/postgres_pgp.rb
index b021972..7109fcb 100644
--- a/lib/crypt_keeper/log_subscriber/postgres_pgp.rb
+++ b/lib/crypt_keeper/log_subscriber/postgres_pgp.rb
@@ -4,14 +4,12 @@ require 'active_support/lazy_load_hooks'
 module CryptKeeper
   module LogSubscriber
     module PostgresPgp
-      extend ActiveSupport::Concern
-
-      included do
-        alias_method_chain :sql, :postgres_pgp
-      end
-
       # Public: Prevents sensitive data from being logged
-      def sql_with_postgres_pgp(event)
+      #
+      # event - An ActiveSupport::Notifications::Event
+      #
+      # Returns a boolean.
+      def sql(event)
         filter  = /(\(*)pgp_(sym|pub)_(?<operation>decrypt|encrypt)(\(+.*\)+)/im
         payload = event.payload[:sql]
           .encode('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '')
@@ -22,12 +20,12 @@ module CryptKeeper
           "#{$~[:operation]}([FILTERED])"
         end

-        sql_without_postgres_pgp(event)
+        super(event)
       end
     end
   end
 end

 ActiveSupport.on_load :crypt_keeper_postgres_pgp_log do
-  ActiveRecord::LogSubscriber.send :include, CryptKeeper::LogSubscriber::PostgresPgp
+  ActiveRecord::LogSubscriber.prepend CryptKeeper::LogSubscriber::PostgresPgp
 end
diff --git a/spec/log_subscriber/mysql_aes_spec.rb b/spec/log_subscriber/mysql_aes_spec.rb
index 67434b9..c681a22 100644
--- a/spec/log_subscriber/mysql_aes_spec.rb
+++ b/spec/log_subscriber/mysql_aes_spec.rb
@@ -16,6 +16,14 @@ module CryptKeeper::LogSubscriber

       subject { ::ActiveRecord::LogSubscriber.new }

+      let(:logger) do
+        subject.send(:logger)
+      end
+
+      def verify_log(query)
+        logger.should_receive(:debug).with(/#{Regexp.escape(query)}/)
+      end
+
       let(:input_query) do
         "SELECT aes_encrypt('encrypt_value', 'encrypt_key'), aes_decrypt('decrypt_value', 'decrypt_key') FROM DUAL;"
       end
@@ -33,25 +41,19 @@ module CryptKeeper::LogSubscriber
       end

       it "filters aes functions" do
-        subject.should_receive(:sql_without_mysql_aes) do |event|
-          event.payload[:sql].should == output_query
-        end
+        verify_log(output_query)

         subject.sql(ActiveSupport::Notifications::Event.new(:sql, 1, 1, 1, { sql: input_query }))
       end

       it "filters aes functions in lowercase" do
-        subject.should_receive(:sql_without_mysql_aes) do |event|
-          event.payload[:sql].should == output_query.downcase.gsub(/filtered/, 'FILTERED')
-        end
+        verify_log(output_query.downcase.gsub(/filtered/, 'FILTERED'))

         subject.sql(ActiveSupport::Notifications::Event.new(:sql, 1, 1, 1, { sql: input_query.downcase }))
       end

       it "filters aes functions when searching" do
-        subject.should_receive(:sql_without_mysql_aes) do |event|
-          event.payload[:sql].should == output_search_query
-        end
+        verify_log(output_search_query)

         subject.sql(ActiveSupport::Notifications::Event.new(:sql, 1, 1, 1, { sql: input_search_query }))
       end
@@ -64,7 +66,7 @@ module CryptKeeper::LogSubscriber
       it "skips logging if CryptKeeper.silence_logs is set" do
         CryptKeeper.silence_logs = true

-        subject.should_not_receive(:sql_without_mysql_aes)
+        logger.should_not_receive(:debug)

         subject.sql(ActiveSupport::Notifications::Event.new(:sql, 1, 1, 1, { sql: input_query }))
       end
diff --git a/spec/log_subscriber/postgres_pgp_spec.rb b/spec/log_subscriber/postgres_pgp_spec.rb
index 6f55c3c..524b834 100644
--- a/spec/log_subscriber/postgres_pgp_spec.rb
+++ b/spec/log_subscriber/postgres_pgp_spec.rb
@@ -6,6 +6,14 @@ module CryptKeeper::LogSubscriber
       CryptKeeper.silence_logs = false
     end

+    let(:logger) do
+      subject.send(:logger)
+    end
+
+    def verify_log(query)
+      logger.should_receive(:debug).with(/#{Regexp.escape(query)}/)
+    end
+
     use_postgres

     context "Symmetric encryption" do
@@ -33,25 +41,19 @@ module CryptKeeper::LogSubscriber
       end

       it "filters pgp functions" do
-        subject.should_receive(:sql_without_postgres_pgp) do |event|
-          event.payload[:sql].should == output_query
-        end
+        verify_log(output_query)

         subject.sql(ActiveSupport::Notifications::Event.new(:sql, 1, 1, 1, { sql: input_query }))
       end

       it "filters pgp functions in lowercase" do
-        subject.should_receive(:sql_without_postgres_pgp) do |event|
-          event.payload[:sql].should == output_query.downcase.gsub(/filtered/, 'FILTERED')
-        end
+        verify_log(output_query.downcase.gsub(/filtered/, 'FILTERED'))

         subject.sql(ActiveSupport::Notifications::Event.new(:sql, 1, 1, 1, { sql: input_query.downcase }))
       end

       it "filters pgp functions when searching" do
-        subject.should_receive(:sql_without_postgres_pgp) do |event|
-          event.payload[:sql].should == output_search_query
-        end
+        verify_log(output_search_query)

         subject.sql(ActiveSupport::Notifications::Event.new(:sql, 1, 1, 1, { sql: input_search_query }))
       end
@@ -64,7 +66,7 @@ module CryptKeeper::LogSubscriber
       it "skips logging if CryptKeeper.silence_logs is set" do
         CryptKeeper.silence_logs = true

-        subject.should_not_receive(:sql_without_postgres_pgp)
+        logger.should_not_receive(:debug)

         subject.sql(ActiveSupport::Notifications::Event.new(:sql, 1, 1, 1, { sql: input_query }))
       end
@@ -96,17 +98,13 @@ module CryptKeeper::LogSubscriber
       end

       it "filters pgp functions" do
-        subject.should_receive(:sql_without_postgres_pgp) do |event|
-          event.payload[:sql].should == output_query
-        end
+        verify_log(output_query)

         subject.sql(ActiveSupport::Notifications::Event.new(:sql, 1, 1, 1, { sql: input_query }))
       end

       it "filters pgp functions in lowercase" do
-        subject.should_receive(:sql_without_postgres_pgp) do |event|
-          event.payload[:sql].should == output_query.downcase.gsub(/filtered/, 'FILTERED')
-        end
+        verify_log(output_query.downcase.gsub(/filtered/, 'FILTERED'))

         subject.sql(ActiveSupport::Notifications::Event.new(:sql, 1, 1, 1, { sql: input_query.downcase }))
       end
@@ -114,7 +112,7 @@ module CryptKeeper::LogSubscriber
       it "skips logging if CryptKeeper.silence_logs is set" do
         CryptKeeper.silence_logs = true

-        subject.should_not_receive(:sql_without_postgres_pgp)
+        logger.should_not_receive(:debug)

         subject.sql(ActiveSupport::Notifications::Event.new(:sql, 1, 1, 1, { sql: input_query }))
       end

AES encryptor is not UTF-8 compatible

I would expect the below spec to be true but unfortunately I get something completely different back.

  1. Address validations utf-8 encoded addreses should decrypt properly
    Failure/Error: expect(newly_saved.city).to eq 'Tromsø'
  expected: "Tromsø"
       got: "Troms\xC3\xB8"
    describe "utf-8 encoded addreses" do
      let(:address) { build :address, player_id: 1, city: 'Tromsø' }

      it "should decrypt properly" do
        address.save!
        newly_saved = Address.find(address.id)
        expect(newly_saved.city).to eq 'Tromsø'
      end
    end

Any suggestions @jmazzi ?

Error while selecting specific non encrypted fields

I am encrypting some of the columns of table in my rails app. In model i specify the fields of table to be encryptes. All the encryption and decryption is working fine but in case where i am fetching only specific non encrypted fields like id and name. its throwing an exception like ActiveModel::MissingAttributeError - missing attribute.
stacktrace is as follows:

activemodel (4.0.9) lib/active_model/attribute_methods.rb:481:in `missing_attribute'
  activerecord (4.0.9) lib/active_record/attribute_methods/read.rb:59:in `block in __temp__26c6f6f646f57627f65707'
  activerecord (4.0.9) lib/active_record/attribute_methods/read.rb:95:in `block (2 levels) in read_attribute'
  activerecord (4.0.9) lib/active_record/attribute_methods/read.rb:94:in `block in read_attribute'
  activerecord (4.0.9) lib/active_record/attribute_methods/read.rb:84:in `read_attribute'
  activerecord (4.0.9) lib/active_record/attribute_methods/read.rb:59:in `__temp__26c6f6f646f57627f65707'
  crypt_keeper (0.18.2) lib/crypt_keeper/model.rb:30:in `block in force_encodings_on_fields'
  crypt_keeper (0.18.2) lib/crypt_keeper/model.rb:29:in `force_encodings_on_fields'
  activesupport (4.0.9) lib/active_support/callbacks.rb:375:in `_run__1730928489337275095__find__callbacks'
  activesupport (4.0.9) lib/active_support/callbacks.rb:80:in `run_callbacks'
  activerecord (4.0.9) lib/active_record/core.rb:210:in `init_with'
  activerecord (4.0.9) lib/active_record/persistence.rb:52:in `instantiate'
  activerecord (4.0.9) lib/active_record/querying.rb:45:in `block in find_by_sql'
  activerecord (4.0.9) lib/active_record/result.rb:21:in `block in each'
  activerecord (4.0.9) lib/active_record/result.rb:21:in `each'
  activerecord (4.0.9) lib/active_record/querying.rb:45:in `find_by_sql'
  activerecord (4.0.9) lib/active_record/relation.rb:587:in `exec_queries'
  activerecord (4.0.9) lib/active_record/relation.rb:471:in `load'
  activerecord (4.0.9) lib/active_record/relation.rb:220:in `to_a'
  activerecord (4.0.9) lib/active_record/relation/delegation.rb:12:in `each'

Thanks in advance.
Komal

crypto_keeper re-encrypts attributes on every save

Here is what I discovered when using crypt_keeper version off github (which uses "serialized" attributes approach instead of callbacks as it does in the released gem).

Saving and existing record which uses crypt_keeper will update all encrypted attributes with new re-encrypted values even if nothing changed on the model. Here is failing test (fails on rails 3.2):

require 'spec_helper'

describe User do
  let(:user) { FactoryGirl.create(:user) }
  subject { user }

  class RawUser < ActiveRecord::Base
    self.table_name = User.table_name
  end
  # This particular scenario was failing for crypto_keeper version on github.
  # To use 'serialized' attributes approach the newer crypto_keeper is using,
  # active_record needs to be of later versions then we are using right now.
  # Need to use crypt_keeper 0.13.1 (released)
  it 'should not re-encrypt and save unchanged encrypted attributes on save' do
    encrypted_email_before = RawUser.find(user.id).email
    subject.save  # this was re-encrypting and saving serialized attributes... :(
    expect(RawUser.find(user.id).email).to eq encrypted_email_before
  end
end

Apparently active record always updates serialized attributes which causes unnecessary performance hit.
https://github.com/rails/rails/blob/9aa1a3d85327fa0a3055b5b757a0be092ce582f7/activerecord/lib/active_record/attribute_methods/dirty.rb#L70

For now I am reverting to the releases 0.13.1 version.

ETA for 0.9?

I need to run the fix that allows empty strings that's in 0.9.0.pre - just wandering when the stable version is likely to drop?

Cheers!

OpenSSL::Cipher::CipherError: iv length too short

I like crypt_keeper. I dislike writing getters/setters for attributes to encrypt/decrypt them appropriately. crypt_keeper abstracts that away for me.

I'm getting this exception whenever I try to call any instance method on the model:

OpenSSL::Cipher::CipherError: iv length too short

This is the line where I invoke crypt_keeper:

crypt_keeper :secret, :encryptor => :aes, :key => ENV['SECRET']

Note that secret is attr_accessible.

I know I'm doing something wrong here, but I'm uncertain of what.

What is the minimum iv length? What is iv? What am I doing wrong here?

Here's the full stack trace:

 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/crypt_keeper-0.13.1/lib/crypt_keeper/provider/aes.rb:52:in `iv='
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/crypt_keeper-0.13.1/lib/crypt_keeper/provider/aes.rb:52:in `decrypt'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/crypt_keeper-0.13.1/lib/crypt_keeper/model.rb:111:in `decrypt'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/crypt_keeper-0.13.1/lib/crypt_keeper/model.rb:54:in `block in decrypt_callback'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/crypt_keeper-0.13.1/lib/crypt_keeper/model.rb:51:in `each'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/crypt_keeper-0.13.1/lib/crypt_keeper/model.rb:51:in `decrypt_callback'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/activesupport-3.2.13/lib/active_support/callbacks.rb:405:in `_run__2196557130005149586__find__2474344336412501888__callbacks'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/activesupport-3.2.13/lib/active_support/callbacks.rb:405:in `__run_callback'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/activesupport-3.2.13/lib/active_support/callbacks.rb:385:in `_run_find_callbacks'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/activesupport-3.2.13/lib/active_support/callbacks.rb:81:in `run_callbacks'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/activerecord-3.2.13/lib/active_record/base.rb:523:in `init_with'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/activerecord-3.2.13/lib/active_record/inheritance.rb:68:in `instantiate'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/activerecord-3.2.13/lib/active_record/querying.rb:38:in `block (2 levels) in find_by_sql'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/activerecord-3.2.13/lib/active_record/querying.rb:38:in `collect!'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/activerecord-3.2.13/lib/active_record/querying.rb:38:in `block in find_by_sql'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/activerecord-3.2.13/lib/active_record/explain.rb:41:in `logging_query_plan'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/activerecord-3.2.13/lib/active_record/querying.rb:37:in `find_by_sql'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/newrelic_rpm-3.6.5.130/lib/new_relic/agent/method_tracer.rb:518:in `block in find_by_sql_with_trace_ActiveRecord_self_name_find_by_sql'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/newrelic_rpm-3.6.5.130/lib/new_relic/agent/method_tracer.rb:268:in `trace_execution_scoped'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/newrelic_rpm-3.6.5.130/lib/new_relic/agent/method_tracer.rb:513:in `find_by_sql_with_trace_ActiveRecord_self_name_find_by_sql'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/activerecord-3.2.13/lib/active_record/relation.rb:171:in `exec_queries'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/activerecord-3.2.13/lib/active_record/relation.rb:160:in `block in to_a'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/activerecord-3.2.13/lib/active_record/explain.rb:34:in `logging_query_plan'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/activerecord-3.2.13/lib/active_record/relation.rb:159:in `to_a'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/activerecord-3.2.13/lib/active_record/relation/finder_methods.rb:380:in `find_first'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/activerecord-3.2.13/lib/active_record/relation/finder_methods.rb:122:in `first'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/activerecord-3.2.13/lib/active_record/relation/finder_methods.rb:338:in `find_one'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/activerecord-3.2.13/lib/active_record/relation/finder_methods.rb:314:in `find_with_ids'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/activerecord-3.2.13/lib/active_record/relation/finder_methods.rb:107:in `find'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/activerecord-3.2.13/lib/active_record/querying.rb:5:in `find'
 /Users/jarred/Code/G/lib/updator.rb:19:in `perform'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/sidekiq-2.13.0/lib/sidekiq/processor.rb:48:in `block (3 levels) in process'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/sidekiq-2.13.0/lib/sidekiq/middleware/chain.rb:109:in `call'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/sidekiq-2.13.0/lib/sidekiq/middleware/chain.rb:109:in `block in invoke'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/newrelic_rpm-3.6.5.130/lib/new_relic/agent/instrumentation/sidekiq.rb:25:in `block in call'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/newrelic_rpm-3.6.5.130/lib/new_relic/agent/instrumentation/controller_instrumentation.rb:318:in `perform_action_with_newrelic_trace'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/newrelic_rpm-3.6.5.130/lib/new_relic/agent/instrumentation/sidekiq.rb:21:in `call'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/sidekiq-2.13.0/lib/sidekiq/middleware/chain.rb:111:in `block in invoke'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/bugsnag-1.4.0/lib/bugsnag/sidekiq.rb:5:in `call'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/sidekiq-2.13.0/lib/sidekiq/middleware/chain.rb:111:in `block in invoke'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/sidekiq-2.13.0/lib/sidekiq/middleware/server/active_record.rb:6:in `call'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/sidekiq-2.13.0/lib/sidekiq/middleware/chain.rb:111:in `block in invoke'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/sidekiq-2.13.0/lib/sidekiq/middleware/server/retry_jobs.rb:49:in `call'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/sidekiq-2.13.0/lib/sidekiq/middleware/chain.rb:111:in `block in invoke'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/sidekiq-2.13.0/lib/sidekiq/middleware/server/logging.rb:11:in `block in call'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/sidekiq-2.13.0/lib/sidekiq/logging.rb:22:in `with_context'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/sidekiq-2.13.0/lib/sidekiq/middleware/server/logging.rb:7:in `call'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/sidekiq-2.13.0/lib/sidekiq/middleware/chain.rb:111:in `block in invoke'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/sidekiq-2.13.0/lib/sidekiq/middleware/chain.rb:114:in `call'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/sidekiq-2.13.0/lib/sidekiq/middleware/chain.rb:114:in `invoke'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/sidekiq-2.13.0/lib/sidekiq/processor.rb:47:in `block (2 levels) in process'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/sidekiq-2.13.0/lib/sidekiq/processor.rb:102:in `stats'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/sidekiq-2.13.0/lib/sidekiq/processor.rb:46:in `block in process'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/sidekiq-2.13.0/lib/sidekiq/processor.rb:83:in `do_defer'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/sidekiq-2.13.0/lib/sidekiq/processor.rb:37:in `process'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/celluloid-0.14.1/lib/celluloid/calls.rb:25:in `public_send'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/celluloid-0.14.1/lib/celluloid/calls.rb:25:in `dispatch'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/celluloid-0.14.1/lib/celluloid/calls.rb:125:in `dispatch'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/celluloid-0.14.1/lib/celluloid/actor.rb:326:in `block in handle_message'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/celluloid-0.14.1/lib/celluloid/tasks.rb:42:in `block in initialize'
 /Users/jarred/.rvm/gems/ruby-2.0.0-p0/gems/celluloid-0.14.1/lib/celluloid/tasks/task_fiber.rb:11:in `block in create'

I'm using crypt_keeper 0.13.1 and this is a Rails 3.2.13 app. ENV['SECRET'] is not nil.

0.9.0.pre - unable to use AES encryptor with AR object when field is nil or empty-string

I gave 0.9.0.pre a test run yesterday, and found a change in behavior from 0.8.0 in that it throws an exception when attempting to save an AR object where the crypt_keeper field is nil.

I'd previously noticed a problem with AR objects and empty strings.

Researching AES just a little bit, it seems AES cannot encrypt an empty string. I'm not sure how other projects/libraries handle it (mysql AES encryption for example works on an empty string).

I suggest we modify the AES encryptor to return nils and empty-strings as-is, like so:

      # Public: Decrypt a string
      #
      # Returns a string
      def decrypt(value)
        return nil if value.nil?
        return '' if value == ''
        ...
      end


      # Public: Encrypt a string
      #
      # Returns a string
      def encrypt(value)
        return nil if value.nil?
        return '' if value == ''
        ...
      end

I'm happy to submit a pull request for this if you agree this should happen.

Question regarding decrypting

Hey there. Let's say I'm using crypt_keeper to encrypt a text attribute on 'Model':

Example:

crypt_keeper :text, encryptor: :postgres_pgp, key: key

Works great. The encrypt and decrypt work as expected when getting records. However, my question is... when doing a sql call—the actual call is more complex with joins, etc—but for example's sake:

Model.where("text ILIKE ?", "%#{term}%")

text is not being decrypted, and hence there is no match. Is there a means by which to decrypt text so that i can make a call like that?

Thanks!

validates_uniqueness_of :encrypted_attribute Fails

Perhaps this is expected behavior and I'm missing something. Having issues with certain validations failing once the crypt_keeper method is applied to the attribute. For example I have a model which defines encryption for the title attribute:

crypt_keeper :title, encryptor: :aes_new, key: 'super_good_password', salt: 'salt'

Once I add the title attribute to crypt_keeper the uniqueness validation will fail. Below is the validation:

validates_uniqueness_of :title, scope: :assessment_component

Rspec test syntax:

it { should validate_uniqueness_of(:title).scoped_to(:assessment_component_id) }

Test output when actually run with rspec:

  1) AssessmentFinding should require case sensitive unique value for title scoped to assessment_component_id
     Failure/Error: it { should validate_uniqueness_of(:title).scoped_to(:assessment_component_id) }
     
       Expected errors to include "has already been taken" when title is set to "a",
       got no errors
     # ./spec/models/assessment_finding_spec.rb:33:in `block (2 levels) in <top (required)>'

Any insight of how I can properly test the uniqueness of this attribute and still provide encryption?

Type error when running the AES conversion utilty

I get this when running crypt_keeper to upgrade to aes_new. The columns in the table I'm updating have no nil values in them. I haven't looked for where the nil is coming from though.

/Users/Cedric/.rvm/gems/ruby-2.1.1@spaceman/gems/crypt_keeper-0.17.0/lib/crypt_keeper/provider/aes.rb:53:in `iv=': no implicit conversion of nil into String (TypeError)
from /Users/Cedric/.rvm/gems/ruby-2.1.1@spaceman/gems/crypt_keeper-0.17.0/lib/crypt_keeper/provider/aes.rb:53:in `decrypt'
from /Users/Cedric/.rvm/gems/ruby-2.1.1@spaceman/gems/crypt_keeper-0.17.0/bin/crypt_keeper:82:in `block (3 levels) in reencrypt_all'

Performance....

So I couldn't use your upgrade scripts because of whatever the reason was so needed to write my own upgrade scripts. Problem is it is taking hours for a mere 10 000 attribute values. How can I speed it up?

Migration tool for upgrading from 0.13 to 0.16

Note: This update is a breaking change which will require re-encrypting all data for anyone using the AES and MySQL AES providers.

  • MySQL AES and Ruby AES Passphrases are now derived using PBKDF2 hashing for enhance security. Because of this change, the above encryptors now requires a salt param in addition to the key. The salt it used when hashing the passphrase to ensure a unique key is used when encrypting data. The Armor gem is used to accomplish this.
  • Log subscribers are now more aggressive to ensure searches do not leak keys or plaintext during a search.
  • The AES provider internals were replaced with the AES gem.

Models can be migrated by temporarly using the migrate encryptors and calling save on every record. Example: :migrate_aes or :migrate_mysql_aes. This works by attempting to read the data using the old encryption method and falling back to the new method. Encryption always uses the new method

@fabiokr @itspriddle what are your thoughts on the below? It's pretty rough but seems to work in my testing.

require 'digest/sha2'
require 'openssl'
require 'base64'

module CryptKeeper
  module Provider
    class OldMysqlAes < CryptKeeper::Provider::MysqlAes
      def initialize(options = {})
        @key = options.fetch(:key)
      end
    end

    class MigrateMysqlAes
      def initialize(options = {})
        @new_enc = CryptKeeper::Provider::MysqlAes.new(options)
        @old_enc = OldMysqlAes.new(options)
      end

      def decrypt(value)
        plain_text = @old_enc.decrypt(value)

        if plain_text.blank?
          @new_enc.decrypt(value)
        else
          plain_text
        end
      end

      def encrypt(value)
        @new_enc.encrypt(value)
      end
    end

    class OldAes
      SEPARATOR = ":crypt_keeper:"

      attr_accessor :key
      attr_accessor :aes

      def initialize(options = {})
        @aes         = ::OpenSSL::Cipher::Cipher.new("AES-256-CBC")
        @aes.padding = 1

        key = options.fetch(:key) do
          raise ArgumentError, "Missing :key"
        end

        @key = Digest::SHA256.digest(key)
      end

      def encrypt(value)
        aes.encrypt
        aes.key = key
        Base64::encode64("#{aes.random_iv}#{SEPARATOR}#{aes.update(value.to_s) + aes.final}")
      end

      def decrypt(value)
        iv, value = Base64::decode64(value.to_s).split(SEPARATOR)
        aes.decrypt
        aes.key = key
        aes.iv  = iv
        aes.update(value) + aes.final
      end

      def search(records, field, criteria)
        records.select { |record| record[field] == criteria }
      end
    end

    class MigrateAes
      def initialize(options = {})
        @new_enc = CryptKeeper::Provider::Aes.new(options)
        @old_enc = OldAes.new(options)
      end

      def decrypt(value)
        plain_text = @old_enc.decrypt(value)

        if plain_text.blank?
          @new_enc.decrypt(value)
        else
          plain_text
        end
      end

      def encrypt(value)
        @new_enc.encrypt(value)
      end
    end
  end
end

Unable to have more than one crypt_keeper declaration in model...

I am attempting to call crypt_keeper more than once in my model:

class Person < ActiveRecord::Base

  crypt_keeper :field1, :field2, encryptor: :postgres_pgp_pub_key, public_key: KEY_DATA

  crypt_keeper :field3, :field4, encryptor: :postgres_pgp_pub_key, public_key: KEY_DATA, private_key: OTHER_KEY_DATA

end

The first crypt_keeper call gets wiped-out by the second crypt_keeper call.

Desired effect: per-field encryption/decryption according to crypt_keeper settings for that field.

Rails 4.2 support

It seems like Crypt Keeper depends on activesupport (< 4.2, >= 3.1) which precludes Rails 4.2. Could this be changed without breaking anything?

Unable to migrate an STI table with 0.18.2

$ $(which crypt_keeper) --old-key 'KEY' --new-key 'NEW_KEY' --salt 'SALT' --table-name 'users' --columns 'ssn' --old-encryptor aes
`rescue in find_sti_class': The single-table inheritance mechanism failed to locate the subclass: 'Admin'. This error is raised because the column 'type' is reserved for storing the class in case of inheritance. Please rename this column if you didn't intend it to be used for storing the inheritance class or overwrite MigrateData.inheritance_column to use another column for that information. (ActiveRecord::SubclassNotFound)

Overriding encrypt_callback/decrypt_callback

Hey there. I'm storing some serialized JSON in my encrypted column. To accomplish this within crypt_keeper, I overrode your encrypt/decrypt callbacks to load/dump the JSON as appropriate, but perhaps there's a better way? I could create a custom encryptor, but that seemed like overkill to me.

e.g.

  def encrypt_callback
    self.selections = self.class.encrypt(JSON.dump(read_attribute(:selections)))
  end

  def decrypt_callback
    self.selections = JSON.load(self.class.decrypt(read_attribute(:selections)))
  end

(I've lost the ability to encrypt multiple columns, but that doesn't apply to this situation anyhow)

Also, just wanted so say thanks for making crypt_keeper. Works out of the box without issue and is just much nicer than other solutions. ✨

How to do Postgres PGP Public Key Decryption on the App Server

I am trying to use the PostgreSQL PGP Public Key encryptor. However, mention somewhere in the docs that:

The private key is optional. If the private key is not present the ciphertext value is returned instead of the plaintext

and...

Encryption is possible with only a public key. Any server that needs access to the plaintext will need the private key.

Do you have any idea how I would do decryption (example code etc.) on the app server so I can keep the private keys completely off my database server?

Thanks for the awesome library!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.