Giter Site home page Giter Site logo

attr_encrypted's People

Contributors

ankane avatar arthurnn avatar austintaylor avatar bfreese avatar bitsapien avatar byroot avatar cheynewallace avatar cyrusstoller avatar dillonwelch avatar douwem avatar eugeneius avatar f3ndot avatar grosser avatar igor-drozdov avatar jish avatar jmazzi avatar joshbranham avatar miltzi avatar mlarraz avatar mvastola avatar mwean avatar nagachika avatar pmarreck avatar rcook avatar saghaulor avatar sbfaulkner avatar shuber avatar tamird avatar vimalvnair avatar willnet 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  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

attr_encrypted's Issues

In Rails 3.2.8+ if you have attr_encrypted before a serialize beware

I have a rails 3.1.8 app with a model that uses both serialize and attr_encrypted. These are used on separate attributes btw. I updated it to rails 3.2.8 and started getting an error. The serialized attribute was no longer being deserialized.

In order to fix this issue I had to move the serialize line above the attr_encrypted line.

Not encrypting the password..

class MyModel < ActiveRecord::Base
attr_encrypted :password, :key => 'a secret key'
end

current_user.MyModel(:user_id => current_user.id,
:site => params[:site],
:username => param[:username],
:password => params[:password]
)
current_user.save!

Pushes NULL value into Mysql db.

Rails version 2.3.4
Ruby version 1.8.7

Am I missing something??

Thanks

OpenSSL::Cipher::CipherError: wrong final block length (Again)

Trying to get attr_encrypted working, but none of the other existing "wrong block length" solutions seem to work for me. Just trying to figure out where things are going wrong, but am stumped.

In other project that uses Encryptor directly I had to use "m0" to encode and "m" to decode to get it to work in ruby 1.9. But not even that seems to work here.

Setup:

  • Ruby 1.9.2p320
  • Rails 3.2
  • attr_encrypted 1.2.1
class User < ActiveRecord::Base
  authenticates_with_sorcery!

  attr_encrypted :first_name, :last_name, :key => 'Pvk1Uv447S2vI8Ex71qqFCHL1vmV4EXg', :default_encoding => 'm0'

  attr_accessible :email, :first_name, :last_name, :password, :password_confirmation
end
1.9.2p320 > u = User.new :email => '[email protected]', :password => 'password', :password_confirmation => 'password'
u.save
1.9.2p320 > u.first_name = "test"
1.9.2p320 > u.save
1.9.2p320 :006 > u.save
   (0.6ms)  BEGIN
  User Exists (1.4ms)  SELECT 1 AS one FROM "users" WHERE ("users"."email" = '[email protected]' AND "users"."id" != 2 AND "users"."portal_id" = 1) LIMIT 1
   (0.7ms)  UPDATE "users" SET "encrypted_first_name" = '$2a$10$VkCljwchbn1UEINCASUmlOMthSZ2/q3mULDFF1Ow90Wr4ZUqaxMAO', "updated_at" = '2012-11-16 21:37:13.147546' WHERE "users"."id" = 2
   (0.7ms)  COMMIT
 => true 
1.9.2p320 > User.first.first_name
  User Load (0.7ms)  SELECT "users".* FROM "users" LIMIT 1
OpenSSL::Cipher::CipherError: wrong final block length
    from /Users/jkamenik/.rvm/gems/ruby-1.9.2-p320@waterfallportal/gems/encryptor-1.1.3/lib/encryptor.rb:62:in `final'
    from /Users/jkamenik/.rvm/gems/ruby-1.9.2-p320@waterfallportal/gems/encryptor-1.1.3/lib/encryptor.rb:62:in `crypt'
    from /Users/jkamenik/.rvm/gems/ruby-1.9.2-p320@waterfallportal/gems/encryptor-1.1.3/lib/encryptor.rb:44:in `decrypt'
    from /Users/jkamenik/.rvm/gems/ruby-1.9.2-p320@waterfallportal/gems/attr_encrypted-1.2.1/lib/attr_encrypted.rb:179:in `decrypt'
    from /Users/jkamenik/.rvm/gems/ruby-1.9.2-p320@waterfallportal/gems/attr_encrypted-1.2.1/lib/attr_encrypted.rb:262:in `decrypt'
    from /Users/jkamenik/.rvm/gems/ruby-1.9.2-p320@waterfallportal/gems/attr_encrypted-1.2.1/lib/attr_encrypted.rb:126:in `block (2 levels) in attr_encrypted'
    from (irb):7
    from /Users/jkamenik/.rvm/gems/ruby-1.9.2-p320@waterfallportal/gems/railties-3.2.8/lib/rails/commands/console.rb:47:in `start'
    from /Users/jkamenik/.rvm/gems/ruby-1.9.2-p320@waterfallportal/gems/railties-3.2.8/lib/rails/commands/console.rb:8:in `start'
    from /Users/jkamenik/.rvm/gems/ruby-1.9.2-p320@waterfallportal/gems/railties-3.2.8/lib/rails/commands.rb:41:in `<top (required)>'
    from script/rails:6:in `require'
    from script/rails:6:in `<main>'

Pass key from private or protected method

Hi, as of Ruby 2.0 we can no longer pass a protected method to generate our key

:key => :protect_method_to_generate_key

protected

def protect_method_to_generate_key
    # some clever method to generate and return a key
end

This generates a TypeError (no implicit conversion of Symbol into String)

Can you suggest another way to pass in a protected or private method so that the key can be generated on the fly without it being accessible from outside the class?

Dynamic find_by and a non String key

Hi,

I would like to implement a model of the structure:

class IngredientItem < ActiveRecord::Base
attr_encrypted :ingredient_id, :key => :attr_encryption_key, :marshal => true
def attr_encryption_key
return "password"
end
end

The problem is that with this setup I can not use dynamic find_by's, e.g.:
IngredientItem.find_by_ingredient_id(id)
fails saying:

/home/funsi/.rvm/gems/ruby-1.9.2-p136/gems/encryptor-1.1.3/lib/encryptor.rb:58:in `pkcs5_keyivgen'
/home/funsi/.rvm/gems/ruby-1.9.2-p136/gems/encryptor-1.1.3/lib/encryptor.rb:58:in `crypt'
/home/funsi/.rvm/gems/ruby-1.9.2-p136/gems/encryptor-1.1.3/lib/encryptor.rb:31:in `encrypt'
/home/funsi/.rvm/gems/ruby-1.9.2-p136/gems/attr_encrypted-1.2.0/lib/attr_encrypted.rb:193:in `encrypt'
/home/funsi/.rvm/gems/ruby-1.9.2-p136/gems/attr_encrypted-1.2.0/lib/attr_encrypted.rb:227:in `method_missing'
/home/funsi/.rvm/gems/ruby-1.9.2-p136/gems/activerecord-3.0.3/lib/active_record/base.rb:1008:in `method_missing'
/home/funsi/.rvm/gems/ruby-1.9.2-p136/gems/attr_encrypted-1.2.0/lib/attr_encrypted/adapters/active_record.rb:50:in `method_missing_with_attr_encrypted'
/home/funsi/.rvm/gems/ruby-1.9.2-p136/gems/attr_encrypted-1.2.0/lib/attr_encrypted/adapters/active_record.rb:44:in `block in method_missing_with_attr_encrypted'
/home/funsi/.rvm/gems/ruby-1.9.2-p136/gems/attr_encrypted-1.2.0/lib/attr_encrypted/adapters/active_record.rb:42:in `each'
/home/funsi/.rvm/gems/ruby-1.9.2-p136/gems/attr_encrypted-1.2.0/lib/attr_encrypted/adapters/active_record.rb:42:in `each_with_index'
/home/funsi/.rvm/gems/ruby-1.9.2-p136/gems/attr_encrypted-1.2.0/lib/attr_encrypted/adapters/active_record.rb:42:in `method_missing_with_attr_encrypted'

The README says that this should work if all records are encrypted with the same encryption key (per attribute), which is clearly the case in my simple example above.

Thanks,

Simon

Custom Encryptor Not Working

Just trying to get the basic example working:

class SillyEncryptor
    def self.silly_encrypt(options)
        (options[:value] + options[:secret_key]).reverse
    end

    def self.silly_decrypt(options)
        options[:value].reverse.gsub(/#{options[:secret_key]}$/, '')
    end
end

class User

  include DataMapper::Resource

  property :id, Serial

  property :encrypted_email, String
  attr_encrypted :email, :secret_key => 'secret', :encryptor => SillyEncryptor, :encrypt_method => :silly_encrypt, :decrypt_method => :silly_decrypt

end

I get:

$ rails console
Loading development environment (Rails 3.0.6)
>> u=User.create(:email => '[email protected]')
=> #<User @id=1 @encrypted_email="dGVyY2VzbW9jLmV0YXZpcnBAbmlyb2M=\n">
>>

attribute? not working

by default active record will give you last_name? if you have a column named last_name. this would be a good method to add for those using attr_encrypted

def last_name?
encrypted_last_name?
end

stack level too deep: devise token encryption

Hi there,

I'm desperatly trying to encrypt the devise user token.
The "authentication_token" is an attribute of the user class.
So what I tried to do is to add the line

attr_encrypted :authentication_token, :key => 'a secret key', :attribute => 'authentication_token'

to the user class and hope it would transparently encrypt it.

However I run into some problem, namely, when I login (note that i previously deleted any user token from the DB), I get the following error message:

Completed 500 Internal Server Error in 364ms

SystemStackError - stack level too deep:
  (gem) actionpack-3.2.13/lib/action_dispatch/middleware/reloader.rb:70:in `'

I assume that an endless recursion is occuring, but I don't understand where this originates from or how to fix it. Maybe someone can give me a hint?

Here also a link to my stackoverflow question:
http://stackoverflow.com/questions/15529846/encrypt-the-devise-token

Ruby 2 Issue: TypeError: no implicit conversion of Symbol into String

Hey guys

Im attempting an upgrade to Ruby 2.0.0-p247 how ever Iv discovered an issue with attr_encrypted.

When setting the value of an encrypted attribute I get the error:

TypeError: no implicit conversion of Symbol into String

Quick example:

attr_encrypted  :content, :key => :note_key, :unless => :locked
user = User.new
user.content = "Some encrypted content"

It's worth mentioning that this code has been working fine using Ruby 1.9.3 and Rails 3.2 for many months.

Environment:
Rails 3.2
Ruby 2.0.0-p247
Strong Parameters

Trace
TypeError: no implicit conversion of Symbol into String
from /usr/local/rvm/gems/ruby-2.0.0-p247@sampleapp/gems/encryptor-1.1.3/lib/encryptor.rb:58:in pkcs5_keyivgen' from /usr/local/rvm/gems/ruby-2.0.0-p247@sampleapp/gems/encryptor-1.1.3/lib/encryptor.rb:58:incrypt'
from /usr/local/rvm/gems/ruby-2.0.0-p247@sampleapp/gems/encryptor-1.1.3/lib/encryptor.rb:31:in encrypt' from /usr/local/rvm/gems/ruby-2.0.0-p247@sampleapp/gems/attr_encrypted-1.2.1/lib/attr_encrypted.rb:205:inencrypt'
from /usr/local/rvm/gems/ruby-2.0.0-p247@sampleapp/gems/attr_encrypted-1.2.1/lib/attr_encrypted.rb:281:in encrypt' from (irb):2 from /usr/local/rvm/gems/ruby-2.0.0-p247@sampleapp/gems/railties-4.0.0/lib/rails/commands/console.rb:90:instart'
from /usr/local/rvm/gems/ruby-2.0.0-p247@sampleapp/gems/railties-4.0.0/lib/rails/commands/console.rb:9:in start' from /usr/local/rvm/gems/ruby-2.0.0-p247@sampleapp/gems/railties-4.0.0/lib/rails/commands.rb:64:in<top (required)>'
from script/rails:6:in require' from script/rails:6:in

'

Using attr_encryption in a migration file, values not stored to db?

Hey there again,

I hope I don't make you mad with my posts here .. :-)
I tried to migrate my users with first- and lastname fields to encrypted ones.

So my migration looks like this:

class AddEncryptedFirstnameAndLastname < ActiveRecord::Migration

  def up
    add_column :users, :encrypted_firstname, :string
    add_column :users, :encrypted_lastname, :string
    encrypt_user_fullname
  end

  def encrypt_user_fullname
    User.all.each do |user|
       user.firstname = user.read_attribute('firstname')
       user.lastname = user.read_attribute('lastname')
       user.save!
    end
  end

end

In user.rb I have added encryption:

  attr_encrypted :firstname, :lastname, :key => 'the_magic'

However when i run the migration, it creates the database fields encrypted_firstname and encrypted_lastname, but it does not store them (nil everywhere). Reading the values out works, so user.read_attribute('firstname') gives indeed the firstname.

Is this problem known, or maybe is it just some mistake on my side?

Edit:
Also trying to reset the User.reset_column_information() after the add_column commands did not help. (thanks for hint to rvanlieshout)

Decrypt with database only

We are using using attr_encrypted for emails in our database with the following config:

{:dump_method=>"dump", :marshal=>false, 
:load_method=>"load", :default_encoding=>"m", 
:attribute=>:encrypted_email, 
:key=>"<key>", 
:encryptor=>Encryptor, :unless=>false, :if=>true, :suffix=>"", 
:prefix=>"encrypted_", 
:encrypt_method=>"encrypt", :encode=>"m", 
:decrypt_method=>"decrypt", :marshaler=>Marshal}

Now we have a part of the team that need to work with database directly without ruby.
So they can not use attr_encrypted.

Is it possible to decrypt an attribute at database level, so that any client can recognize it?
We are using mysql.

Passing a hash to Model.create / Model.new doesn't encrypt the attributes

Passing a hash to Mode.new doesn't encrypt values:

m = Model.new(some_attribute: "some_value")
m.encrypted_some_attribute
>> "some_value"

Whereas using the setter method everything works fine:

m = Model.new
m.some_attribute = "some_value"
m.encrypted_some_attribute
>> "N80ZHASLND..."

I believe that the attributes should be encrypted in both situations. Do you agree?

Encrypted password doesn't save in MongoDB

Perhaps I'm setting up my class incorrectly, but I can't get my encrypted data to save to MongoDB. I'm using attr_encrypted (1.2.1) and mongoid (3.0.14).

My class looks like

class Participant
  include Mongoid::Document
  field :first_name, type: String
  field :last_name, type: String
  field :email, type: String
  attr_encrypted :password, :key => 'mykey', :encode => true
  field :password, type: String
  field :encrypted_password, type: String

  attr_accessible :first_name, :last_name, :email, :password

  auto_increment :user_id

  validates_presence_of :encrypted_password
  validates_length_of :password, minimum: 5
  validates :last_name, :presence => true, :if => "first_name.nil?"
  validates_uniqueness_of :email
  validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :allow_nil => true
end

My failing test is

 describe 'saving' do
    let!(:participant) { FactoryGirl.build(:participant)}
    it 'should save the encrypted password in the database' do
      participant.password = 'averyuniquepassword'
      participant.save
      puts participant.password
      puts participant.encrypted_password
      retrieved_participant = Participant.where(encrypted_password: participant.encrypted_password).first
      retrieved_participant.should_not be_nil
    end
end

and I can retrieve the values of encrypted_password and password from the instance in memory, but I can see they're not saved in MongoDB.

Thanks for your help!

OpenSSL::Cipher::CipherError: wrong final block length

Gosh - I can't win - the column is encrypted in the DB (yay) but now I'm getting this when trying to decrypt:

ruby-1.9.2-p290 :009 > u.dob

OpenSSL::Cipher::CipherError: wrong final block length
from /Users/northband/.rvm/gems/ruby-1.9.2-p290/gems/encryptor-1.1.3/lib/encryptor.rb:62:in final' from /Users/northband/.rvm/gems/ruby-1.9.2-p290/gems/encryptor-1.1.3/lib/encryptor.rb:62:incrypt'
from /Users/northband/.rvm/gems/ruby-1.9.2-p290/gems/encryptor-1.1.3/lib/encryptor.rb:44:in decrypt' from /Users/northband/.rvm/gems/ruby-1.9.2-p290/gems/attr_encrypted-1.2.1/lib/attr_encrypted.rb:179:indecrypt'
from /Users/northband/.rvm/gems/ruby-1.9.2-p290/gems/attr_encrypted-1.2.1/lib/attr_encrypted.rb:262:in decrypt' from /Users/northband/.rvm/gems/ruby-1.9.2-p290/gems/attr_encrypted-1.2.1/lib/attr_encrypted.rb:126:inblock (2 levels) in attr_encrypted'
from (irb):9
from /Users/northband/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.2.8/lib/rails/commands/console.rb:47:in start' from /Users/northband/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.2.8/lib/rails/commands/console.rb:8:instart'
from /Users/northband/.rvm/gems/ruby-1.9.2-p290/gems/railties-3.2.8/lib/rails/commands.rb:41:in <top (required)>' from script/rails:6:inrequire'
from script/rails:6:in `

'

Any ideas?

TypeError: can't convert nil into String

Hi,

I've installed attr_encrypted gem, created new AR model Cc with attr_encrypted :pan method. I've also created db table, containing encrypted_pan field. When I try to assign value to pan, I'm encountering error below:

TypeError: can't convert nil into String
  from /bla/bla/bla/gems/encryptor-1.1.2/lib/encryptor.rb:57:in `pkcs5_keyivgen'
  from /bla/bla/bla/gems/encryptor-1.1.2/lib/encryptor.rb:57:in `crypt'
  from /bla/bla/bla/gems/encryptor-1.1.2/lib/encryptor.rb:31:in `encrypt'
  from /bla/bla/bla/gems/attr_encrypted-1.2.0/lib/attr_encrypted.rb:193:in `encrypt'
  from /bla/bla/bla/gems/attr_encrypted-1.2.0/lib/attr_encrypted.rb:269:in `encrypt'
  from /bla/bla/bla/gems/attr_encrypted-1.2.0/lib/attr_encrypted.rb:128:in `block (2 levels) in attr_encrypted'
  from (irb):3
  from /bla/bla/bla/gems/ruby-1.9.2-p180@app0/gems/railties-3.0.6/lib/rails/commands/console.rb:44:in `start'
  from /bla/bla/bla/gems/ruby-1.9.2-p180@app0/gems/railties-3.0.6/lib/rails/commands/console.rb:8:in `start'
  from /bla/bla/bla/gems/ruby-1.9.2-p180@app0/gems/railties-3.0.6/lib/rails/commands.rb:23:in `<top (required)>'
  from script/rails:6:in `require'
  from script/rails:6:in `<main>'

I use Ruby 1.9.2-p180 with Rails 3.0.6

Active Record adapter ordering issue with validators

I'm using attr_encrypted in combination with validates_timeliness (https://github.com/adzap/validates_timeliness) and it turns out that the order with which I declare my attributes with the appropriate methods is significant. In the case of the following example, the call to attr_encrypted breaks validation of the birthdate attribute:

class User < ActiveRecord::Base
    attr_encrypted :name, :key => 'SECRET_KEY'
    validates :birthdate, :timeliness => { :type => :date }
end

If, however, I declare them the other way round, everything works fine:

class User < ActiveRecord::Base
    validates :birthdate, :timeliness => { :type => :date }
    attr_encrypted :name, :key => 'SECRET_KEY'
end

The culprit is this line: https://github.com/shuber/attr_encrypted/blob/master/lib/attr_encrypted/adapters/active_record.rb#L17. Basically, the call to attr_encrypted in my class is invoking define_attribute_methods which can be empty at this point since the validators have not yet been encountered in the source file.

I'm not sure how to fix this, but I do, at least, have a reasonable workaround for the problem.

Could be related to #46.

Cannot really use with serialized objects in DB

I could not get attr_encrypted to just save the encrypted values without keeping the unencrypted values - when I tried to force this by setting :attribute or :prefix I got an exception raised within attr_encrypted options.merge! call (option seems to be set to nil). Now I roll my own implementation:

def attr_accessor_encrypted(*args)
      options = args.extract_options!
      options[:key] ||= DEFAULT_ATTR_ENCRYPTION_KEY
      
      args.each do |attribute|
        attr_accessor attribute
        
        define_method(:"#{attribute}") do
          value = instance_variable_get(:"@#{attribute}")
          value.present? ? value.decrypt(:key => Digest::SHA256.hexdigest(options[:key])) : value
        end

        define_method(:"#{attribute}=") do |value|
          value = value.present? ? value.encrypt(:key => Digest::SHA256.hexdigest(options[:key])) : value
          instance_variable_set :"@#{attribute}", value
        end
      end
    end

...but don't really get why this was not possible/simple to do with this gem.

Assigning integer to attr_encrypted attribute raises TypeError

When assigning an integer to an attr_encrypted attribute the following error is raised:

TypeError: can't convert Fixnum into String

This is because the integer value is passed straight through to Encryptor which passes it to the OpenSSL::Cipher::Cipher instance. The error only occurs when marshaling is not used; I assume the marshaling procedure always outputs a string acceptable to the cipher.

As a solution I suggest type casting the assigned value. This can be achieved by updating line 192 of attr_encrypted.rb from...

value = options[:marshaler].send(options[:dump_method], value) if options[:marshal]

...to...

value = options[:marshal] ? options[:marshaler].send(options[:dump_method], value) : value.to_s

...or...

if options[:marshal]
  value = options[:marshaler].send(options[:dump_method], value)
else
  value = value.to_s
end

...depending on whether you prefer clarity or brevity.

Alternately:

  • The type casting could be performed in the Encryptor.
  • The user could hack a marshaller into doing the type casting.
  • The user could wrap the assignment in a type casting block using alias_method_chain.

I think it's reasonable to assume the user intends all assigned values to be cast to string when marshaling is not used, which is why I propose doing it here in the AttrEncrypted module.

documentation request: provide simple example of how to generate a key (and where to store it)

For the beginner, it would be handy to provide an example of how to generate a strong key, e.g. SecureRandom.base64(96), and some guidance on where to store it. A simplistic approach for a Rails app:

# file: config/initializers/custom.rb
MY_ENCRYPTION_KEY = "1xiGKEkkXG0PXOVJL+S8Ux2QkcYlekqhWCFVX1FWgpUf5hv8j1Kgcl47stgBGrpso5rfWwfCdgXZv3PRpBGhKY8ekInvmhVagLipMB2ZQjJyUwag1HnuqVTPMrlOKRMf"

A slightly fancier version would store MY_ENCRYPTION_KEY as an environment variable so the key doesn't appear in the source code. This might be handy for people wishing to deploy on Heroku, for example. But I don't consider myself enough of a security expert to know if that's a sensible approach.

validates_numericality_of fails to run on attr_encrypted fields

The validates_numericality_of method in ActiveRecord specifically sends (activerecord/lib/active_record/validations.rb:1019, in rails-2.3.5):

record.send("#{attr_name}_before_type_cast")

While this method exists for any native-columns in ActiveRecord, it doesn't with the virtual non-encrypted fields.

Example:
class AchPayment < ActiveRecord::Base

attr_encrypted :account_number, :key => $encryption_key
attr_encrypted :routing_number, :key => $encryption_key

validates_length_of :account_number, :in => 2..15
validates_numericality_of :account_number, :only_integer => true
validates_length_of :routing_number, :is => 9
validates_numericality_of :account_number, :only_integer => true
end

Produces:

a = Factory.build(:ach_payment)
=> #<AchPayment id: nil, order_id: 321975001, name: "John Doe", encrypted_account_number: "nslmxtNRHAmYmWsXq7dnfA==\n", encrypted_routing_number: "NuL13ZfR8CpuNvdQpa3CPg==\n", account_type: "checking", payment_date: "2009-12-12 22:29:53", amount_mode: nil, amount: 500, created_at: nil, updated_at: nil>
a.save
NoMethodError: undefined method account_number_before_type_cast' for #<AchPayment:0x102e380c0> from /Users/user/Desktop/project/vendor/rails/activerecord/lib/active_record/attribute_methods.rb:255:inmethod_missing'
from /Users/user/Desktop/project/vendor/rails/activerecord/lib/active_record/validations.rb:1019:in send' from /Users/user/Desktop/project/vendor/rails/activerecord/lib/active_record/validations.rb:1019:invalidates_numericality_of'
from /Users/user/Desktop/project/vendor/rails/activerecord/lib/active_record/validations.rb:468:in validates_each' from /Users/user/Desktop/project/vendor/rails/activerecord/lib/active_record/validations.rb:465:ineach'
from /Users/user/Desktop/project/vendor/rails/activerecord/lib/active_record/validations.rb:465:in validates_each' from /Users/user/Desktop/project/vendor/rails/activesupport/lib/active_support/callbacks.rb:182:incall'
from /Users/user/Desktop/project/vendor/rails/activesupport/lib/active_support/callbacks.rb:182:in evaluate_method' from /Users/user/Desktop/project/vendor/rails/activesupport/lib/active_support/callbacks.rb:166:incall'
from /Users/user/Desktop/project/vendor/rails/activesupport/lib/active_support/callbacks.rb:90:in run' from /Users/user/Desktop/project/vendor/rails/activesupport/lib/active_support/callbacks.rb:90:ineach'
from /Users/user/Desktop/project/vendor/rails/activesupport/lib/active_support/callbacks.rb:90:in send' from /Users/user/Desktop/project/vendor/rails/activesupport/lib/active_support/callbacks.rb:90:inrun'
from /Users/user/Desktop/project/vendor/rails/activesupport/lib/active_support/callbacks.rb:276:in run_callbacks' from /Users/user/Desktop/project/vendor/rails/activerecord/lib/active_record/validations.rb:1098:invalid_without_callbacks?'
from /Users/user/Desktop/project/vendor/rails/activerecord/lib/active_record/callbacks.rb:315:in valid?' from /Users/user/Desktop/project/vendor/rails/activerecord/lib/active_record/validations.rb:1077:insave_without_dirty'
from /Users/user/Desktop/project/vendor/rails/activerecord/lib/active_record/dirty.rb:79:in save_without_transactions' from /Users/user/Desktop/project/vendor/rails/activerecord/lib/active_record/transactions.rb:229:insend'
from /Users/user/Desktop/project/vendor/rails/activerecord/lib/active_record/transactions.rb:229:in with_transaction_returning_status' from /Users/user/Desktop/project/vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb:136:intransaction'
from /Users/user/Desktop/project/vendor/rails/activerecord/lib/active_record/transactions.rb:182:in transaction' from /Users/user/Desktop/project/vendor/rails/activerecord/lib/active_record/transactions.rb:228:inwith_transaction_returning_status'
from /Users/user/Desktop/project/vendor/rails/activerecord/lib/active_record/transactions.rb:196:in save' from /Users/user/Desktop/project/vendor/rails/activerecord/lib/active_record/transactions.rb:208:inrollback_active_record_state!'
from /Users/user/Desktop/project/vendor/rails/activerecord/lib/active_record/transactions.rb:196:in `save'

would it make sense to add a _before_type_cast match to Huberry::AttrEncrypted::Adapters::ActiveRecord::method_missing_with_attr_encrypted ?

Reloading Active Record model instance does not refresh attr_encrypted's virtual attributes

Calling reload on an instance of an Active Record model class (i.e. a class derived from ActiveRecord::Base) is intended to restore the state of the object by requerying its contents from the database. Attributes declared with attr_encrypted do not exhibit this behaviour.

Here's the test scenario:

Create model source file User.rb and corresponding database migration:

class User < ActiveRecord::Base
  attr_encrypted :name, :marshal => true, :key => 'SECRET_KEY'
end

Run the migration to create the table and then perform the following sequence of steps in the Rails console:

$ u = User.create(:name => 'Winston Churchill')
$ u.name = 'Neville Chamberlain'
$ u.reload
$ u.name
> 'Neville Chamberlain'

In this example, we create an instance of the model with a given name value and then change it to another value without saving it to the database. Calling reload should restore the value of this attribute to the value in the database. In this example, the last line should yield 'Winston Churchill' instead of 'Neville Chamberlain'. This is definitely not peace for our time.

In fact, it turns out that reload does, in fact, requery the database and reload all of the class's real attributes (in this case encrypted_name etc.). However, attr_encrypted does not correctly invalidate attr_encrypted's virtual attributes such as name.

The fix should be fairly straightforward: we need to overload the ActiveRecord::Base.reload method to clear out the instance variables used to track the values of the virtual attributes exposed via attr_encrypted. Here's the current workaround I'm using for this issue:

class ActiveRecord::Base
  def reload(*args)
    self.class.encrypted_attributes.keys.each do |attribute_name|
      instance_variable_set("@#{attribute_name}", nil)
    end
    super
  end
end

This behaviour would just need to be mixed into ActiveRecord::Base in the usual way.

update_attributes

This is a question more than an answer. Do you want encrypted fields to work with update_attributes? I'm leaning toward no because these fields should have attr_protected. Curious on your feelings.

Currently not compatible with ActiveRecord 3.2.9 (Retracted)

I'm retracting this issue shown below.

This gem attr_encrypted does actually work with ActiveRecord 3.2.9 and possibly some previous versions where the issue was raised about the encrypted data not being stored in the database.

I misunderstood how this feature is to be used with the database. The following excerpt got me thinking that I might be wrong on how I was implementing this feature:

"Specifying the encrypted attribute name

By default, the encrypted attribute name is encrypted_#{attribute} (e.g. attr_encrypted :email would create an attribute named encrypted_email). So, if you’re storing the encrypted attribute in the database, you need to make sure the encrypted_#{attribute} field exists in your table. You have a couple of options if you want to name your attribute something else."

I began doing some tests and got the gem to work flawlessly, but it does kind of work backwards than the way I was thinking it should work.

Here's how to implement attr_encrypted as I understand it.

MySQL Table EncyptTest structure:

id:             Integer, Autoincrement, Primary Key
encrypted_data: Long Text or BLOB
created_at:     DateTime 

Model definition:

class EncryptTest < ActiveRecord::Base
  attr_encypted :data, :key => CONFIG[:encryption_key]
end

This code will work as expected. What I wasn't getting was that the "unencrypted" attribute name (:data in this case) is not the field name in the database table, it is actually just used for accessing/storing the data via the model. The actual field name in the database needs to be the "encrypted" name (encrypted_data in this case) created by the attr_encrypted feature. And since I'm using ActiveRecord, the :encode flag is set to true by default.

Hope this helps some other newbie that is trying to use this.

!!!!!!!!!!!!!!!!!!!!!!!!!!!I S S U E___B E L O W___R E T R A C T E D!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

I've been unable to get attr_encrypted to work with ActiveRecord 3.2.9 and it appears to be the same issue as reported before with the encrypted fields not actually getting written to the database.

However, I've a simple alternative approach that seems to work as seamlessly as this plugin.
You just need the encryptor 1.1.3 gem created by shuber.

Here is some sample code to show how to do the same thing using ActiveRecord 3.2.9 and encryptor 1.1.3 gem until the attr_encrypted gem is fixed.

Note: I put my encryption key into a configuration constant using the figaro gem.

class DatabaseModelName < ActiveRecord::Base
  attr_accessible :data

  before_save :encrypt_data

  after_save :decrypt_data
  after_find :decrypt_data

  protected

  def encrypt_data
    self.data = Encryptor.encrypt(:value => self.data, :key => CONFIG[:encryption_key]) unless self.data.blank?
  end

  def decrypt_data
    self.data = Encryptor.decrypt(:value => self.data, :key => CONFIG[:encryption_key) unless self.data.blank?
  end
end

Generating salt to use in encryption key

Is it possible to generate a salt attribute to be used for each record where attributes are being encrypted? I've attempted to create the salt by override the attribute setter - but the instance method to generate the key+salt used in the encryption key seems to be ignored.

Gemcutter time?

Hi Sean,

I'm wondering if you have plans to put attr_encrypted up on Gemcutter (or even RubyForge) in the future. Github dropping gem building has a lot of people standing on their heads! Thanks,

Steve

Configuration

New to GitHub. I found this gem very useful, but just to add a few comments:

  1. It is annoying to specify the :key all the time for all of the encryptable attributes. Would be extremely nice to have a simple configuration file, where you could specify the default key to be used everywhere, where :key is not specified. So it would be clean, flexible and very nice.

  2. If no key is specified in both places (config and :key), gem could use "YourApp::Application.config.secret_token" as an encryption key. It is pretty unique and secure!

  3. Not related to config, but, please, add an additional validation to the encrypted attribute. If it is equal to the original - throw an error. Consider example: attr_encrypted :snn, :prefix => "", :suffix => "". The IRB would throw one of the following errors: 1) Stack too deep. 2) Memory Error. Shouldn't be like that.

attr_encryptor alias breaks functionality.

I've verified that with ActiveRecord 3.2.9 that simply replacing the key word attr_encrypted with attr_encryptor prevents data from being stored to database. I'm not sure why.

  • Christopher Mullins

Broken in Rails 2.3.8 + Bundler

It works without bundler on a different machine, but my setup only works with bundler + RVM setups.

What's Happening?: Whenever I try to save an encrypted attribute via the Web UI, it doesn't save to the database. (All params are successfully sent to the controller)

I do "ap params" (ap is awesome_print) before and after the save (and everything I entered in the form is there), and store the result of the method update_attributes to a variable -- whose value is true... so rails thinks the save was successful... but when I look at the database all the attr_encrypted fields are still blank. No errors or anything, on the web side or the server side. Rails thinks everything is working as intended.

I'm using:
ruby 1.8.7
rails 2.3.8
bundler 1.0.21

This is how attr_encrypted is in the gemfile:
gem "attr_encrypted"

Ruby 1.9.3 and UTF-8

I recently upgraded my application that has been successfully using attr_encrypted since its inception to rails 3.2.2 + ruby 1.9.3. I am now experiencing a problem where an encrypted attribute that contains UTF-8 characters (i.e., a ruby 1.9 String encoded as UTF-8) upon encryption is not being encoded correctly upon decryption. When accessing the decrypted attribute, the String encoding is ASCII-8BIT.

This is probably best demonstrated by the below example:

# my class using attr_encrypted
class PaymentMethod < ActiveRecord::Base

  attr_encrypted :cc_number,           :prefix => 'crypted_', :key => Cloak.cloak
  attr_encrypted :cc_expiration_month, :prefix => 'crypted_', :key => Cloak.cloak
  attr_encrypted :cc_expiration_year,  :prefix => 'crypted_', :key => Cloak.cloak
  attr_encrypted :first_name,          :prefix => 'crypted_', :key => Cloak.cloak
  attr_encrypted :middle_name,         :prefix => 'crypted_', :key => Cloak.cloak
  attr_encrypted :last_name,           :prefix => 'crypted_', :key => Cloak.cloak

end

1.9.3-p125 :006 > p = PaymentMethod.last
  PaymentMethod Load (0.3ms)  SELECT "payment_methods".* FROM "payment_methods" ORDER BY "payment_methods"."id" DESC LIMIT 1
 => #<PaymentMethod id: 1, user_id: 1, active: true, crypted_cc_number: "UdOXr61FOI709h52Radtiw==\n", crypted_cc_expiration_month: "Y7uSwMsu5dlc74J5GALv8g==\n", crypted_cc_expiration_year: "alcZ1dlyzq7WToQYCwuA9g==\n", crypted_first_name: "9wS8fEwmZEcr0OEPNpY4Ag==\n", crypted_middle_name: "", crypted_last_name: "xrKHtQgjisVriueH6mMNgw==\n", company: nil, address1: "240 cant", address2: nil, city: "bury", state: "fl", zip: "33428", country: "US", phone: "3829382938", note: nil, created_at: "2012-03-21 15:16:29", updated_at: "2012-03-21 15:16:29", created_by: "ncr", updated_by: nil> 
1.9.3-p125 :007 > p.last_name.inspect => "\"Gagn\\xC3\\xA9\"" 
1.9.3-p125 :008 > p.last_name.encoding => #<Encoding:ASCII-8BIT> 
1.9.3-p125 :009 > p.last_name => "Gagn\xC3\xA9" 
1.9.3-p125 :010 > p.last_name.encode('UTF-8')
Encoding::UndefinedConversionError: "\xC3" from ASCII-8BIT to UTF-8
    from (irb):10:in `encode'
    from (irb):10
    from /Users/nick/.rvm/gems/ruby-1.9.3-p125/gems/railties-3.2.2/lib/rails/commands/console.rb:47:in `start'
    from /Users/nick/.rvm/gems/ruby-1.9.3-p125/gems/railties-3.2.2/lib/rails/commands/console.rb:8:in `start'
    from /Users/nick/.rvm/gems/ruby-1.9.3-p125/gems/railties-3.2.2/lib/rails/commands.rb:41:in `<top (required)>'
    from script/rails:6:in `require'
    from script/rails:6:in `<main>'
1.9.3-p125 :011 > p.last_name.unpack('U*') => [71, 97, 103, 110, 233] 
1.9.3-p125 :012 > p.last_name.unpack('U*').pack('U*') => "Gagné" # this is what it should be

As you can see, the decrypted String does indeed contain the correct UTF-8 data, but it is not escaped in a way that ruby 1.9's String understands. An explicit unpack followed by a pack corrects the encoding.

I am not sure how to fix this correctly and am hoping someone can shed some light. Is this an attr_encrypted problem, an shuber/encryptor problem, or something that I should be handling myself?

At the moment I have this monkey patch in place in an initializer, which seems to alleviate the problem for my deployments.

AttrEncrypted::InstanceMethods.module_eval do

  alias_method :original_decrypt, :decrypt
  def decrypt(attribute, encrypted_value)
    value = original_decrypt(attribute, encrypted_value)
    value.is_a?(String) ? value.unpack('U*').pack('U*') : value
  end

end

Nested models

When used in nested models using accepts_nested_attributes_for :model the key can not be dynamic.

e.g

class Parent < ActiveRecord::Base  
  has_many :children, :dependent => :destroy
  accepts_nested_attributes_for :children, :allow_destroy => true  
end

class Child < ActiveRecord::Base  
  belongs_to :parent
  attr_encrypted :some_column, :key => proc { |child| child.encryption_key }
end

This does not work, the key can only be a static value.

specifying multiple attributes on single line is broken

In a previous (early) version of attr_encrypted under rails 2.3.x, I had always done:

attr_encrypted :cc_number, :cc_month, :prefix => 'crypted_', :key => 'somekey'

Recently I upgraded my application to rails 3.0.9, with attr_encrypted 1.2.0 (my Gemfile contains "gem 'attr_encrypted'").

Suddenly the cc_month accessor method (i.e., not the first attribute) returns the value of cc_number (i.e., the first attribute).

I've fixed this by temporarily doing.

attr_encrypted :cc_number, :prefix => 'crypted_', :key => 'somekey'
attr_encrypted :cc_month, :prefix => 'crypted_', :key => 'somekey'

FWIW I actually have more than two encrypted attributes in the model, above is just an example.

I noticed this commit that attempts to fix the issue:
9194755

Although I haven't had time to dig further and debug myself, it does seem that this issue is not fixed, or I am doing something incredibly wrong.

Thanks.

Broken in Rails 3.0.8 Ruby 1.9.2

I don't know if this is related to issue #2 or not, but this is what I have found.

These 3 lines (really the last 2) are the culprits (lib/attr_encrypted.rb lines 121-123)

instance_methods_as_symbols = instance_methods.collect { |method| method.to_sym }      
attr_reader encrypted_attribute_name unless instance_methods_as_symbols.include?(encrypted_attribute_name)
attr_writer encrypted_attribute_name unless instance_methods_as_symbols.include?(:"#{encrypted_attribute_name}=")

From what I have been able to figure out, when attr_encrypted runs Rails has not generated the accessor methods for the database columns, so attr_encrypted writes its own using the above code. Then, when Rails comes around to generating the accessors, they already exist so it doesn't do anything.

The problem is, the getters and setters generated in the code above do not use the read_attribute and write_attribute methods (or self[:attribute_name] and self[:attribute_name]=). As a result, changes to "encrypted_attribute_name" don't end up in the changes hash and thus don't get saved to the DB. Also, because the getters don't call read_attribute, the persisted "encrypted_attribute_name" isn't pulled from the database. In other word, Ruby friendly accessors are generated, not Rails friendly ones.

Commenting out those lines does seem to fix some issues, but unfortunately, not all of them. I am too new at ruby/rails to really dig in much deeper and figure this out. It looks like I am going to be manually encrypting columns...

validates_uniqueness_of results in undefined method `text?' for nil:NilClass

as the title says, as soon as i add the validates_uniqueness_of validation for an encrypted model attribute, upon create/update ruby throws
undefined method `text?' for nil:NilClass
example:

class User < ActiveRecord::Base

    attr_encrypted :name, :key => 'a very secret key'
    validates_uniqueness_of :name

end

other validations work fine for me.

i'm on ruby 1.9.2-p180, rails 3.0.9, attr_encrypted 1.2.0

attr_encrypted seems to break serialized attributes

Just observed the following behavior:

  1. declared a attr_encrypted
  2. declared a serialize :attribute below it

After that, my serialized fields weren't being de-serialized. Accessing the attribute yielded the YAML string instead of the deserialized object (Array in my case).

Moving the attr_encrypted call to after the serialize call seems to have fixed that specific problem. Makes me worry about more hidden issues though.

This is on Rails 2.3.2 and Ruby 1.8.7.

I need to encrypt the data such that mysql can decrypt it.

Some clients following ISO 27001 are asking me to encrypt 'sensitive' data on DB, fields like email address, phone number e etc. attr_encrypted works really great, but I have several queries in pure SQL and Sphinx Search to deal with.

I tried these two ciphers with attr_encrypted, but AES_DECRYPT(encrypted_field,'key') returned NULL on MySQL console:

  • aes-128-cbc
  • aes-128-ecb

Am I missing something here, or the aes implementation from MySQL is different from openssl?

Best regards,
Fernando

Ruby 1.9: troubles with non-English chars

I use mongoid, but I think it does not matter.
User model:

class User
  include Mongoid::Document

  attr_encrypted :name, :key => 'password', :encode => true
  field :encrypted_name
end

I tried to play such code:

irb(main):005:0> User.create! :name => "тест"
=> #<User _id: 4d2a32fe5e6f990866000003, encrypted_name: "FDBMiOZQCXfSf9Mcyq2CFA==\n">
irb(main):006:0> User.last.name
=> "\xD1\x82\xD0\xB5\xD1\x81\xD1\x82"

And as you can see it can't decode string properly. But when I switched to ruby 1.8.7 it is ok:

irb(main):005:0> User.create! :name => "тест"
=> #<User _id: 4d2a32fe5e6f990866000003, encrypted_name: "FDBMiOZQCXfSf9Mcyq2CFA==\n">
irb(main):006:0> User.last.name
=> "тест"

P.S. Ruby 1.9.2. Patches for ruby 1.9 from spectator: https://github.com/spectator/attr_encrypted

Gem initialization with ActiveRecord spams SHOW FIELDS FROM query

I'm using attr_encrypted on a Rails 2.3 app. I've been noticing a SHOW FIELDS FROM query anytime I open the Rails console in development and tracked it down to the attr_encrypted call on the model (commented it out and log no longer does the query). I'm using Resque as a background job processor and it seems that anytime it's running, the SHOW FIELDS FROM query keeps getting spammed a lot. Is there a way to modify the gem initialization so that it doesn't load the ActiveRecord model? I'm using several other plugins/gems that extend AR and none seem to do this.

length validation and column size

Ran into an issue where our MySQL db column was smaller than our length validation limit, and data was truncated and therefore corrupted.

This naturally raises the question: how much longer can the encrypted value be than the original value?

Example:
zip code, should validate max length 9. How long must the db column be?

Is there a minimum encrypted length, and above that, the original and encrypted lengths are the same? Or is there a fixed length that's always added, or some percentage?

It'd be great if someone knows the answer so I don't have to spend time figuring it out. It should also be added to the readme, assuming it's something people should know about.

migrating from "sentry"

I'm hoping I can get some help with migrating from the sentry plugin to attr_encrypted. I have a bunch of rails deployments with encrypted data using sentry. I was hoping, since attr_encrypted is so flexible, that I could just drop-in-replace sentry with attr_encrypted without having to do a more elaborate un-encrypt and re-encrypt migration effort.

Heres sort of what I had for sentry in one of my models...

Sentry::SymmetricSentry.default_key = CLOAK
include ActiveRecord::Sentry  
symmetrically_encrypts :cc_number
symmetrically_encrypts :cc_expiration_month
symmetrically_encrypts :cc_expiration_year
symmetrically_encrypts :first_name
symmetrically_encrypts :middle_name
symmetrically_encrypts :last_name

equivalent config for attr_encrypted that I am trying...

attr_encrypted :cc_number, :cc_expiration_month, :cc_expiration_year,
:first_name, :middle_name, :last_name, :prefix => 'crypted_',
:key => CLOAK, :algorithm => 'des-ede3-cbc'

Using the previous I get "encryptor.rb:48:in `final': bad decrypt" exceptions when trying to load old records. I'm pretty sure that the default symmetric algorithm used by sentry is des-ede3-cbc. There must be something else different in the decryption process that I do not understand.

Should this work or am I out of luck? Everything works great for new records. Appreciate any help. Thanks.

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.