views:

52

answers:

2

A bit of a Ruby newbie here - should be an easy question: I want to use the encrypted_strings gem to create a password encrypted string: (from http://rdoc.info/projects/pluginaweek/encrypted_strings)

Question is: Everything works fine, but how come I don't need the password to decrypt the string? Say I want to store the string somewhere for a while,like the session. Is the password also stored with it? (which would seem very strange?). And no, I'm not planning on using 'secret-key' or any similar hack as a password.

I am planning on dynamically generating a class variable @@password using a uuid, which I don't store other than in memory, and can change from one running of the program to the next.

Symmetric:

>> password = 'shhhh'
 => "shhhh"
 >> crypted_password = password.encrypt(:symmetric, :password => 'secret_key')
 => "qSg8vOo6QfU=\n"
  >> crypted_password.class
 => String
 >> crypted_password == 'shhhh'
 => true
 >> password = crypted_password.decrypt
 => "shhhh"
+1  A: 

With a symmetric encryption scheme, you only need the same password for encryption and decryption. And from the looks of it, the password is stored in an instance variable on the encrypted string:

>> secret = '123'
=> "123"
>> crypted = secret.encrypt(:symmetric, :password => "password")
=> "R5RVA511Nzw=\n"
>> crypted.instance_variables
=> ["@cipher"]
>> crypted.instance_variable_get("@cipher")
=> #<EncryptedStrings::SymmetricCipher:0x101192768 @password="password", @algorithm="DES-EDE3-CBC">

So yes, if you store the crypted object as above, you'll be storing the password as well. The goal then is to store only the string content of crypted without its instance variables. I thought that crypted.to_s or String(crypted) would accomplish this, but neither do. As a workaround, you can string interpolate it, explicitly pass it to String#new, or explicitly remove the instance variable:

>> "#{crypted}".instance_variables
=> []
>> String.new(crypted).instance_variables
=> []
>> crypted.send :remove_instance_variable, :@cipher
=> #<EncryptedStrings::SymmetricCipher:0x101192768 @password="password", @algorithm="DES-EDE3-CBC">
>> crypted.instance_variables
=> []

Once you have only the string content, you can decrypt it with the password at a later point:

>> "R5RVA511Nzw=\n".decrypt(:symmetric, :password => "password")
=> "123"
Mark Rushakoff
Thanks for that. Ok. But - 'crypted' IS a string, so calling to_s on it just gives you back the same object. So - sub question - how would I get a plain string with the same contents as crypted?
Tom Andersen
@Tom: I should have tested that before writing it. I have updated the answer.
Mark Rushakoff
A: 

Ok - so here is an attempt to answer my own question:

  • Thanks again Mark for the console code. That led me to this:

You should use the String.new() method to create a plain string from the crypted one for external storage:

I think this is kinda strange and a little dangerous, namely that when a string is encrypted, the default behaviour is to include the password in the string.

Loading development environment (Rails 2.3.8)
>> secret = '123'
=> "123"
>> require 'encrypted_strings'
=> []
>> crypted = secret.encrypt(:symmetric, :password => "password")
=> "R5RVA511Nzw=\n"
>> crypted.instance_variables
=> ["@cipher"]
>> crypted.instance_variable_get("@cipher")
=> #<EncryptedStrings::SymmetricCipher:0x101c58b20 @algorithm="DES-EDE3-CBC", @password="password">
// note that this .to_s only passes back the crypted, since crypted _is_ a string.
>> someString = crypted.to_s 
=> "R5RVA511Nzw=\n"
>> someString.instance_variables
=> ["@cipher"]
>> crypted.instance_variable_get("@cipher")
=> #<EncryptedStrings::SymmetricCipher:0x101c58b20 @algorithm="DES-EDE3-CBC", @password="password">
>> plainString = String.new(crypted)
=> "R5RVA511Nzw=\n"
>> plainString.instance_variables
=> []
>> crypted.class
=> String
>> plainString.decrypt
ArgumentError: Cipher cannot be inferred: must specify it as an argument
    from /Library/Ruby/Gems/1.8/gems/encrypted_strings-0.3.3/lib/encrypted_strings/extensions/string.rb:98:in `decrypt'
    from (irb):14
>> plainString.decrypt(:symmetric, :password => "password")
=> "123"
Tom Andersen
Mark updated his answer as I was typing this. Thanks.
Tom Andersen
This storing of the encryption information in the string made me switch to the encryptor gem. It does not store the passwords, etc with the string.
Tom Andersen